chicken_soup 0.6.1 → 0.8.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.
Files changed (41) hide show
  1. data/lib/chicken_soup/capabilities/apache/apache-checks.rb +0 -2
  2. data/lib/chicken_soup/capabilities/apache/apache-defaults.rb +7 -12
  3. data/lib/chicken_soup/capabilities/bundler/bundler-checks.rb +0 -2
  4. data/lib/chicken_soup/capabilities/bundler/bundler-defaults.rb +0 -2
  5. data/lib/chicken_soup/capabilities/bundler/bundler-tasks.rb +0 -2
  6. data/lib/chicken_soup/capabilities/heroku/heroku-checks.rb +0 -2
  7. data/lib/chicken_soup/capabilities/heroku/heroku-defaults.rb +0 -2
  8. data/lib/chicken_soup/capabilities/nginx/nginx-checks.rb +0 -2
  9. data/lib/chicken_soup/capabilities/nginx/nginx-defaults.rb +7 -8
  10. data/lib/chicken_soup/capabilities/passenger/passenger-defaults.rb +9 -1
  11. data/lib/chicken_soup/capabilities/rvm/rvm-checks.rb +0 -2
  12. data/lib/chicken_soup/capabilities/rvm/rvm-defaults.rb +13 -13
  13. data/lib/chicken_soup/capabilities/rvm/rvm-tasks.rb +0 -2
  14. data/lib/chicken_soup/capabilities/shared/db-checks.rb +5 -3
  15. data/lib/chicken_soup/capabilities/shared/db-defaults.rb +10 -2
  16. data/lib/chicken_soup/capabilities/shared/db-tasks.rb +67 -15
  17. data/lib/chicken_soup/capabilities/shared/web_server-defaults.rb +13 -0
  18. data/lib/chicken_soup/capabilities/shared/web_server-tasks.rb +4 -6
  19. data/lib/chicken_soup/capabilities/svn/svn-defaults.rb +0 -2
  20. data/lib/chicken_soup/capabilities/unix/unix-checks.rb +3 -5
  21. data/lib/chicken_soup/capabilities/unix/unix-defaults.rb +11 -12
  22. data/lib/chicken_soup/capabilities/unix/unix-tasks.rb +0 -2
  23. data/lib/chicken_soup/capabilities.rb +0 -2
  24. data/lib/chicken_soup/environment/checks.rb +3 -6
  25. data/lib/chicken_soup/environment/defaults.rb +11 -4
  26. data/lib/chicken_soup/environment/tasks.rb +1 -1
  27. data/lib/chicken_soup/global.rb +98 -5
  28. data/lib/chicken_soup/notifiers/email/email-checks.rb +0 -2
  29. data/lib/chicken_soup/notifiers/email/email-defaults.rb +0 -2
  30. data/lib/chicken_soup/notifiers/email/presenter.rb +2 -4
  31. data/lib/chicken_soup/notifiers/git/git-tasks.rb +2 -2
  32. data/lib/chicken_soup/notifiers.rb +0 -2
  33. data/lib/chicken_soup/templates/maintenance.html.erb +41 -0
  34. data/lib/chicken_soup/tools/defaults.rb +41 -0
  35. data/lib/chicken_soup/tools/log/log-defaults.rb +21 -0
  36. data/lib/chicken_soup/tools/log/log-tasks.rb +56 -0
  37. data/lib/chicken_soup/tools/tasks.rb +12 -0
  38. data/lib/chicken_soup/tools.rb +16 -0
  39. data/lib/chicken_soup/version.rb +1 -1
  40. data/lib/chicken_stock.rb +4 -0
  41. metadata +9 -2
@@ -2,8 +2,6 @@
2
2
  # APACHE CHECKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :variable do
9
7
  namespace :check do
@@ -2,27 +2,22 @@
2
2
  # APACHE DEFAULTS #
3
3
  ######################################################################
4
4
  module ChickenSoup
5
- def find_web_server_control_script
6
- if remote_file_exists?("/usr/sbin/apachectl")
7
- set :web_server_control_script, "/usr/sbin/apachectl"
8
- elsif remote_file_exists?("/usr/sbin/apache2")
9
- set :web_server_control_script, "/usr/sbin/apache2"
10
- elsif remote_file_exists?("/usr/sbin/httpd")
11
- set :web_server_control_script, "/usr/sbin/httpd"
12
- end
13
-
14
- abort "Couldn't figure out how to control your installation of Apache" unless exists?(:web_server_control_script)
5
+ module WebServer
6
+ STANDARD_CONTROL_SCRIPTS = ['/usr/sbin/apachectl', '/usr/sbin/apache2', '/usr/sbin/httpd']
7
+ STANDARD_LOG_LOCATIONS = ['/var/log/apache2', '/var/log/httpd', '/etc/httpd/logs']
8
+ STANDARD_ERROR_LOGS = ['error_log', 'error.log', 'httpd-error.log']
9
+ STANDARD_ACCESS_LOGS = ['access_log', 'access.log', 'httpd-access.log']
15
10
  end
16
11
  end
17
12
 
18
13
  Capistrano::Configuration.instance(:must_exist).load do
19
- extend ChickenSoup
14
+ require 'chicken_soup/capabilities/shared/web_server-defaults'
20
15
 
21
16
  namespace :capabilities do
22
17
  namespace :defaults do
23
18
  desc "[internal] Sets intelligent defaults for Apache deployments."
24
19
  task :apache do
25
- find_web_server_control_script
20
+ capabilities.defaults.web_server
26
21
 
27
22
  if web_server_control_script =~ /apache2/
