AppTower-ubistrano 1.0.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 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,110 @@
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 AppTower-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
+ :production => {
53
+ :domain => [ 'myapp.com', 'www.myapp.com' ],
54
+ :host => '127.0.0.1'
55
+ },
56
+
57
+ :staging => {
58
+ :domain => 'staging.myapp.com',
59
+ :host => '127.0.0.1'
60
+ }
61
+ }
62
+
63
+ require 'ubistrano'
64
+ </pre>
65
+
66
+ Ubistrano uses the same Capistrano options you've come to love, but provides defaults and a few extra options as well.
67
+
68
+ Feel free to add standard options like :user to the stage groups.
69
+
70
+ Set up your Ubuntu Hardy server
71
+ -------------------------------
72
+
73
+ ### From your app directory
74
+
75
+ <pre>cap ubuntu</pre>
76
+
77
+ ### Example output
78
+
79
+ <pre>
80
+ =================================================================================
81
+ Let's set up an Ubuntu server! (Tested with 8.04 LTS Hardy)
82
+
83
+ With each task, Ubistrano will describe what it is doing, and wait for a yes/no.
84
+
85
+ =================================================================================
86
+ Have you already created the user defined in deploy.rb? (y/n)
87
+ </pre>
88
+
89
+ Deploy your app
90
+ ---------------
91
+
92
+ All apps should have a <code>public</code> directory.
93
+
94
+ ### First deploy
95
+
96
+ cap deploy:first
97
+
98
+ ### Subsequent deploys
99
+
100
+ cap deploy
101
+
102
+
103
+ Deploy to staging
104
+ -----------------
105
+
106
+ Use any capistrano task, but replace `cap` with `cap staging`.
107
+
108
+ ### Example
109
+
110
+ cap staging deploy:first
data/Rakefile ADDED
@@ -0,0 +1,23 @@
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
data/changelog.rdoc ADDED
@@ -0,0 +1,25 @@
1
+
2
+ Version 2.0.0
3
+ * Tested on Ubuntu 8.04 LTS Hardy
4
+ * Deploys PHP, Rails, and Sinatra apps
5
+ * Redux version with new stack
6
+ * Apache
7
+ * Git
8
+ * God
9
+ * MySQL
10
+ * Passenger (mod_rails)
11
+ * Rails
12
+ * Ruby Enterprise Edition
13
+
14
+ Version 1.1.0
15
+ * Tested on Debian Etch
16
+ * Git
17
+ * Nginx
18
+ * Mongrel cluster
19
+ * Monit
20
+ * MySQL
21
+ * PHP (Nginx w/ spawn-fcgi)
22
+ * Rails
23
+ * Ruby
24
+ * RubyGems
25
+ * Sphinx
data/example/deploy.rb ADDED
@@ -0,0 +1,17 @@
1
+ set :ubistrano, {
2
+ :application => :my_app,
3
+ :platform => :rails, # :php, :rails, :sinatra
4
+ :repository => 'git@github.com:user/my-app.git',
5
+
6
+ :production => {
7
+ :domain => [ 'myapp.com', 'www.myapp.com' ],
8
+ :host => '127.0.0.1'
9
+ },
10
+
11
+ :staging => {
12
+ :domain => 'staging.myapp.com',
13
+ :host => '127.0.0.1'
14
+ }
15
+ }
16
+
17
+ require 'ubistrano'
data/lib/ubistrano.rb ADDED
@@ -0,0 +1,71 @@
1
+
2
+ # Require helpers and recipes
3
+ Dir["#{File.dirname(__FILE__)}/ubistrano/*.rb"].each { |f| require f }
4
+
5
+
6
+ Capistrano::Configuration.instance(:must_exist).load do
7
+
8
+ # Reference ROOT when namespaces clash
9
+ ROOT = self
10
+
11
+ # Default package versions
12
+ ubistrano[:versions] ||= {}
13
+ ubistrano[:versions].merge!(
14
+ :git => '1.6.0.4',
15
+ :mysecureshell => '1.1',
16
+ :rails => '2.2.2',
17
+ :ruby => '1.8.7-p72',
18
+ :rubygems => '1.3.1',
19
+ :sphinx => '0.9.8.1'
20
+ )
21
+
22
+ # Merge ubistrano hash with capistrano
23
+ ubistrano.each do |key, value|
24
+ value.respond_to?(:keys) ?
25
+ value.each { |k, v| set "#{key}_#{k}".intern, v } :
26
+ set(key, value)
27
+ end
28
+
29
+ # Set default capistrano values
30
+ set :db_user, fetch(:db_user, 'app')
31
+ set :db_pass, fetch(:db_pass, '')
32
+ set :platform, fetch(:platform, :rails)
33
+ set :port, fetch(:port, 22)
34
+ set :stage, fetch(:stage, :production)
35
+ set :use_sudo, fetch(:use_sudo, false)
36
+ set :user, fetch(:user, 'deploy')
37
+ set :sources, fetch(:sources, {
38
+ :git => "http://kernel.org/pub/software/scm/git/git-#{versions_git}.tar.gz",
39
+ :mysecureshell => "http://internap.dl.sourceforge.net/sourceforge/mysecureshell/MySecureShell-#{versions_mysecureshell}_source.tgz",
40
+ :mysqltuner => "http://mysqltuner.com/mysqltuner.pl",
41
+ :ruby => "ftp://ftp.ruby-lang.org/pub/ruby/#{versions_ruby.split('.')[0..1].join('.')}/ruby-#{versions_ruby}.tar.gz",
42
+ :rubygems => "http://rubyforge.org/frs/download.php/45905/rubygems-#{versions_rubygems}.tgz",
43
+ :sphinx => "http://www.sphinxsearch.com/downloads/sphinx-#{versions_sphinx}.tar.gz"
44
+ })
45
+
46
+ # Rails plugins
47
+ set :app_helpers, fetch(:app_helpers, false)
48
+ set :rails_widget, fetch(:rails_widget, false)
49
+ set :ultrasphinx, fetch(:ultrasphinx, false)
50
+ set :thinking_sphinx, fetch(:thinking_sphinx, false)
51
+ set :attachment_fu, fetch(:attachment_fu, false)
52
+ set :asset_packager, fetch(:asset_packager, false)
53
+ after('deploy:update_code', 'rails:config:app_helpers') if app_helpers
54
+ after('deploy:update_code', 'rails:config:asset_packager') if asset_packager
55
+ after('deploy:update_code', 'rails:config:attachment_fu') if attachment_fu
56
+ after('deploy:update_code', 'rails:config:rails_widget') if rails_widget
57
+ after('deploy:update_code', 'rails:config:ultrasphinx') if ultrasphinx
58
+ after('deploy:update_code', 'rails:config:thinking_sphinx') if thinking_sphinx
59
+
60
+ # Git by default
61
+ set :scm, :git
62
+ set :deploy_via, :remote_cache
63
+ set :repository_cache, 'git_cache'
64
+ ssh_options[:paranoid] = false
65
+
66
+ # Events
67
+ on :before, 'setup_stage', :except => [ :staging, :testing ] # Executed before every task
68
+ after('deploy:update_code', 'rails:config:to_app' ) if platform == :rails
69
+ after('deploy:update_code', 'sinatra:config:to_app') if platform == :sinatra
70
+
71
+ end
@@ -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 => 'ubuntu'
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,52 @@
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 [
7
+ "mkdir #{current_path}/tmp",
8
+ "touch #{current_path}/tmp/restart.txt"
9
+ ]
10
+ end
11
+
12
+ desc "Start application"
13
+ task :start, :roles => :app do
14
+ apache.virtual_host.enable
15
+ end
16
+
17
+ desc "Stop application"
18
+ task :stop, :roles => :app do
19
+ apache.virtual_host.disable
20
+ end
21
+
22
+ desc "Deploy for the first time"
23
+ task :first, :roles => :app do
24
+ sudo_each [
25
+ "mkdir -p #{base_dir}",
26
+ "chown -R #{user}:#{user} #{base_dir}"
27
+ ]
28
+ mysql.create.db
29
+ deploy.setup
30
+ deploy.update
31
+ apache.virtual_host.create
32
+ case platform
33
+ when :rails
34
+ rails.config.default
35
+ deploy.migrate
36
+ when :sinatra
37
+ sinatra.config.default
38
+ sinatra.install
39
+ end
40
+ deploy.start
41
+ apache.reload
42
+ end
43
+
44
+ desc "Stop servers and destroy all files"
45
+ task :destroy, :roles => :app do
46
+ deploy.stop
47
+ sudo "rm -Rf #{deploy_to}"
48
+ mysql.destroy.db
49
+ end
50
+ end
51
+
52
+ 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
@@ -0,0 +1,237 @@
1
+ require 'erb'
2
+
3
+ Capistrano::Configuration.instance(:must_exist).load do
4
+
5
+ # Install
6
+
7
+ def gem_install(name, options='')
8
+ sudo_puts "gem install #{name} #{options} --no-rdoc --no-ri -q"
9
+ end
10
+
11
+ def install_source(source)
12
+ path, source = unpack_source source
13
+ yield path
14
+ sudo "rm -Rf #{source}"
15
+ end
16
+
17
+ def make_install(path)
18
+ ";cd #{path} && ./configure && make && sudo make install"
19
+ end
20
+
21
+ def unpack_source(source)
22
+ url = sources[source]
23
+ name = File.basename url
24
+ src = "/home/#{user}/sources"
25
+ base = nil
26
+ [ 'tar.gz', 'tgz' ].each do |ext|
27
+ base = name[0..((ext.length + 2) * -1)] if name.include?(ext)
28
+ end
29
+ run_each [
30
+ "mkdir -p #{src}",
31
+ "cd #{src} && wget --quiet #{url}",
32
+ "tar -xzvf #{src}/#{name} -C #{src}"
33
+ ]
34
+ [ "#{src}/#{base}", src ]
35
+ end
36
+
37
+
38
+ # Files
39
+
40
+ def add_line(file, *lines)
41
+ lines.each do |line|
42
+ sudo_each "echo \"#{line}\" | sudo tee -a #{file}"
43
+ end
44
+ end
45
+
46
+ def change_line(file, from, to)
47
+ sudo_each "sed 's/#{from}/#{to}/' #{file}"
48
+ end
49
+
50
+ def remove_line(file, *lines)
51
+ lines.each do |line|
52
+ change_line file, line, ''
53
+ end
54
+ end
55
+
56
+ def get_ssh_keys
57
+ keys = Dir[File.expand_path('~/.ssh/*.pub')].collect do |f|
58
+ File.open(f).collect { |line| line.strip.empty? ? nil : line.strip }.compact
59
+ end
60
+ keys.flatten.join("\n").strip
61
+ end
62
+
63
+ def upload_from_erb(destination, bind=nil, options={})
64
+ # options[ :chown => owner of file (default: deploy user),
65
+ # :chmod => 0644 etc
66
+ # :folder => 'postfix' etc,
67
+ # :name => name of template if differs from destination ]
68
+ if destination.respond_to?(:uniq)
69
+ destination.each { |d| upload_from_erb d, bind, options }
70
+ else
71
+ template = File.basename destination
72
+ template = template[1..-1] if template[0..0] == '.'
73
+ folder = options[:folder] ? options[:folder] + '/' : ''
74
+ template = File.expand_path("../../templates/#{folder}#{options[:name]||template}.erb", File.dirname(__FILE__))
75
+ template = File.read template
76
+ sudo "touch #{destination}"
77
+ sudo "chown #{user} #{destination}"
78
+ put ERB.new(template).result(bind || binding), destination
79
+ sudo("chown #{options[:chown]} #{destination}") if options[:chown]
80
+ sudo("chmod #{options[:chmod]} #{destination}") if options[:chmod]
81
+ end
82
+ end
83
+
84
+
85
+ # MySQL
86
+
87
+ def mysql_run(sql)
88
+ if sql.respond_to?(:uniq)
89
+ sql.each { |s| mysql_run s }
90
+ else
91
+ run "echo \"#{sql}\" | #{mysql_call}"
92
+ end
93
+ end
94
+
95
+ def mysql_call
96
+ @mysql_root_password = @mysql_root_password || ask("Password for mysql root:")
97
+ "mysql -u root --password=#{@mysql_root_password}"
98
+ end
99
+
100
+
101
+ # Questions
102
+
103
+ def ask(question, default='')
104
+ question = "\n" + question.join("\n") if question.respond_to?(:uniq)
105
+ answer = Capistrano::CLI.ui.ask(space(question)).strip
106
+ answer.empty? ? default : answer
107
+ end
108
+
109
+ def yes(question)
110
+ question = "\n" + question.join("\n") if question.respond_to?(:uniq)
111
+ question += ' (y/n)'
112
+ ask(question).downcase.include? 'y'
113
+ end
114
+
115
+ def space(str)
116
+ "\n#{'=' * 90}\n#{str}"
117
+ end
118
+
119
+
120
+ # Runners
121
+
122
+ def run_each(*args, &block)
123
+ cmd = args[0]
124
+ sudo = args[1]
125
+ if cmd.respond_to?(:uniq)
126
+ cmd.each { |c| run_each c, sudo, &block }
127
+ elsif sudo
128
+ puts space("sudo #{cmd}")
129
+ sudo(cmd) { |ch, st, data| block.call(data) if block }
130
+ else
131
+ puts space(cmd)
132
+ run(cmd) { |ch, st, data| block.call(data) if block }
133
+ end
134
+ end
135
+
136
+ def sudo_each(cmds, &block)
137
+ run_each cmds, true, &block
138
+ end
139
+
140
+ def run_puts(cmds, &block)
141
+ run_each(cmds) { |data| puts data }
142
+ end
143
+
144
+ def sudo_puts(cmds, &block)
145
+ sudo_each(cmds) { |data| puts data }
146
+ end
147
+
148
+
149
+ # Messages
150
+
151
+ def msg(type)
152
+ case type
153
+ when :about_templates
154
+ "Let's set up an Ubuntu server! (Tested with 8.04 LTS Hardy)
155
+
156
+ With each task, Ubistrano will describe what it is doing, and wait for a yes/no."
157
+ when :aptitude_default
158
+ "Do you want me to run aptitude update, upgrade, and install build-essential?
159
+ If not, instructions for doing it manually will be displayed."
160
+ when :aptitude_instructions
161
+ "Please run these manually:
162
+ sudo aptitude update
163
+ sudo aptitude upgrade
164
+ sudo aptitude build-essential"
165
+ when :create_keys
166
+ "May I generate an rsa ssh key pair in your ~/.ssh folder?"
167
+ when :create_server_keys
168
+ "May I generate an rsa ssh key pair in the server's ~/.ssh folder?
169
+ The public key will be displayed."
170
+ when :god
171
+ "May I install God?"
172
+ when :god_apache
173
+ "Would you like God to monitor apache?
174
+ See #{File.expand_path '../../', File.dirname(__FILE__)}/templates/ubuntu/apache.god.erb"
175
+ when :god_mysql
176
+ "Would you like God to monitor mysql?
177
+ See #{File.expand_path '../../', File.dirname(__FILE__)}/templates/ubuntu/mysql.god.erb"
178
+ when :god_apache
179
+ "Would you like God to monitor sshd?
180
+ See #{File.expand_path '../../', File.dirname(__FILE__)}/templates/ubuntu/sshd.god.erb"
181
+ when :have_keys
182
+ "Do you have rsa key pairs installed on your system? (see ~/.ssh/id_rsa)"
183
+ when :iptables
184
+ "May I update your server's iptables, limiting access to SSH, HTTP, HTTPS, and ping only?
185
+ See #{File.expand_path '../../', File.dirname(__FILE__)}/templates/ubuntu/iptables.rules.erb"
186
+ when :logrotate
187
+ "May I add a logrotate entry for this application?
188
+ See #{File.expand_path '../../', File.dirname(__FILE__)}/templates/log/rotate.conf.erb"
189
+ when :mysqltuner
190
+ "Would you like to install MySQLTuner and receive instructions for running it?"
191
+ when :mysqltuner_instructions
192
+ "Please ssh to your server and run `sudo mysqltuner`.
193
+ Continue?"
194
+ when :passenger
195
+ "Please run `sudo passenger-install-apache2-module` manually.
196
+ The apache config file is found at /etc/apache2/apache2.conf.
197
+ Reload apache?"
198
+ when :secure_mysql
199
+ "It is highly recommended you run mysql_secure_installation manually.
200
+ See http://dev.mysql.com/doc/refman/5.1/en/mysql-secure-installation.html
201
+ Continue?"
202
+ when :ssh_keys_create
203
+ "Create rsa ssh key pairs locally or remotely? (default: remote)"
204
+ when :ssh_keys_upload
205
+ "Press enter to copy all public keys (~/.ssh/*.pub), or paste a key: "
206
+ when :sshd_config
207
+ "May I update your server's sshd_config with the following settings?
208
+ Port #{port}
209
+ PermitRootLogin no
210
+ X11Forwarding no
211
+ UsePAM no
212
+ UseDNS no
213
+ "
214
+ when :sudoers
215
+ "May I add sudo-without-password privileges for the deploy user?
216
+ I will have to edit /etc/sudoers."
217
+ when :ubuntu_restart
218
+ "Would you like to restart the server now?"
219
+ when :ubuntu_finished
220
+ "That's it! Glad you made it.
221
+
222
+ Use `cap deploy:first` to set up your PHP, Rails, or Sinatra app.
223
+ Use `cap deploy` for all subsequent deploys.
224
+
225
+ "
226
+ when :upload_keys
227
+ "May I copy all of your public keys in ~/.ssh to the server's authorized_keys?"
228
+ when :visudo
229
+ "Please run the following commands:
230
+ ssh root@#{host}:#{port}
231
+ adduser #{user}
232
+
233
+ "
234
+ end
235
+ end
236
+
237
+ end