winton-ubistrano 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/MIT-LICENSE +20 -0
- data/README.markdown +116 -0
- data/Rakefile +31 -0
- data/changelog.markdown +24 -0
- data/example/deploy.rb +23 -0
- data/lib/ubistrano/apache.rb +38 -0
- data/lib/ubistrano/deploy.rb +64 -0
- data/lib/ubistrano/ec2.rb +113 -0
- data/lib/ubistrano/gems.rb +29 -0
- data/lib/ubistrano/helpers.rb +271 -0
- data/lib/ubistrano/log.rb +20 -0
- data/lib/ubistrano/mysql.rb +94 -0
- data/lib/ubistrano/rails.rb +76 -0
- data/lib/ubistrano/sinatra.rb +25 -0
- data/lib/ubistrano/ssh.rb +56 -0
- data/lib/ubistrano/stage.rb +29 -0
- data/lib/ubistrano/ubuntu.rb +275 -0
- data/lib/ubistrano.rb +82 -0
- data/templates/apache/virtual_host.erb +32 -0
- data/templates/log/rotate.conf.erb +9 -0
- data/templates/rails/database.yml.erb +13 -0
- data/templates/sinatra/config.ru.erb +19 -0
- data/templates/ubuntu/apache.god.erb +31 -0
- data/templates/ubuntu/god.erb +36 -0
- data/templates/ubuntu/god.god.erb +1 -0
- data/templates/ubuntu/iptables.rules.erb +31 -0
- data/templates/ubuntu/mysql.god.erb +31 -0
- data/templates/ubuntu/sshd.god.erb +31 -0
- data/ubistrano.gemspec +49 -0
- metadata +90 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 AppTower
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
Ubistrano
|
2
|
+
=========
|
3
|
+
|
4
|
+
Provision and deploy to an Ubuntu/God/Apache/Passenger stack using Capistrano.
|
5
|
+
|
6
|
+
Goals
|
7
|
+
-----
|
8
|
+
|
9
|
+
* Provision a solid Ubuntu Hardy application server in one command (<code>cap ubuntu</code>)
|
10
|
+
* Deploy PHP, Rails, and Sinatra apps
|
11
|
+
* Be descriptive about what is going on and allow the user to opt out
|
12
|
+
* Simplify the deploy.rb file
|
13
|
+
|
14
|
+
The stack
|
15
|
+
---------
|
16
|
+
|
17
|
+
* Apache
|
18
|
+
* Git
|
19
|
+
* MySQL
|
20
|
+
* MySQLTuner
|
21
|
+
* Perl
|
22
|
+
* PHP
|
23
|
+
* Postfix (relay)
|
24
|
+
* Ruby
|
25
|
+
* RubyGems
|
26
|
+
* Passenger (mod\_rails)
|
27
|
+
* God
|
28
|
+
* Rails
|
29
|
+
* Sinatra
|
30
|
+
* Sphinx
|
31
|
+
|
32
|
+
|
33
|
+
Getting started
|
34
|
+
---------------
|
35
|
+
|
36
|
+
### Install gem
|
37
|
+
|
38
|
+
gem install winton-ubistrano
|
39
|
+
|
40
|
+
### Capify your project
|
41
|
+
|
42
|
+
capify .
|
43
|
+
|
44
|
+
### Edit config/deploy.rb
|
45
|
+
|
46
|
+
<pre>
|
47
|
+
set :ubistrano, {
|
48
|
+
:application => :my_app,
|
49
|
+
:platform => :rails, # :php, :rails, :sinatra
|
50
|
+
:repository => 'git@github.com:user/my-app.git',
|
51
|
+
|
52
|
+
:ec2 => {
|
53
|
+
:access_key => '',
|
54
|
+
:secret_key => ''
|
55
|
+
},
|
56
|
+
|
57
|
+
:production => {
|
58
|
+
:domains => [ 'myapp.com', 'www.myapp.com' ],
|
59
|
+
:ssl => [ 'myapp.com' ],
|
60
|
+
:host => '127.0.0.1'
|
61
|
+
},
|
62
|
+
|
63
|
+
:staging => {
|
64
|
+
:domains => [ 'staging.myapp.com' ],
|
65
|
+
:host => '127.0.0.1'
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
require 'ubistrano'
|
70
|
+
</pre>
|
71
|
+
|
72
|
+
Ubistrano uses the same Capistrano options you've come to love, but provides defaults and a few extra options as well.
|
73
|
+
|
74
|
+
Feel free to add standard options like :user to the stage groups.
|
75
|
+
|
76
|
+
Set up your Ubuntu Hardy server
|
77
|
+
-------------------------------
|
78
|
+
|
79
|
+
### From your app directory
|
80
|
+
|
81
|
+
<pre>cap ubuntu</pre>
|
82
|
+
|
83
|
+
### Example output
|
84
|
+
|
85
|
+
<pre>
|
86
|
+
=================================================================================
|
87
|
+
Let's set up an Ubuntu server! (Tested with 8.04 LTS Hardy)
|
88
|
+
|
89
|
+
With each task, Ubistrano will describe what it is doing, and wait for a yes/no.
|
90
|
+
|
91
|
+
=================================================================================
|
92
|
+
Have you already created the user defined in deploy.rb? (y/n)
|
93
|
+
</pre>
|
94
|
+
|
95
|
+
Deploy your app
|
96
|
+
---------------
|
97
|
+
|
98
|
+
All apps should have a <code>public</code> directory.
|
99
|
+
|
100
|
+
### First deploy
|
101
|
+
|
102
|
+
cap deploy:first
|
103
|
+
|
104
|
+
### Subsequent deploys
|
105
|
+
|
106
|
+
cap deploy
|
107
|
+
|
108
|
+
|
109
|
+
Deploy to staging
|
110
|
+
-----------------
|
111
|
+
|
112
|
+
Use any capistrano task, but replace `cap` with `cap staging`.
|
113
|
+
|
114
|
+
### Example
|
115
|
+
|
116
|
+
cap staging deploy:first
|
data/Rakefile
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'rake'
|
2
|
+
|
3
|
+
task :default => 'ubistrano.gemspec'
|
4
|
+
|
5
|
+
file 'ubistrano.gemspec' => FileList['{example,lib,templates}/**','Rakefile'] do |f|
|
6
|
+
# read spec file and split out manifest section
|
7
|
+
spec = File.read(f.name)
|
8
|
+
parts = spec.split(" # = MANIFEST =\n")
|
9
|
+
fail 'bad spec' if parts.length != 3
|
10
|
+
# determine file list from git ls-files
|
11
|
+
files = `git ls-files`.
|
12
|
+
split("\n").
|
13
|
+
sort.
|
14
|
+
reject{ |file| file =~ /^\./ }.
|
15
|
+
reject { |file| file =~ /^doc/ }.
|
16
|
+
map{ |file| " #{file}" }.
|
17
|
+
join("\n")
|
18
|
+
# piece file back together and write...
|
19
|
+
parts[1] = " s.files = %w[\n#{files}\n ]\n"
|
20
|
+
spec = parts.join(" # = MANIFEST =\n")
|
21
|
+
File.open(f.name, 'w') { |io| io.write(spec) }
|
22
|
+
puts "Updated #{f.name}"
|
23
|
+
end
|
24
|
+
|
25
|
+
# sudo rake install
|
26
|
+
task :install do
|
27
|
+
`gem uninstall ubistrano`
|
28
|
+
`gem build ubistrano.gemspec`
|
29
|
+
`gem install ubistrano*.gem`
|
30
|
+
`rm ubistrano*.gem`
|
31
|
+
end
|
data/changelog.markdown
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
Version 1.2.2
|
2
|
+
-------------
|
3
|
+
|
4
|
+
* Hardened cap ec2 -> cap ubuntu -> cap ubuntu:install
|
5
|
+
* There should be nothing to cause the user to stop and restart the tasks
|
6
|
+
|
7
|
+
Version 1.2.0
|
8
|
+
-------------
|
9
|
+
|
10
|
+
* New EC2 tasks
|
11
|
+
* EC2 setup and `cap ubuntu` provision tested
|
12
|
+
|
13
|
+
Version 1.1.0
|
14
|
+
-------------
|
15
|
+
|
16
|
+
* Sinatra apps deploying properly
|
17
|
+
* PHP and Rails apps should be deploying properly
|
18
|
+
* `cap ubuntu` flow hardened
|
19
|
+
|
20
|
+
Version 1.0.3
|
21
|
+
-------------
|
22
|
+
|
23
|
+
* `cap ubuntu` tested on Ubuntu 8.04 LTS Hardy
|
24
|
+
* App deploying not at all tested
|
data/example/deploy.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
set :ubistrano, {
|
2
|
+
:application => :my_app,
|
3
|
+
:platform => :rails, # :php, :rails, :sinatra
|
4
|
+
:repository => 'git@github.com:user/my-app.git',
|
5
|
+
|
6
|
+
:ec2 => {
|
7
|
+
:access_key => '',
|
8
|
+
:secret_key => ''
|
9
|
+
},
|
10
|
+
|
11
|
+
:production => {
|
12
|
+
:domains => [ 'myapp.com', 'www.myapp.com' ],
|
13
|
+
:ssl => [ 'myapp.com' ],
|
14
|
+
:host => '127.0.0.1'
|
15
|
+
},
|
16
|
+
|
17
|
+
:staging => {
|
18
|
+
:domains => [ 'staging.myapp.com' ],
|
19
|
+
:host => '127.0.0.1'
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
require 'ubistrano'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
namespace :apache do
|
4
|
+
desc "Reload apache settings"
|
5
|
+
task :reload, :roles => :web do
|
6
|
+
sudo_puts "/etc/init.d/apache2 reload"
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Restart apache"
|
10
|
+
task :restart, :roles => :web do
|
11
|
+
sudo_puts "/etc/init.d/apache2 restart"
|
12
|
+
end
|
13
|
+
|
14
|
+
namespace :virtual_host do
|
15
|
+
desc "Create a new virtual host"
|
16
|
+
task :create, :roles => :web do
|
17
|
+
upload_from_erb "/etc/apache2/sites-available/#{application}_#{stage}", binding, :name => 'virtual_host', :folder => 'apache'
|
18
|
+
end
|
19
|
+
|
20
|
+
desc "Enable a virtual host"
|
21
|
+
task :enable, :roles => :web do
|
22
|
+
sudo_puts "a2ensite #{application}_#{stage}"
|
23
|
+
end
|
24
|
+
|
25
|
+
desc "Destroy a virtual host"
|
26
|
+
task :destroy, :roles => :web do
|
27
|
+
apache.virtual_host.disable
|
28
|
+
sudo_each "rm /etc/apache2/sites-available/#{application}_#{stage}"
|
29
|
+
end
|
30
|
+
|
31
|
+
desc "Disable a virtual host"
|
32
|
+
task :disable, :roles => :web do
|
33
|
+
sudo_puts "a2dissite #{application}_#{stage}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
namespace :deploy do
|
4
|
+
desc "Restart application"
|
5
|
+
task :restart, :roles => :app, :except => { :no_release => true } do
|
6
|
+
run_each "touch #{current_path}/tmp/restart.txt"
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Start application"
|
10
|
+
task :start, :roles => :app do
|
11
|
+
apache.virtual_host.enable
|
12
|
+
end
|
13
|
+
|
14
|
+
desc "Stop application"
|
15
|
+
task :stop, :roles => :app do
|
16
|
+
apache.virtual_host.disable
|
17
|
+
end
|
18
|
+
|
19
|
+
desc "Deploy for the first time"
|
20
|
+
task :first, :roles => :app do
|
21
|
+
sudo_each [
|
22
|
+
"mkdir -p #{base_dir}",
|
23
|
+
"chown -R #{user}:#{user} #{base_dir}"
|
24
|
+
]
|
25
|
+
mysql.create.db
|
26
|
+
deploy.setup
|
27
|
+
case platform
|
28
|
+
when :php
|
29
|
+
deploy.update
|
30
|
+
when :rails
|
31
|
+
rails.config.default
|
32
|
+
deploy.update
|
33
|
+
deploy.migrate
|
34
|
+
when :sinatra
|
35
|
+
sinatra.config.default
|
36
|
+
deploy.update
|
37
|
+
sinatra.install
|
38
|
+
end
|
39
|
+
apache.virtual_host.create
|
40
|
+
deploy.start
|
41
|
+
apache.reload
|
42
|
+
end
|
43
|
+
|
44
|
+
desc "Stop servers and destroy all files"
|
45
|
+
task :destroy, :roles => :app do
|
46
|
+
sudo_each "rm -Rf #{deploy_to}"
|
47
|
+
mysql.destroy.db
|
48
|
+
apache.virtual_host.destroy
|
49
|
+
end
|
50
|
+
|
51
|
+
namespace :web do
|
52
|
+
task :disable do
|
53
|
+
pub = "#{deploy_to}/current/public"
|
54
|
+
sudo_each "mv #{pub}/maintenance.html #{pub}/index.html"
|
55
|
+
end
|
56
|
+
|
57
|
+
task :enable do
|
58
|
+
pub = "#{deploy_to}/current/public"
|
59
|
+
sudo_each "mv #{pub}/index.html #{pub}/maintenance.html"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
namespace :ec2 do
|
4
|
+
desc "Set up a new EC2 instance and provision"
|
5
|
+
task :default, :roles => :web do
|
6
|
+
ec2.key_pair.install
|
7
|
+
ec2.instance.create
|
8
|
+
ec2.security.group.setup if yes("Set up the default security group? You only need to do this once.")
|
9
|
+
exit unless yes("Add the instance's IP address to config/deploy.rb. Continue?")
|
10
|
+
puts space(msg(:ec2_finished))
|
11
|
+
end
|
12
|
+
|
13
|
+
namespace :instance do
|
14
|
+
desc "Create a fresh Hardy instance"
|
15
|
+
task :create do
|
16
|
+
options = {
|
17
|
+
:image_id => ask('Press enter for Ubuntu Hardy or enter an AMI image id: ', 'ami-1c5db975'),
|
18
|
+
:key_name => "#{application}"
|
19
|
+
}
|
20
|
+
instance = ec2_api.run_instances(options).instancesSet.item[0]
|
21
|
+
instance_id = instance.instanceId
|
22
|
+
pp instance
|
23
|
+
ip = ec2_api.allocate_address.publicIp
|
24
|
+
ec2_api.associate_address(:instance_id => instance_id, :public_ip => ip)
|
25
|
+
puts "\nYour instance id is: #{instance_id}"
|
26
|
+
puts "Your IP address is: #{ip}"
|
27
|
+
end
|
28
|
+
|
29
|
+
desc "Restart an instance"
|
30
|
+
task :restart do
|
31
|
+
ec2.instances
|
32
|
+
pp ec2_api.reboot_instances(:instance_id => ask("Restart which instance ids?"))
|
33
|
+
end
|
34
|
+
|
35
|
+
desc "Destroy an instance"
|
36
|
+
task :destroy do
|
37
|
+
ec2.instances
|
38
|
+
instance_id = ask("Terminate which instance ids?")
|
39
|
+
ec2_api.terminate_instances(:instance_id => instance_id)
|
40
|
+
ip = ec2_api.describe_addresses.addressesSet.item.select { |x| x.instanceId == instance_id }.first
|
41
|
+
ec2_api.release_address(:public_ip => ip.publicIp) if ip
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "List your EC2 instances"
|
46
|
+
task :instances do
|
47
|
+
pp ec2_api.describe_instances
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "List IPs for this EC2 account"
|
51
|
+
task :ips do
|
52
|
+
pp ec2_api.describe_addresses
|
53
|
+
end
|
54
|
+
|
55
|
+
namespace :key_pair do
|
56
|
+
desc "Install key pair for SSH"
|
57
|
+
task :install do
|
58
|
+
begin
|
59
|
+
out = ec2_api.create_keypair(:key_name => application.to_s)
|
60
|
+
key = out.keyMaterial
|
61
|
+
rescue EC2::InvalidKeyPairDuplicate
|
62
|
+
ec2.key_pair.remove
|
63
|
+
ec2.key_pair.install
|
64
|
+
end
|
65
|
+
File.open(File.expand_path("~/.ssh/id_rsa-#{application}"), 'w') { |f| f.write key }
|
66
|
+
end
|
67
|
+
|
68
|
+
desc "Install key pair for SSH"
|
69
|
+
task :remove do
|
70
|
+
ec2_api.delete_keypair(:key_name => application.to_s)
|
71
|
+
`rm ~/.ssh/id_rsa-#{application}`
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
namespace :security do
|
76
|
+
namespace :group do
|
77
|
+
desc "Open standard ports for default security group"
|
78
|
+
task :setup do
|
79
|
+
[ 22, 80, 443 ].each do |port|
|
80
|
+
ec2_api.authorize_security_group_ingress(
|
81
|
+
:group_name => 'default', :cidr_ip => '0.0.0.0/0', :from_port => port, :to_port => port, :ip_protocol => 'tcp'
|
82
|
+
)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
desc "Describe default security group"
|
87
|
+
task :describe do
|
88
|
+
pp ec2_api.describe_security_groups(:group_name => 'default')
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
namespace :api_tools do
|
94
|
+
desc "Install ec2 api tools locally"
|
95
|
+
task :install, :roles => :web do
|
96
|
+
`cd ~ && curl http://s3.amazonaws.com/ec2-downloads/ec2-api-tools.zip -O`
|
97
|
+
`cd ~ && unzip ec2-api-tools.zip`
|
98
|
+
`cd ~ && rm ec2-api-tools.zip`
|
99
|
+
`mv ~/ec2-api-tools-* ~/.ec2`
|
100
|
+
end
|
101
|
+
|
102
|
+
desc "Install ec2 api tools locally"
|
103
|
+
task :remove, :roles => :web do
|
104
|
+
`rm -Rf ~/.ec2`
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def ec2_api
|
109
|
+
@ec2_api ||= EC2::Base.new(:access_key_id => ec2_access_key, :secret_access_key => ec2_secret_key)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
Capistrano::Configuration.instance(:must_exist).load do
|
2
|
+
|
3
|
+
namespace :gems do
|
4
|
+
desc "List gems on remote server"
|
5
|
+
task :list, :roles => :app do
|
6
|
+
run_puts "gem list"
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "Update gems on remote server"
|
10
|
+
task :update, :roles => :app do
|
11
|
+
sudo_each [
|
12
|
+
"gem update --system",
|
13
|
+
"gem update"
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
17
|
+
desc "Install a remote gem"
|
18
|
+
task :install, :roles => :app do
|
19
|
+
gem_install ask('Enter the name of the gem to install:')
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Uninstall a remote gem"
|
23
|
+
task :uninstall, :roles => :app do
|
24
|
+
gem_name = ask 'Enter the name of the gem to remove:'
|
25
|
+
sudo "gem uninstall #{gem_name}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|