winton-ubistrano 1.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|