28
23
  set :apache_enable_script, "a2ensite"
@@ -2,8 +2,6 @@
2
2
  # BUNDLER CHECKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :variable do
9
7
  namespace :check do
@@ -2,8 +2,6 @@
2
2
  # BUNDLER DEFAULTS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :defaults do
9
7
  desc "[internal] Sets intelligent defaults for Bundler deployments."
@@ -2,8 +2,6 @@
2
2
  # BUNDLER TASKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  before 'gems:install', 'bundler:install'
8
6
 
9
7
  run_task 'bundler:install', :as => manager_username
@@ -2,8 +2,6 @@
2
2
  # HEROKU CHECKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :variable do
9
7
  namespace :check do
@@ -2,8 +2,6 @@
2
2
  # HEROKU DEFAULTS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :defaults do
9
7
  desc "[internal] Sets intelligent defaults for Heroku deployments"
@@ -2,8 +2,6 @@
2
2
  # NGINX CHECKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :variable do
9
7
  namespace :check do
@@ -2,23 +2,22 @@
2
2
  # NGINX DEFAULTS #
3
3
  ######################################################################
4
4
  module ChickenSoup
5
- def find_web_server_control_script
6
- if remote_file_exists?("/etc/init.d/nginx")
7
- set :web_server_control_script, "/etc/init.d/nginx"
8
- end
9
-
10
- abort "Couldn't figure out how to control your installation of Nginx" unless exists?(:web_server_control_script)
5
+ module WebServer
6
+ STANDARD_CONTROL_SCRIPTS = ['/etc/init.d/nginx']
7
+ STANDARD_LOG_LOCATIONS = ['/var/log/nginx', '/var/log/nginx/current']
8
+ STANDARD_ERROR_LOGS = ['error.log']
9
+ STANDARD_ACCESS_LOGS = ['access.log']
11
10
  end
12
11
  end
13
12
 
14
13
  Capistrano::Configuration.instance(:must_exist).load do
15
- extend ChickenSoup
14
+ require 'chicken_soup/capabilities/shared/web_server-defaults'
16
15
 
17
16
  namespace :capabilities do
18
17
  namespace :defaults do
19
18
  desc "[internal] Checks to see what type of Nginx installation is running on the remote."
20
19
  task :nginx do
21
- find_web_server_control_script
20
+ capabilities.defaults.web_server
22
21
  end
23
22
  end
24
23
  end
@@ -1,10 +1,18 @@
1
1
  ######################################################################
2
2
  # PASSENGER DEFAULTS #
3
3
  ######################################################################
4
+ module ChickenSoup
5
+ module ApplicationServer
6
+ STANDARD_LOGS = ['passenger_log', 'passenger.log', 'passenger']
7
+ end
8
+ end
9
+
4
10
  Capistrano::Configuration.instance(:must_exist).load do
5
11
  namespace :capabilities do
6
12
  namespace :defaults do
7
- set :application_server_type, :passenger
13
+ task :passenger do
14
+ set :application_server_type, :passenger
15
+ end
8
16
  end
9
17
  end
10
18
  end
@@ -2,8 +2,6 @@
2
2
  # RVM CHECKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :variable do
9
7
  namespace :check do
@@ -6,24 +6,24 @@ module ChickenSoup
6
6
  end
7
7
 
8
8
  Capistrano::Configuration.instance(:must_exist).load do
9
- extend ChickenSoup
10
-
11
9
  namespace :capabilities do
12
10
  namespace :defaults do
13
- _cset :rvmrc_file, File.join(rails_root, '.rvmrc')
14
- set :ruby_version_update_pending, false
11
+ task :rvm do
12
+ _cset :rvmrc_file, File.join(rails_root, '.rvmrc')
13
+ set :ruby_version_update_pending, false
15
14
 
16
- _cset(:ruby_version) do
17
- contents = File.read(rvmrc_file)
18
- contents.match(ChickenSoup::RVM_INFO_FORMAT)[2]
19
- end
15
+ _cset(:ruby_version) do
16
+ contents = File.read(rvmrc_file)
17
+ contents.match(ChickenSoup::RVM_INFO_FORMAT)[2]
18
+ end
20
19
 
21
- _cset(:ruby_gemset) do
22
- contents = File.read(rvmrc_file)
23
- contents.match(ChickenSoup::RVM_INFO_FORMAT)[3]
24
- end
20
+ _cset(:ruby_gemset) do
21
+ contents = File.read(rvmrc_file)
22
+ contents.match(ChickenSoup::RVM_INFO_FORMAT)[3]
23
+ end
25
24
 
26
- _cset(:full_ruby_environment_string) {ruby_gemset ? "#{ruby_version}@#{ruby_gemset}" : ruby_version}
25
+ _cset(:full_ruby_environment_string) {ruby_gemset ? "#{ruby_version}@#{ruby_gemset}" : ruby_version}
26
+ end
27
27
  end
28
28
  end
29
29
  end
@@ -8,8 +8,6 @@ module ChickenSoup
8
8
  end
9
9
 
10
10
  Capistrano::Configuration.instance(:must_exist).load do
11
- extend ChickenSoup
12
-
13
11
  run_task 'ruby:update', :as => manager_username
14
12
 
15
13
  namespace :ruby do
@@ -2,8 +2,6 @@
2
2
  # DB CHECKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :variable do
9
7
  namespace :check do
@@ -13,7 +11,11 @@ Capistrano::Configuration.instance(:must_exist).load do
13
11
  task :db do
