ricodigo-capistrano-recipes 0.1.0

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.
@@ -0,0 +1,65 @@
1
+ rails_root = '<%= "#{deploy_to}/current" %>'
2
+ rails_env = '<%= environment %>'
3
+ pid_file = '<%= unicorn_pid %>'
4
+ socket_file= '<%= unicorn_socket %>'
5
+ log_file = '<%= deploy_to %>/current/log/unicorn.log'
6
+ username = '<%= unicorn_user %>'
7
+ group = '<%= unicorn_group %>'
8
+ old_pid = pid_file + '.oldbin'
9
+
10
+
11
+ working_directory rails_root
12
+
13
+ timeout <%= unicorn_workers_timeout %>
14
+
15
+ worker_processes <%= unicorn_workers %>
16
+
17
+ # Listen on a Unix data socket
18
+ listen socket_file, :backlog => 1024
19
+ pid pid_file
20
+
21
+ stderr_path log_file
22
+ stdout_path log_file
23
+
24
+ preload_app true
25
+
26
+ GC.copy_on_write_friendly = true if GC.respond_to?(:copy_on_write_friendly=)
27
+
28
+ before_fork do |server, worker|
29
+ if File.exists?(old_pid) && server.pid != old_pid
30
+ pid = File.read(old_pid).to_i
31
+ begin
32
+ Process.kill("QUIT", pid)
33
+ Process.kill(0, pid)
34
+ Process.wait
35
+ rescue Errno::ECHILD, Errno::ESRCH => e
36
+ $stderr.puts ">> Process #{pid} has stopped"
37
+ rescue Errno::ENOENT => e
38
+ $stderr.puts ">> Error killing previous instance. #{e.message}"
39
+ # someone else did our job for us
40
+ end
41
+ end
42
+ end
43
+
44
+
45
+ after_fork do |server, worker|
46
+ begin
47
+ uid, gid = Process.euid, Process.egid
48
+
49
+ target_uid = File.stat(Rails.root).uid
50
+ user = Etc.getpwuid(target_uid).name
51
+
52
+ target_gid = File.stat(Rails.root).gid
53
+ group = Etc.getgrgid(target_gid).name
54
+
55
+ worker.tmp.chown(target_uid, target_gid)
56
+ if uid != target_uid || gid != target_gid
57
+ Process.initgroups(user, target_gid)
58
+ Process::GID.change_privilege(target_gid)
59
+ Process::UID.change_privilege(target_uid)
60
+ end
61
+ rescue => e
62
+ STDERR.puts "cannot change privileges on #{Rails.env} environment"
63
+ STDERR.puts " #{e}"
64
+ end
65
+ end
data/lib/helpers.rb ADDED
@@ -0,0 +1,88 @@
1
+ # =========================================================================
2
+ # These are helper methods that will be available to your recipes.
3
+ # =========================================================================
4
+
5
+ # automatically sets the environment based on presence of
6
+ # :stage (multistage gem), :rails_env, or RAILS_ENV variable; otherwise defaults to 'production'
7
+ def environment
8
+ if exists?(:stage)
9
+ stage
10
+ elsif exists?(:rails_env)
11
+ rails_env
12
+ elsif(ENV['RAILS_ENV'])
13
+ ENV['RAILS_ENV']
14
+ else
15
+ "production"
16
+ end
17
+ end
18
+
19
+ def is_using_nginx
20
+ is_using('nginx',:web_server)
21
+ end
22
+
23
+ def is_using_passenger
24
+ is_using('passenger',:app_server)
25
+ end
26
+
27
+ def is_using_unicorn
28
+ is_using('unicorn',:app_server)
29
+ end
30
+
31
+ def is_app_monitored?
32
+ is_using('bluepill', :monitorer)
33
+ end
34
+
35
+ def is_using(something, with_some_var)
36
+ exists?(with_some_var.to_sym) && fetch(with_some_var.to_sym).to_s.downcase == something
37
+ end
38
+
39
+ # Path to where the generators live
40
+ def templates_path
41
+ expanded_path_for('../generators')
42
+ end
43
+
44
+ def docs_path
45
+ expanded_path_for('../doc')
46
+ end
47
+
48
+ def expanded_path_for(path)
49
+ e = File.join(File.dirname(__FILE__),path)
50
+ File.expand_path(e)
51
+ end
52
+
53
+ def parse_config(file)
54
+ require 'erb' #render not available in Capistrano 2
55
+ template=File.read(file) # read it
56
+ return ERB.new(template).result(binding) # parse it
57
+ end
58
+
59
+ # =========================================================================
60
+ # Prompts the user for a message to agree/decline
61
+ # =========================================================================
62
+ def ask(message, default=true)
63
+ Capistrano::CLI.ui.agree(message)
64
+ end
65
+
66
+ # Generates a configuration file parsing through ERB
67
+ # Fetches local file and uploads it to remote_file
68
+ # Make sure your user has the right permissions.
69
+ def generate_config(local_file,remote_file)
70
+ temp_file = '/tmp/' + File.basename(local_file)
71
+ buffer = parse_config(local_file)
72
+ File.open(temp_file, 'w+') { |f| f << buffer }
73
+ upload temp_file, remote_file, :via => :scp
74
+ `rm #{temp_file}`
75
+ end
76
+
77
+ # =========================================================================
78
+ # Executes a basic rake task.
79
+ # Example: run_rake log:clear
80
+ # =========================================================================
81
+ def run_rake(task)
82
+ run "cd #{current_path} && rake #{task} RAILS_ENV=#{environment}"
83
+ end
84
+
85
+
86
+ def rvmsudo(task)
87
+ run "cd #{current_path} && rvmsudo #{task}"
88
+ end
@@ -0,0 +1,68 @@
1
+ Capistrano::Configuration.instance.load do
2
+ # User settings
3
+ set :user, 'app' unless exists?(:user)
4
+ set :group,'app' unless exists?(:group)
5
+
6
+ # Server settings
7
+ set :app_server, :unicorn unless exists?(:app_server)
8
+ set :web_server, :nginx unless exists?(:web_server)
9
+ set :runner, user unless exists?(:runner)
10
+ set :application_port, 80 unless exists?(:application_port)
11
+
12
+ set :application_uses_ssl, true unless exists?(:application_uses_ssl)
13
+ set :application_port_ssl, 443 unless exists?(:application_port_ssl)
14
+
15
+ # Database settings
16
+ set :database, :mongodb unless exists?(:database)
17
+
18
+ # SCM settings
19
+ set :scm, :git
20
+ set :branch, 'master' unless exists?(:branch)
21
+ set :deploy_to, "/home/#{user}/rails/#{application}"
22
+ set :deploy_via, :checkout
23
+ set :keep_releases, 3
24
+ set :run_method, :run
25
+ set :git_enable_submodules, true
26
+ set :git_shallow_clone, 1
27
+ set :rails_env, 'production' unless exists?(:rails_env)
28
+
29
+ # Git settings for capistrano
30
+ default_run_options[:pty] = true
31
+ ssh_options[:forward_agent] = true
32
+
33
+ # RVM settings
34
+ set :using_rvm, true unless exists?(:using_rvm)
35
+
36
+ if using_rvm
37
+ $:.unshift(File.expand_path('./lib', ENV['rvm_path'])) # Add RVM's lib directory to the load path.
38
+ require "rvm/capistrano" # Load RVM's capistrano plugin.
39
+
40
+ # Sets the rvm to a specific version (or whatever env you want it to run in)
41
+ set :rvm_ruby_string, '1.9.2' unless exists?(:rvm_ruby_string)
42
+ end
43
+
44
+ # Daemons settings
45
+ # The unix socket that unicorn will be attached to.
46
+ # Also, nginx will upstream to this guy.
47
+ # The *nix place for socks is /var/run, so we should probably put it there
48
+ # Make sure the runner can access this though.
49
+ set :sockets_path, "/var/run/#{application}" unless exists?(:sockets_path)
50
+
51
+ # Just to be safe, put the pid somewhere that survives deploys. shared/pids is
52
+ # a good choice as any.
53
+ set(:pids_path) { File.join(shared_path, "pids") } unless exists?(:pids_path)
54
+
55
+ set :monitorer, 'bluepill' unless exists?(:monitorer)
56
+
57
+ # Application settings
58
+ set :shared_dirs, %w(config config/pills uploads backup bundle tmp sockets pids log system) unless exists?(:shared_dirs)
59
+
60
+ namespace :app do
61
+ task :setup, :roles => :app do
62
+ commands = shared_dirs.map do |path|
63
+ "if [ ! -d '#{path}' ]; then mkdir -p #{path}; fi;"
64
+ end
65
+ run "cd #{shared_path}; #{commands.join(' ')}"
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,66 @@
1
+ Capistrano::Configuration.instance.load do
2
+ set(:bluepill_local_config) { "#{templates_path}/app.bluepill.erb" } unless exists?(:nginx_local_config)
3
+ set(:bluepill_remote_config) { "#{shared_path}/config/pills/#{application}.pill" } unless exists?(:nginx_remote_config)
4
+
5
+ namespace :bluepill do
6
+ desc "|capistrano-recipes| Parses and uploads nginx configuration for this app."
7
+ task :setup, :roles => :app , :except => { :no_release => true } do
8
+ generate_config(bluepill_local_config, bluepill_remote_config)
9
+ end
10
+
11
+ desc "|capistrano-recipes| Install the bluepill monitoring tool"
12
+ task :install, :roles => [:app] do
13
+ sudo "gem install bluepill"
14
+ end
15
+
16
+ desc "|capistrano-recipes| Stop processes that bluepill is monitoring and quit bluepill"
17
+ task :quit, :roles => [:app] do
18
+ args = exists?(:options) ? options : ''
19
+ begin
20
+ rvmsudo "bluepill stop #{args}"
21
+ rescue
22
+ puts "Bluepill was unable to finish gracefully all the process"
23
+ ensure
24
+ rvmsudo "bluepill quit"
25
+ end
26
+ end
27
+
28
+ desc "|capistrano-recipes| Load the pill from {your-app}/config/pills/{app-name}.pill"
29
+ task :init, :roles =>[:app] do
30
+ rvmsudo "bluepill load #{shared_path}/config/pills/#{application}.pill"
31
+ end
32
+
33
+ desc "|capistrano-recipes| Starts your previous stopped pill"
34
+ task :start, :roles =>[:app] do
35
+ args = exists?(:options) ? options : ''
36
+ app = exists?(:app) ? app : application
37
+ rvmsudo "bluepill #{app} start #{args}"
38
+ end
39
+
40
+ desc "|capistrano-recipes| Stops some bluepill monitored process"
41
+ task :stop, :roles =>[:app] do
42
+ args = exists?(:options) ? options : ''
43
+ app = exists?(:app) ? app : application
44
+ rvmsudo "bluepill #{app} stop #{args}"
45
+ end
46
+
47
+ desc "|capistrano-recipes| Restarts the pill from {your-app}/config/pills/{app-name}.pill"
48
+ task :restart, :roles =>[:app] do
49
+ args = exists?(:options) ? options : ''
50
+ app = exists?(:app) ? app : application
51
+ rvmsudo "bluepill #{app} restart #{args}"
52
+ end
53
+
54
+ desc "|capistrano-recipes| Prints bluepills monitored processes statuses"
55
+ task :status, :roles => [:app] do
56
+ args = exists?(:options) ? options : ''
57
+ app = exists?(:app) ? app : application
58
+ rvmsudo "bluepill #{app} status #{args}"
59
+ end
60
+ end
61
+
62
+ after 'deploy:setup' do
63
+ bluepill.install if Capistrano::CLI.ui.agree("Do you want to install the bluepill monitor? [Yn]")
64
+ bluepill.setup if Capistrano::CLI.ui.agree("Create bluepill configuration file? [Yn]")
65
+ end if is_using('bluepill', :monitorer)
66
+ end
@@ -0,0 +1,14 @@
1
+ Capistrano::Configuration.instance.load do
2
+ namespace :bundler do
3
+ desc "|capistrano-recipes| Installs bundler gem to your server"
4
+ task :setup, :roles => :app do
5
+ run "if ! gem list | grep --silent -e 'bundler'; then #{try_sudo} gem uninstall bundler; #{try_sudo} gem install --no-rdoc --no-ri bundler; fi"
6
+ end
7
+
8
+ desc "|capistrano-recipes| Runs bundle install on the app server (internal task)"
9
+ task :install, :roles => :app, :except => { :no_release => true } do
10
+ run "cd #{current_path} && bundle install --deployment --without=development test"
11
+ end
12
+ end
13
+ end
14
+
data/lib/recipes/db.rb ADDED
@@ -0,0 +1,97 @@
1
+ require 'erb'
2
+
3
+ Capistrano::Configuration.instance.load do
4
+ namespace :db do
5
+ namespace :mongodb do
6
+ desc <<-EOF
7
+ |capistrano-recipes| Performs a compressed database dump. \
8
+ WARNING: This locks your tables for the duration of the mongodump.
9
+ Don't run it madly!
10
+ EOF
11
+ task :dump, :roles => :db, :only => { :primary => true } do
12
+ prepare_from_yaml
13
+ run "mongodump -u #{db_user} -p #{db_pass} -h #{db_host} --port #{db_port} -d #{db_name} #{db_backup_path}" do |ch, stream, out|
14
+ puts out
15
+ end
16
+ end
17
+
18
+ desc "|capistrano-recipes| Restores the database from the latest compressed dump"
19
+ task :restore, :roles => :db, :only => { :primary => true } do
20
+ prepare_from_yaml
21
+ run "mongorestore --drop -d #{db_name} #{db_backup_path}/#{db_name}" do |ch, stream, out|
22
+ puts out
23
+ end
24
+ end
25
+
26
+ desc "|capistrano-recipes| Downloads the compressed database dump to this machine"
27
+ task :fetch_dump, :roles => :db, :only => { :primary => true } do
28
+ prepare_from_yaml
29
+ download db_remote_file, db_local_file, :via => :scp
30
+ end
31
+
32
+ # Sets database variables from remote database.yaml
33
+ def prepare_from_yaml
34
+ set(:db_backup_path) { "#{shared_path}/backup/" }
35
+ set(:db_local_file) { "tmp/#{db_file}" }
36
+ set(:db_user) { db_config[rails_env]["username"] }
37
+ set(:db_pass) { db_config[rails_env]["password"] }
38
+ set(:db_host) { db_config[rails_env]["host"] }
39
+ set(:db_name) { db_config[rails_env]["database"] }
40
+ end
41
+
42
+ def db_config
43
+ @db_config ||= fetch_db_config
44
+ end
45
+
46
+ def fetch_db_config
47
+ require 'yaml'
48
+ file = capture "cat #{shared_path}/config/mongoid.yml"
49
+ db_config = YAML.load(file)
50
+ end
51
+ end
52
+
53
+ desc "|capistrano-recipes| Create mongoid.yml in shared path with settings for current stage and test env"
54
+ task :setup do
55
+ set(:db_host) { Capistrano::CLI.ui.ask("Enter #{environment} database host:") {|q|q.default = "localhost"} }
56
+ set(:db_port) { Capistrano::CLI.ui.ask("Enter #{environment} database port:", Integer){|q| q.default = 27017 } }
57
+ set(:db_user) { Capistrano::CLI.ui.ask "Enter #{environment} database username:" }
58
+ set(:db_pass) { Capistrano::CLI.password_prompt "Enter #{environment} database password:" }
59
+ set(:db_safe_mode) { Capistrano::CLI.ui.agree "Enable safe mode on #{environment} database? [Yn]:" }
60
+
61
+ db_config = ERB.new <<-EOF
62
+ defaults: &defaults
63
+ host: #{db_host}
64
+ port: #{db_port}
65
+ <% if db_user && !db_user.empty? %>
66
+ username: #{db_user}
67
+ password: #{db_pass}
68
+ <% end %>
69
+ autocreate_indexes: false
70
+ allow_dynamic_fields: true
71
+ include_root_in_json: false
72
+ parameterize_keys: true
73
+ persist_in_safe_mode: #{db_safe_mode}
74
+ raise_not_found_error: true
75
+ reconnect_time: 3
76
+
77
+ development:
78
+ <<: *defaults
79
+ database: #{application}-development
80
+
81
+ test:
82
+ <<: *defaults
83
+ database: #{application}-test
84
+
85
+ production:
86
+ <<: *defaults
87
+ database: #{application}-production
88
+ EOF
89
+
90
+ put db_config.result(binding), "#{shared_path}/config/mongoid.yml"
91
+ end
92
+ end
93
+
94
+ after "deploy:setup" do
95
+ db.setup if Capistrano::CLI.ui.agree("Create mongoid.yml in app's shared path? [Yn]")
96
+ end
97
+ end
@@ -0,0 +1,65 @@
1
+ Capistrano::Configuration.instance.load do
2
+ set :shared_children, %w(system log pids config)
3
+
4
+ namespace :deploy do
5
+ desc "|capistrano-recipes| Deploy it, github-style."
6
+ task :default, :roles => :app, :except => { :no_release => true } do
7
+ update
8
+ restart
9
+ end
10
+
11
+ desc "|capistrano-recipes| Destroys everything"
12
+ task :seppuku, :roles => :app, :except => { :no_release => true } do
13
+ run "rm -rf #{current_path}; rm -rf #{shared_path}"
14
+ end
15
+
16
+ desc "|capistrano-recipes| Create shared dirs"
17
+ task :setup_dirs, :roles => :app, :except => { :no_release => true } do
18
+ commands = shared_dirs.map do |path|
19
+ "mkdir -p #{shared_path}/#{path}"
20
+ end
21
+ run commands.join(" && ")
22
+ end
23
+
24
+ desc "|capistrano-recipes| Uploads your local config.yml to the server"
25
+ task :configure, :roles => :app, :except => { :no_release => true } do
26
+ generate_config('config/config.yml', "#{shared_path}/config/config.yml")
27
+ end
28
+
29
+ desc "|capistrano-recipes| Setup a GitHub-style deployment."
30
+ task :setup, :roles => :app, :except => { :no_release => true } do
31
+ run "rm -rf #{current_path}"
32
+ setup_dirs
33
+ run "git clone #{repository} #{current_path}"
34
+ end
35
+
36
+ desc "|capistrano-recipes| Update the deployed code."
37
+ task :update_code, :roles => :app, :except => { :no_release => true } do
38
+ run "cd #{current_path}; git fetch origin; git reset --hard #{branch}"
39
+ end
40
+
41
+ desc "|capistrano-recipes| Alias for symlinks:make"
42
+ task :symlink, :roles => :app, :except => { :no_release => true } do
43
+ symlinks.make
44
+ end
45
+
46
+ desc "|capistrano-recipes| Remote run for rake db:seed"
47
+ task :migrate, :roles => :app, :except => { :no_release => true } do
48
+ run "cd #{current_path}; bundle exec rake RAILS_ENV=#{rails_env} db:seed"
49
+ end
50
+
51
+ desc "|capistrano-recipes| [Obsolete] Nothing to cleanup when using reset --hard on git"
52
+ task :cleanup, :roles => :app, :except => { :no_release => true } do
53
+ #nothing to cleanup, we're not working with 'releases'
54
+ puts "Nothing to cleanup, yay!"
55
+ end
56
+
57
+ namespace :rollback do
58
+ desc "|capistrano-recipes| Rollback , :except => { :no_release => true }a single commit."
59
+ task :default, :roles => :app, :except => { :no_release => true } do
60
+ set :branch, "HEAD^"
61
+ deploy.default
62
+ end
63
+ end
64
+ end
65
+ end