chicken_soup 0.6.1 → 0.8.0

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