14
12
  required_variables = [
15
13
  :skip_backup_before_migration,
16
- :db_backups_path
14
+ :db_backups_path,
15
+ :db_backup_file_extension,
16
+ :autocompress_db_backups,
17
+ :limit_db_backups,
18
+ :total_db_backup_limit
17
19
  ]
18
20
 
19
21
  verify_variables(required_variables)
@@ -2,14 +2,22 @@
2
2
  # DB DEFAULTS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :defaults do
9
7
  desc "[internal] Sets intelligent defaults for DB deployments."
10
8
  task :db do
11
9
  _cset :skip_backup_before_migration, false
10
+
12
11
  _cset :db_backups_path, "#{shared_path}/db_backups"
12
+ _cset :db_backup_file_extension, "dump.sql"
13
+
14
+ _cset :autocompress_db_backups, true
15
+
16
+ set(:latest_db_backup_file) {capture("ls #{db_backups_path} -1t | head -n 1").chomp}
17
+ set(:latest_db_backup) {"#{db_backups_path}/#{latest_db_backup_file}"}
18
+
19
+ _cset :limit_db_backups, true
20
+ _cset :total_db_backup_limit, 100
13
21
  end
14
22
  end
15
23
  end
@@ -2,8 +2,6 @@
2
2
  # COMMON DB TASKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  _cset(:db_root_password) {Capistrano::CLI.password_prompt("Root Password For DB: ")}
8
6
  _cset(:db_app_password) {Capistrano::CLI.password_prompt("App Password For DB: ")}
9
7
 
@@ -11,20 +9,71 @@ Capistrano::Configuration.instance(:must_exist).load do
11
9
  run_task "db:drop", :as => manager_username
12
10
 
13
11
  before "deploy:cleanup", "deploy:migrate"
14
- before "deploy:migrate", "db:backup" unless skip_backup_before_migration
12
+ before "deploy:migrate", "db:backup" unless skip_backup_before_migration
15
13
 
16
- namespace :db do
17
- desc <<-DESC
18
- Calls the rake task `db:backup` on the server for the given environment.
14
+ after "db:backup", "db:backup:compress" if autocompress_db_backups
15
+ after "db:backup", "db:backup:cleanup" if limit_db_backups
19
16
 
20
- * The backup file is placed in a directory called `db_backups` under the `shared`
21
- directory by default.
22
- * The filenames are formatted with the timestamp of the backup.
23
- * After export, each file is zipped up using a bzip2 compression format.
24
- DESC
17
+ namespace :db do
25
18
  namespace :backup do
19
+ desc <<-DESC
20
+ Calls the rake task `db:backup` on the server for the given environment.
21
+
22
+ * The backup file is placed in a directory called `db_backups` under the `shared`
23
+ directory by default.
24
+ * The filenames are formatted with the timestamp of the backup.
25
+ * After export, each file is zipped up using a bzip2 compression format.
26
+ DESC
26
27
  task :default, :roles => :db, :only => {:primary => true} do
27
- run "cd #{current_path} && BACKUP_DIRECTORY=#{db_backups_path} #{rake} db:backup"
28
+ run %Q{cd #{current_path} && BACKUP_DIRECTORY="#{db_backups_path}" BACKUP_FILE="#{release_name}" BACKUP_FILE_EXTENSION="#{db_backup_file_extension}" #{rake} db:backup}
29
+ end
30
+
31
+ desc <<-DESC
32
+ If the user has decided they would like to limit the number of db backups
33
+ that can exist on the system, this task is called to clean up any files
34
+ which are over that limit.
35
+
36
+ The oldest files are cleaned up first.
37
+ DESC
38
+ task :cleanup, :roles => :db, :only => {:primary => true} do
39
+ number_of_backups = capture("ls #{db_backups_path} -1 | wc -l").chomp.to_i
40
+
41
+ if number_of_backups > total_db_backup_limit
42
+ backup_files_to_remove = capture("ls #{db_backups_path}/* -1t | tail -n #{number_of_backups - total_db_backup_limit}").chomp.split("\n")
43
+
44
+ backup_files_to_remove.each do |file|
45
+ run "rm -f #{file}"
46
+ end
47
+ end
48
+ end
49
+
50
+ namespace :compress do
51
+ desc <<-DESC
52
+ Compresses the most recent backup if it isn't already compressed.
53
+
54
+ The compression format is bzip2.
55
+ DESC
56
+ task :default, :roles => :db, :only => {:primary => true} do
57
+ run "bzip2 -zvck9 #{latest_db_backup} > #{latest_db_backup}.bz2 && rm -f #{latest_db_backup}" unless compressed_file?(latest_db_backup)
58
+
59
+ # After compressing, the latest_db_backup is no longer the latest DB
60
+ # backup so we need to reset it.
61
+ reset! :latest_db_backup_file
62
+ reset! :latest_db_backup
63
+ end
64
+
65
+ desc <<-DESC
66
+ Compresses any uncompressed DB backups to help save space.
67
+
68
+ The compression format is bzip2.
69
+ DESC
70
+ task :all, :roles => :db, :only => {:primary => true} do
71
+ uncompressed_backup_files = capture("ls #{db_backups_path}/*.#{db_backup_file_extension} -1tr").chomp.split("\n")
72
+
73
+ uncompressed_backup_files.each do |file|
74
+ run "bzip2 -zvck9 #{file} > #{file}.bz2 && rm -f #{file}"
75
+ end
76
+ end
28
77
  end
29
78
  end
30
79
 
@@ -49,12 +98,15 @@ Capistrano::Configuration.instance(:must_exist).load do
49
98
  Just like `db:pull` but doesn't create a new backup first.
50
99
  DESC
51
100
  task :latest, :roles => :db, :only => {:primary => true} do
52
- latest_backup = capture(%Q{ls #{db_backups_path} -xtC | head -n 1 | cut -d " " -f 1}).chomp
101
+ download_compressed "#{latest_db_backup}", "#{rails_root}/tmp/#{latest_db_backup_file}", :once => true
53
102
 
54
- download_compressed "#{db_backups_path}/#{latest_backup}", "#{rails_root}/tmp/#{latest_backup}", :once => true
103
+ latest_local_db_backup = `ls -1t #{rails_root}/tmp/*.#{db_backup_file_extension} | head -n 1`.chomp
55
104
 
105
+ puts 'Running `rake db:drop:all db:create:all` locally'
56
106
  `rake db:drop:all db:create:all`
57
- `rails dbconsole development < #{rails_root}/tmp/#{latest_backup}`
107
+ puts "Running `rails dbconsole development < #{latest_local_db_backup}` locally"
108
+ `rails dbconsole development < #{latest_local_db_backup}`
109
+ puts "Running `rake db:migrate db:test:prepare` locally"
58
110
  `rake db:migrate db:test:prepare`
59
111
  end
60
112
  end
@@ -0,0 +1,13 @@
1
+ ######################################################################
2
+ # WEB SERVER DEFAULTS #
3
+ ######################################################################
4
+ Capistrano::Configuration.instance(:must_exist).load do
5
+ namespace :capabilities do
6
+ namespace :defaults do
7
+ desc "[internal] Sets common defaults for web servers."
8
+ task :web_server do
9
+ _cset(:web_server_control_script) { WebServer::STANDARD_CONTROL_SCRIPTS.detect { |f| remote_directory_exists? f } }
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,8 +2,6 @@
2
2
  # COMMON WEB SERVER TASKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  run_task 'web_server:stop', :as => manager_username
8
6
  run_task 'web_server:start', :as => manager_username
9
7
  run_task 'web_server:restart', :as => manager_username
@@ -50,7 +48,7 @@ Capistrano::Configuration.instance(:must_exist).load do
50
48
  web-accessible again.
51
49
  DESC
52
50
  task :disable, :roles => :web do
53
- run "rm #{shared_path}/system/maintenance.html"
51
+ run "rm #{shared_path}/system/#{maintenance_basename}.html"
54
52
  end
55
53
 
56
54
  desc <<-DESC
@@ -70,15 +68,15 @@ Capistrano::Configuration.instance(:must_exist).load do
70
68
  Further customization will require that you write your own task.
71
69
  DESC
72
70
  task :enable, :roles => :web do
73
- on_rollback { rm "#{shared_path}/system/maintenance.html" }
71
+ on_rollback { rm "#{shared_path}/system/#{maintenance_basename}.html" }
74
72
 
75
73
  require 'erb'
76
74
  deadline, reason = ENV['UNTIL'], ENV['REASON']
77
75
 
78
- template = File.read("./public/maintenance.html.erb")
76
+ template = File.read(maintenance_filename)
79
77
  maintenance_page = ERB.new(template).result(binding)
80
78
 
81
- put maintenance_page, "#{shared_path}/system/maintenance.html", :mode => 0644
79
+ put maintenance_page, "#{shared_path}/system/#{maintenance_basename}.html", :mode => 0644
82
80
  end
83
81
  end
84
82
  end
@@ -2,8 +2,6 @@
2
2
  # SUBVERSION DEFAULTS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :defaults do
9
7
  desc "[internal] Sets intelligent version control defaults for deployments"
@@ -2,8 +2,6 @@
2
2
  # UNIX CHECKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :variable do
9
7
  namespace :check do
@@ -24,9 +22,9 @@ Capistrano::Configuration.instance(:must_exist).load do
24
22
  :app_server_ip,
25
23
  :web_server_ip,
26
24
  :db_server_ip,
27
- :web_servers,
28
- :app_servers,
29
- :db_servers
25
+ :web_server_name,
26
+ :app_server_name,
27
+ :db_server_name
30
28
  ]
31
29
 
32
30
  verify_variables(required_variables)
@@ -2,8 +2,6 @@
2
2
  # UNIX SERVER DEFAULTS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :capabilities do
8
6
  namespace :defaults do
9
7
  desc "[internal] Sets intelligent defaults for unix server deployments."
@@ -19,15 +17,16 @@ Capistrano::Configuration.instance(:must_exist).load do
19
17
  _cset :deploy_site_name, domain
20
18
  set :deploy_to, "#{deploy_base_dir}/#{deploy_site_name}"
21
19
 
22
- _cset :app_server_ip, default_server_ip
23
- _cset :web_server_ip, default_server_ip
24
- _cset :db_server_ip, default_server_ip
25
-
26
20
  _cset :default_server_name, domain
21
+ _cset(:default_server_ip) { lookup_ip_for default_server_name }
22
+
23
+ _cset(:app_server_name) { default_server_name }
24
+ _cset(:web_server_name) { default_server_name }
25
+ _cset(:db_server_name) { default_server_name }
27
26
 
28
- _cset(:app_servers) { default_server_name }
29
- _cset(:web_servers) { default_server_name }
30
- _cset(:db_servers) { default_server_name }
27
+ _cset(:app_server_ip) { lookup_ip_for app_server_name }
28
+ _cset(:web_server_ip) { lookup_ip_for web_server_name }
29
+ _cset(:db_server_ip) { lookup_ip_for db_server_name }
31
30
 
32
31
  # Evidently roles can't be assigned in a namespace :-/
33
32
  set_unix_server_roles
@@ -37,8 +36,8 @@ Capistrano::Configuration.instance(:must_exist).load do
37
36
 
38
37
  desc "[internal] This task is only here because `role` cannot be used within a `namespace`"
39
38
  task :set_unix_server_roles do
40
- role :web, web_servers
41
- role :app, app_servers
42
- role :db, db_servers, :primary => true
39
+ role :web, web_server_name
40
+ role :app, app_server_name
41
+ role :db, db_server_name, :primary => true
43
42
  end
44
43
  end
@@ -2,8 +2,6 @@
2
2
  # UNIX TASKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  before "deploy:shared_files:symlink", "deploy:shared_files:setup"
8
6
 
9
7
  namespace :deploy do
@@ -14,8 +14,6 @@
14
14
  #
15
15
  ######################################################################
16
16
  Capistrano::Configuration.instance(:must_exist).load do
17
- extend ChickenSoup
18
-
19
17
  require 'chicken_soup/capabilities/defaults'
20
18
  require 'chicken_soup/capabilities/checks'
21
19
  require 'chicken_soup/capabilities/tasks'
@@ -6,8 +6,8 @@
6
6
  # First, an environment MUST be present in order for any deployment
7
7
  # to happen. It's a safety measure that this is explicitly stated.
8
8
  #
9
- # It also checks to make sure that the :application and
10
- # :application_short environment variables have been set.
9
+ # It also checks to make sure that the :application environment
10
+ # variable has been set.
11
11
  #
12
12
  # This happens before any of the capabilities have been added to the
13
13
  # deployment and therefore that is all we know to check for at this
@@ -15,8 +15,6 @@
15
15
  #
16
16
  ######################################################################
17
17
  Capistrano::Configuration.instance(:must_exist).load do
18
- extend ChickenSoup
19
-
20
18
  on :start, 'environment:variable:check', :except => ['staging', 'production']
21
19
  before 'deploy', 'environment:deployment:check'
22
20
  before 'deploy:cold', 'environment:deployment:check'
@@ -33,8 +31,7 @@ Capistrano::Configuration.instance(:must_exist).load do
33
31
  abort "You need to specify a deployment type in your application's 'deploy.rb' file. ie 'set :deployment_type, :heroku'" unless exists?(:deployment_type)
34
32
 
35
33
  required_variables = [
36
- :application,
37
- :application_short
34
+ :application
38
35
  ]
39
36
 
40
37
  verify_variables(required_variables)
@@ -20,23 +20,25 @@
20
20
  require 'etc'
21
21
 
22
22
  Capistrano::Configuration.instance(:must_exist).load do
23
- extend ChickenSoup
24
-
25
23
  after 'production', 'environment:defaults:production', 'environment:init'
26
24
  after 'staging', 'environment:defaults:staging', 'environment:init'
27
25
 
28
- after 'environment:defaults', 'capabilities:defaults', 'notifiers:defaults'
26
+ after 'environment:defaults', 'capabilities:defaults', 'notifiers:defaults', 'tools:defaults'
29
27
 
30
28
  namespace :environment do
31
29
  namespace :defaults do
32
30
  desc "[internal] Used to set up the intelligent staging defaults we like for our projects"
33
31
  task :staging do
34
32
  set :rails_env, 'staging'
33
+
34
+ _cset(:domain) { "staging.#{application}.com" }
35
35
  end
36
36
 
37
37
  desc "[internal] Used to set up the intelligent production defaults we like for our projects"
38
38
  task :production do
39
39
  set :rails_env, 'production'
40
+
41
+ _cset(:domain) { "#{application}.com" }
40
42
  end
41
43
 
42
44
  desc "[internal] Sets intelligent common defaults for deployments"
@@ -51,10 +53,15 @@ Capistrano::Configuration.instance(:must_exist).load do
51
53
 
52
54
  _cset :global_shared_elements, ["config/database.yml"]
53
55
 
56
+ _cset :maintenance_page_path, 'public'
57
+
54
58
  _cset :notifiers, []
59
+ _cset :tools, [:log]
55
60
 
56
- _cset(:application_short) {application}
57
61
  _cset(:application_underscored) {application.gsub(/-/, "_")}
62
+
63
+ _cset(:latest_release_name) {exists?(:deploy_timestamped) ? release_name : releases.last}
64
+ _cset(:previous_release_name) {releases.length > 1 ? releases[-2] : nil}
58
65
  end
59
66
  end
60
67
  end
@@ -2,7 +2,7 @@
2
2
  # ENVIRONMENT TASKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- after 'environment:load_tasks', 'capabilities:load_tasks', 'notifiers:load_tasks'
5
+ after 'environment:load_tasks', 'capabilities:load_tasks', 'notifiers:load_tasks', 'tools:load_tasks'
6
6
 
7
7
  namespace :environment do
8
8
  desc "[internal] A helper task used to load the tasks for all of the capabilities."
@@ -115,7 +115,13 @@ module ChickenSoup
115
115
  # remote_file_exists? '/var/www/myappdir/current'
116
116
  #
117
117
  def remote_file_exists?(file)
118
- capture("if [[ -d #{file} ]] || [[ -h #{file} ]] || [[ -f #{file} ]]; then echo -n 'exists'; fi;") == "exists"
118
+ capture("if [[ -d #{file} ]] || [[ -h #{file} ]] || [[ -f #{file} ]]; then echo -n 'exists'; fi;") == 'exists'
119
+ end
120
+
121
+ def remote_directory_exists?(directory, options = {})
122
+ with_files_check = options[:with_files] ? "&& $(ls -A #{directory})" : ''
123
+
124
+ capture("if [[ -d #{directory} #{with_files_check} ]]; then echo -n 'exists'; fi") == 'exists'
119
125
  end
120
126
 
121
127
  ###
@@ -152,16 +158,40 @@ module ChickenSoup
152
158
  # download_compressed 'my/remote/file', 'my/local/file', :once => true
153
159
  #
154
160
  def download_compressed(remote, local, options = {})
155
- remote_compressed_filename = "#{remote}.bz2"
156
- local_compressed_filename = "#{local}.bz2"
161
+ remote_basename = File.basename(remote)
162
+
163
+ unless compressed_file? remote
164
+ remote_compressed_filename = "#{user_home}/#{remote_basename}.bz2"
165
+ local_compressed_filename = "#{local}.bz2"
166
+
167
+ run "bzip2 -zvck9 #{remote} > #{remote_compressed_filename}"
168
+ end
169
+
170
+ remote_compressed_filename ||= remote
171
+ local_compressed_filename ||= local
157
172
 
158
- run "bzip2 -zvck9 #{remote} > #{remote_compressed_filename}"
159
173
  download remote_compressed_filename, local_compressed_filename, options
160
174
 
161
- run "rm -f #{remote_compressed_filename}"
175
+ run "rm -f #{remote_compressed_filename}" unless remote_compressed_filename == remote
162
176
  `bunzip2 -f #{local_compressed_filename} && rm -f #{local_compressed_filename}`
163
177
  end
164
178
 
179
+ ###
180
+ # Checks to see if a filename has an extension which would imply that
181
+ # it is compressed.
182
+ #
183
+ # @param [String] filename The filename whose extension will be checked.
184
+ #
185
+ # @return [Boolean] the result of whether the file has a compression
186
+ # extension.
187
+ #
188
+ # @example
189
+ # compressed_file? 'file.bz2'
190
+ #
191
+ def compressed_file?(filename)
192
+ filename =~ /.*\.bz2/
193
+ end
194
+
165
195
  ###
166
196
  # A stub method which simply passes through to Capistrano's #run. This
167
197
  # method is meant to be overridden when a Ruby manager capability (ie RVM)
@@ -195,4 +225,67 @@ module ChickenSoup
195
225
  def vc_log
196
226
  nil
197
227
  end
228
+
229
+ ###
230
+ # Uses nslookup locally to figure out the IP address of the provided
231
+ # hostname.
232
+ #
233
+ # @param [String] hostname The hostname you would like to retrieve the
234
+ # IP for.
235
+ #
236
+ # @return [String] The IP address of the provided hostname. If no
237
+ # IP can be retrieved, nil will be returned.
238
+ #
239
+ # @example
240
+ # lookup_ip_for 'google.com'
241
+ #
242
+ def lookup_ip_for(hostname)
243
+ ip = `nslookup #{hostname} | tail -n 2 | head -n 1 | cut -d ' ' -f 2`.chomp
244
+ ip != '' ? ip : nil
245
+ end
246
+
247
+ def find_all_logs(log_directory, log_filenames)
248
+ existing_files = []
249
+
250
+ log_filenames.each do |standard_file|
251
+ existing_files << "#{log_directory}/#{application}.#{standard_file}" if remote_file_exists?("#{log_directory}/#{application}.#{standard_file}")
252
+ existing_files << "#{log_directory}/#{application}-#{standard_file}" if remote_file_exists?("#{log_directory}/#{application}-#{standard_file}")
253
+ existing_files << "#{log_directory}/#{standard_file}" if remote_file_exists?("#{log_directory}/#{standard_file}")
254
+ end
255
+
256
+ existing_files
257
+ end
258
+
259
+ def log_directory(log_directories)
260
+ log_directories.detect do |directory|
261
+ remote_directory_exists? directory, :with_files => true
262
+ end
263
+ end
264
+
265
+ def fetch_log(logs)
266
+ logs.each do |log|
267
+ local_log_directory = "#{rails_root}/log/#{rails_env}/#{release_name}"
268
+
269
+ `mkdir -p #{local_log_directory}`
270
+ download log, "#{local_log_directory}/$CAPISTRANO:HOST$-#{File.basename(log)}"
271
+ end
272
+ end
273
+
274
+ def tail_log(logs)
275
+ run "tail -n #{ENV['lines'] || 20} -f #{logs.join ' '}" do |channel, stream, data|
276
+ trap("INT") { puts 'Log tailing aborted...'; exit 0; }
277
+
278
+ puts # for an extra line break before the host name
279
+ puts "#{channel[:host]}: #{data}"
280
+
281
+ break if stream == :err
282
+ end
283
+ end
284
+
285
+ def maintenance_filename
286
+ custom_maintenance_path = File.join(rails_root, maintenance_page_path, "#{maintenance_basename}.html.erb")
287
+ template_maintenance_path = File.join(File.dirname(__FILE__), "templates", "maintenance.html.erb")
288
+
289
+ File.exist?(custom_maintenance_path) ? custom_maintenance_path : template_maintenance_path
290
+ end
198
291
  end
@@ -2,8 +2,6 @@
2
2
  # EMAIL NOTIFIER CHECKS #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  namespace :notifiers do
8
6
  namespace :variable do
9
7
  namespace :check do
@@ -6,8 +6,6 @@ require 'erb'
6
6
  require 'chicken_soup/notifiers/email/presenter'
7
7
 
8
8
  Capistrano::Configuration.instance(:must_exist).load do |cap|
9
- extend ChickenSoup
10
-
11
9
  namespace :notifiers do
12
10
  namespace :defaults do
13
11
  task :email do
@@ -3,8 +3,6 @@ require 'time'
3
3
  module ChickenSoup
4
4
  module Email
5
5
  class Presenter
6
- include ChickenSoup
7
-
8
6
  LongDateFormat = "%A, %B %e, %Y at %l:%M%p %Z"
9
7
 
10
8
  def initialize(capistrano)
@@ -24,11 +22,11 @@ module ChickenSoup
24
22
  end
25
23
 
26
24
  def deploy_date_in_long_format
27
- format_timestamp(@capistrano[:current_release], LongDateFormat)
25
+ format_timestamp(@capistrano[:latest_release_name], LongDateFormat)
28
26
  end
29
27
 
30
28
  def previous_deploy_date_in_long_format
31
- format_timestamp(@capistrano[:previous_release], LongDateFormat)
29
+ format_timestamp(@capistrano[:previous_release_name], LongDateFormat)
32
30
  end
33
31
 
34
32
  def notifiers
@@ -19,9 +19,9 @@ Capistrano::Configuration.instance(:must_exist).load do
19
19
  Tag push happens in the background so it won't slow down deployment.
20
20
  DESC
21
21
  task :tag do
22
- tag_name = "deployment/#{rails_env}/#{current_release}"
22
+ tag_name = "deployment/#{rails_env}/#{latest_release_name}"
23
23
 
24
- `git tag -a -m "Tagging deploy to #{rails_env} at #{current_release}" #{tag_name} #{branch}`
24
+ `git tag -a -m "Tagging deploy to #{rails_env} at #{latest_release_name}" #{tag_name} #{branch}`
25
25
  `git push #{remote} --tags > /dev/null 2>&1 &`
26
26
  `git push origin --tags > /dev/null 2>&1 &`
27
27
  end
@@ -2,8 +2,6 @@
2
2
  # NOTIFIERS SETUP #
3
3
  ######################################################################
4
4
  Capistrano::Configuration.instance(:must_exist).load do
5
- extend ChickenSoup
6
-
7
5
  require 'chicken_soup/notifiers/defaults'
8
6
  require "chicken_soup/notifiers/checks"
9
7
  require "chicken_soup/notifiers/tasks"
@@ -0,0 +1,41 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+
5
+ <head>
6
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
7
+ <title>The page you were looking for doesn't exist (404)</title>
8
+ <style type="text/css">
9
+ body {
10
+ background-color: #fff;
11
+ color: #666;
12
+ text-align: center;
13
+ font-family: arial, sans-serif;
14
+ }
15
+
16
+ div.dialog {
17
+ width: 25em;
18
+ padding: 0 4em;
19
+ margin: 4em auto 0 auto;
20
+ border: 1px solid #ccc;
21
+ border-right-color: #999;
22
+ border-bottom-color: #999;
23
+ }
24
+
25
+ h1 {
26
+ font-size: 100%;
27
+ color: #f00;
28
+ line-height: 1.5em;
29
+ }
30
+ </style>
31
+ </head>
32
+
33
+ <body>
34
+
35
+ <div class="dialog">
36
+ <h1>The application is currently down for <%= reason || "maintenance" %>.</h1>
37
+
38
+ <p>As of <%= Time.now.strftime("%H:%M %Z") %> this application was taken offline. We apologize for the inconvenience and are doing everything we can to have the site back up <%= deadline ? "by #{deadline}" : "shortly" %>.</p>
39
+ </div>
40
+ </body>
41
+ </html>
@@ -0,0 +1,41 @@
1
+ ######################################################################
2
+ # DEFAULT TOOLS SETUP
3
+ #
4
+ # The 'tools:defaults' task hooks itself into the deployment
5
+ # stream by attaching an after hook to 'environment:defaults'.
6
+ #
7
+ # Prior to execution, all of the tools which were specified in
8
+ # the deploy.rb file are loaded and then each tool has its
9
+ # 'defaults' task called.
10
+ #
11
+ # All tools's defaults tasks are in the format:
12
+ # tools:defaults:<tool_name>
13
+ #
14
+ # Defaults tasks are there simply to set standard conventional
15
+ # standards on each tool. In almost all cases, they can
16
+ # be overridden.
17
+ #
18
+ # Defaults are also optional. If a tools doesn't require any
19
+ # environment variables to be set, it can simply omit a defaults task.
20
+ #
21
+ ######################################################################
22
+ Capistrano::Configuration.instance(:must_exist).load do
23
+ before 'tools:defaults', 'load_tool_defaults'
24
+
25
+ namespace :tools do
26
+ namespace :defaults do
27
+ desc <<-DESC
28
+ [internal] Installs all tools for the given deployment type.
29
+
30
+ Most of these values can be overridden in each application's deploy.rb file.
31
+ DESC
32
+ task :default do
33
+ if exists?(:tools)
34
+ fetch(:tools).each do |tool|
35
+ tools.defaults.send(tool.to_s) if tools.defaults.respond_to?(tool.to_sym)
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,21 @@
1
+ ######################################################################
2
+ # LOG DEFAULTS #
3
+ ######################################################################
4
+ Capistrano::Configuration.instance(:must_exist).load do
5
+ namespace :tools do
6
+ namespace :defaults do
7
+ task :log do
8
+ _cset(:web_server_error_log_files) { find_all_logs(web_server_log_directory, ChickenSoup::WebServer::STANDARD_ERROR_LOGS) }
9
+ _cset(:web_server_access_log_files) { find_all_logs(web_server_log_directory, ChickenSoup::WebServer::STANDARD_ACCESS_LOGS) }
10
+ _cset(:web_server_log_files) { web_server_access_log_files + web_server_error_log_files }
11
+ _cset(:web_server_log_directory) { log_directory(ChickenSoup::WebServer::STANDARD_LOG_LOCATIONS) }
12
+
13
+ _cset(:app_server_log_files) { find_all_logs(web_server_log_directory, ChickenSoup::ApplicationServer::STANDARD_LOGS) }
14
+
15
+ _cset(:rails_log_files) { ["#{shared_path}/log/#{rails_env}.log"] }
16
+
17
+ _cset(:log_files) { rails_log_files + app_server_log_files + web_server_log_files }
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,56 @@
1
+ ######################################################################
2
+ # LOG TASKS #
3
+ ######################################################################
4
+ Capistrano::Configuration.instance(:must_exist).load do
5
+ namespace :log do
6
+ desc <<-DESC
7
+ Begins tailing the Rails log file within the specified environment.
8
+
9
+ * Pass lines=<number> to give you a bigger look back at what has
10
+ recently happened. ie: cap staging log lines=50
11
+ DESC
12
+ task :default, :roles => :app do
13
+ log.all.tail
14
+ end
15
+
16
+ namespace :application do
17
+ task :fetch, :roles => :app do
18
+ fetch_log(rails_log_files)
19
+ end
20
+
21
+ task :tail, :roles => :app do
22
+ tail_log(rails_log_files)
23
+ end
24
+ end
25
+
26
+ namespace :app_server do
27
+ task :fetch, :roles => :app do
28
+ fetch_log(app_server_log_files)
29
+ end
30
+
31
+ task :tail, :roles => :app do
32
+ tail_log(app_server_log_files)
33
+ end
34
+ end
35
+
36
+ namespace :web_server do
37
+ task :fetch, :roles => :web do
38
+ fetch_log(web_server_log_files)
39
+ end
40
+
41
+ task :tail, :roles => :web do
42
+ tail_log(web_server_log_files)
43
+ end
44
+ end
45
+
46
+ namespace :all do
47
+ task :fetch, :roles => [:app, :web] do
48
+ fetch_log(log_files)
49
+ end
50
+
51
+ task :tail, :roles => [:app, :web] do
52
+ tail_log(log_files)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,12 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ before 'tools:load_tasks', 'load_tool_tasks'
3
+
4
+ namespace :tools do
5
+ desc <<-DESC
6
+ [internal] A helper task used to load all of the tasks associated with the
7
+ requested tools.
8
+ DESC
9
+ task :load_tasks do
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ ######################################################################
2
+ # TOOLS SETUP #
3
+ ######################################################################
4
+ Capistrano::Configuration.instance(:must_exist).load do
5
+ require "chicken_soup/tools/defaults"
6
+ require "chicken_soup/tools/tasks"
7
+
8
+ ['defaults', 'checks', 'tasks'].each do |method|
9
+ desc "[internal] This task is only here because `require` cannot be used within a `namespace`"
10
+ task "load_tool_#{method}".to_sym do
11
+ fetch(:tools).each do |tool|
12
+ require_if_exists "chicken_soup/tools/#{tool}/#{tool}-#{method}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module ChickenSoup
2
- VERSION = "0.6.1"
2
+ VERSION = "0.8.0"
3
3
  end
data/lib/chicken_stock.rb CHANGED
@@ -1,5 +1,9 @@
1
1
  require 'chicken_soup/global'
2
+
3
+ include ChickenSoup
4
+
2
5
  require 'chicken_soup/environment'
3
6
  require 'chicken_soup/capabilities'
4
7
  require 'chicken_soup/notifiers'
8
+ require 'chicken_soup/tools'
5
9
  require 'chicken_soup/deploy'
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: chicken_soup
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.6.1
5
+ version: 0.8.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - thekompanee
@@ -11,7 +11,7 @@ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
13
 
14
- date: 2011-08-11 00:00:00 -05:00
14
+ date: 2011-08-20 00:00:00 -05:00
15
15
  default_executable:
16
16
  dependencies:
17
17
  - !ruby/object:Gem::Dependency
@@ -119,6 +119,7 @@ files:
119
119
  - lib/chicken_soup/capabilities/shared/db-checks.rb
120
120
  - lib/chicken_soup/capabilities/shared/db-defaults.rb
121
121
  - lib/chicken_soup/capabilities/shared/db-tasks.rb
122
+ - lib/chicken_soup/capabilities/shared/web_server-defaults.rb
122
123
  - lib/chicken_soup/capabilities/shared/web_server-tasks.rb
123
124
  - lib/chicken_soup/capabilities/svn/svn-defaults.rb
124
125
  - lib/chicken_soup/capabilities/svn/svn-tasks.rb
@@ -144,6 +145,12 @@ files:
144
145
  - lib/chicken_soup/notifiers/tasks.rb
145
146
  - lib/chicken_soup/templates/client_email.html.erb
146
147
  - lib/chicken_soup/templates/internal_email.html.erb
148
+ - lib/chicken_soup/templates/maintenance.html.erb
149
+ - lib/chicken_soup/tools.rb
150
+ - lib/chicken_soup/tools/defaults.rb
151
+ - lib/chicken_soup/tools/log/log-defaults.rb
152
+ - lib/chicken_soup/tools/log/log-tasks.rb
153
+ - lib/chicken_soup/tools/tasks.rb
147
154
  - lib/chicken_soup/version.rb
148
155
  - lib/chicken_stock.rb
149
156
  - spec/support/focused.rb