engineyard-eycap 0.3.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,84 @@
1
+ == HEAD / 0000-00-00
2
+ * rake install_gem_no_doc for faster install
3
+
4
+ == 0.3.3 / 2008-05-07
5
+ * add ey_logger to log deploys to server
6
+
7
+ == 0.3.2 / 2008-04-29
8
+ * adding db:clone_to_local task to take a dump on the slice, fetch it, and load it into your dev db on your workstation
9
+ * only clone from replica database
10
+ * remove call to variable in task desc
11
+ * fix ferret symlinking
12
+ * gemspec for github
13
+
14
+ == 0.3.1 / 2008-03-17
15
+ * Make the custom maintenance pages actually work!
16
+
17
+ == 0.3.0 / 2008-03-05
18
+ * Adding custom maintenance pages is now as easy as copying a custom html file to #{shared_path}/system/maintenance.html.custom
19
+
20
+ == 0.2.10 / 2008-03-02
21
+ * Symlink memcached.yml only on :memcached => true, except :no_release => true
22
+
23
+ == 0.2.9 / 2008-02-27
24
+ * Fix a bug with ultrasphinx:configure running on multiple hosts
25
+
26
+ == 0.2.8 / 2008-02-20
27
+ * Add tasks for solr starting,stopping, and log tailing.
28
+ * Add monit namespace and make appservers php/merb compatible
29
+ * Make ultrasphinx symlinking a little smarter
30
+ * Add tomcat tasks for spongecell
31
+
32
+ == 0.2.6 / 2008-02-14
33
+ * Make mongrel restarts only apply to mongrel slices
34
+
35
+ == 0.2.5 / 2008-02-11
36
+ * Added db cloning task
37
+
38
+ == 0.2.4 / 2008-02-06
39
+ * Symlink memcached.yml in on deploy if you enable the callback
40
+
41
+ == 0.2.3 / 2008-02-01
42
+ * Make log tailing environmentally aware. Also add tasks to tail mongrel logs
43
+
44
+ == 0.2.2 / 2008-01-25
45
+ * sphinx:configure ultrasphinx configuration task
46
+
47
+ == 0.2.1 / 2008-01-25
48
+ * override default deploy recipe start/stop tasks
49
+
50
+ == 0.2.0 / 2008-01-23
51
+ * sphinx:symlink ultrasphinx configuration directory
52
+
53
+ == 0.1.9 / 2008-01-21
54
+ * Correct memcached tasks.
55
+
56
+ == 0.1.8 / 2008-01-20
57
+ * Add memcached tasks
58
+
59
+ == 0.1.7 / 2008-01-19
60
+ * fix symlink_configs task
61
+
62
+ == 0.1.6 / 2008-01-19
63
+ * add restart tasks for backgroundrb
64
+
65
+ == 0.1.5 / 2008-01-18
66
+ * fixed bug in filtered_remote_cache that prevented a changed checkout URL from taking over the cache
67
+
68
+ == 0.1.4 / 2008-01-17
69
+ * added sphinx:[reindex|start|stop|restart] matches only app servers with :sphinx => true
70
+
71
+ == 0.1.3 / 2008-01-17
72
+ * filtered_remote_cache to removes the cached copy of the source URL changed
73
+
74
+ == 0.1.2 / 2008-01-15
75
+ * added filtered_remote_cache capistrano deployment strategy
76
+
77
+ == 0.1.1 / 2008-01-15
78
+ * removed database tasks until problem with 'defer' is solved
79
+
80
+ == 0.1.0 / 2008-01-14
81
+ * Bugfix for empty :application variable
82
+
83
+ == 0.0.1 / 2008-01-14
84
+ * Initial release
data/Manifest.txt ADDED
@@ -0,0 +1,25 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ lib/capistrano/recipes/deploy/strategy/filtered_remote_cache.rb
6
+ lib/eycap.rb
7
+ lib/eycap/lib/ey_logger.rb
8
+ lib/eycap/lib/ey_logger_hooks.rb
9
+ lib/eycap/recipes.rb
10
+ lib/eycap/recipes/backgroundrb.rb
11
+ lib/eycap/recipes/database.rb
12
+ lib/eycap/recipes/deploy.rb
13
+ lib/eycap/recipes/ferret.rb
14
+ lib/eycap/recipes/juggernaut.rb
15
+ lib/eycap/recipes/memcached.rb
16
+ lib/eycap/recipes/mongrel.rb
17
+ lib/eycap/recipes/monit.rb
18
+ lib/eycap/recipes/nginx.rb
19
+ lib/eycap/recipes/slice.rb
20
+ lib/eycap/recipes/solr.rb
21
+ lib/eycap/recipes/sphinx.rb
22
+ lib/eycap/recipes/templates/maintenance.rhtml
23
+ lib/eycap/recipes/tomcat.rb
24
+ test/test_eycap.rb
25
+ test/test_helper.rb
data/README.txt ADDED
@@ -0,0 +1,63 @@
1
+ = eycap
2
+
3
+ == DESCRIPTION:
4
+
5
+ Engine Yard capistrano tasks for use specifically with Engine Yard slices. They include convenience methods for managed a database, mongrel, nginx or other services.
6
+
7
+ Also included is a deployment strategy, :filtered_remote_cache, which speeds up deployment like :remote_cache, but filters out .svn directory which are a security risk and write slowly to shared disks.
8
+
9
+ == REQUIREMENTS:
10
+
11
+ * capistrano (http://capify.org) > 2.0.0, but recommended with > 2.2.0
12
+
13
+ == INSTALL:
14
+
15
+ $ gem sources -a http://gems.github.com/ (you only need to do this once)
16
+ $ gem install engineyard-eycap
17
+
18
+ == SOURCE:
19
+
20
+ eycaps git repo is available on GitHub, which can be browsed at:
21
+
22
+ http://github.com/engineyard/eycap
23
+
24
+ and cloned from:
25
+
26
+ git://github.com/engineyard/eycap.git
27
+
28
+ == USAGE:
29
+
30
+ = Include in capistrano
31
+
32
+ In your deploy.rb, simply include this line at the top:
33
+
34
+ require 'eycap/recipes'
35
+
36
+ = Filtered remote cache
37
+
38
+ To use filtered_remote_cache, simply:
39
+
40
+ set :deploy_via, :filtered_remote_cache
41
+
42
+ == LICENSE:
43
+
44
+ Copyright (c) 2008 Engine Yard
45
+
46
+ Permission is hereby granted, free of charge, to any person obtaining
47
+ a copy of this software and associated documentation files (the
48
+ "Software"), to deal in the Software without restriction, including
49
+ without limitation the rights to use, copy, modify, merge, publish,
50
+ distribute, sublicense, and/or sell copies of the Software, and to
51
+ permit persons to whom the Software is furnished to do so, subject to
52
+ the following conditions:
53
+
54
+ The above copyright notice and this permission notice shall be
55
+ included in all copies or substantial portions of the Software.
56
+
57
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
58
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
59
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
60
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
61
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
62
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
63
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'rubygems'
2
+ require 'hoe'
3
+ require './lib/eycap'
4
+
5
+ Hoe.new('eycap', Eycap::VERSION) do |p|
6
+ p.author = 'Engine Yard'
7
+ p.email = 'tech@engineyard.com'
8
+ p.summary = 'Capistrano tasks for Engine Yard slices'
9
+ p.description = 'A bunch of useful recipes to help deployment to Engine Yard slices'
10
+ p.url = 'http://eycap.rubyforge.org'
11
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
12
+ p.extra_deps << ['capistrano', '>= 2.2.0']
13
+ end
14
+
15
+ desc "Open an irb session preloaded with this library"
16
+ task :console do
17
+ sh "irb -rubygems -r ./lib/eycap.rb"
18
+ end
19
+
20
+ task :coverage do
21
+ system("rm -fr coverage")
22
+ system("rcov test/test_*.rb")
23
+ system("open coverage/index.html")
24
+ end
25
+
26
+ desc "Upload site to Rubyforge"
27
+ task :site do
28
+ end
29
+
30
+ desc 'Install the package as a gem.'
31
+ task :install_gem_no_doc => [:clean, :package] do
32
+ sh "#{'sudo ' unless Hoe::WINDOZE}gem install --local --no-rdoc --no-ri pkg/*.gem"
33
+ end
@@ -0,0 +1,48 @@
1
+ require 'capistrano/recipes/deploy/strategy/remote'
2
+
3
+ module Capistrano
4
+ module Deploy
5
+ module Strategy
6
+
7
+ # Implements the deployment strategy that keeps a cached checkout of
8
+ # the source code on each remote server. Each deploy simply updates the
9
+ # cached checkout, and then filters a copy through tar to remove unwanted .svn directories,
10
+ # finally leaving a pristeen, export-like copy at the destination.
11
+ class FilteredRemoteCache < Remote
12
+ # Executes the SCM command for this strategy and writes the REVISION
13
+ # mark file to each host.
14
+ def deploy!
15
+ update_repository_cache
16
+ tar_copy_repository_cache
17
+ end
18
+
19
+ def check!
20
+ super.check do |d|
21
+ d.remote.writable(shared_path)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def repository_cache
28
+ configuration[:repository_cache] || "/var/cache/engineyard/#{configuration[:application]}"
29
+ end
30
+
31
+ def update_repository_cache
32
+ logger.trace "checking if the cached copy URL matches this deploy, then updating it"
33
+ command = "if [ -d #{repository_cache} ] && ! [ `svn info #{repository_cache} | grep URL | awk '{print $2}'` = '#{configuration[:repository]}' ]; then " +
34
+ "rm -rf #{repository_cache} && #{source.checkout(revision, repository_cache)}; " +
35
+ "elif [ -d #{repository_cache} ]; then #{source.sync(revision, repository_cache)}; " +
36
+ "else #{source.checkout(revision, repository_cache)}; fi"
37
+ scm_run(command)
38
+ end
39
+
40
+ def tar_copy_repository_cache
41
+ logger.trace "copying and filtering .svn via tar from cached version to #{configuration[:release_path]}"
42
+ run "mkdir #{configuration[:release_path]} && tar c --exclude=#{configuration[:filter_spec] || ".svn"} -C #{repository_cache} . | tar xC #{configuration[:release_path]} && #{mark}"
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,124 @@
1
+ require 'tmpdir'
2
+ module Capistrano
3
+
4
+ class Logger
5
+
6
+ def ey_log(level, message, line_prefix = nil)
7
+ EYLogger.log(level, message, line_prefix) if EYLogger.setup?
8
+ log_without_ey_logging(level, message, line_prefix)
9
+ end
10
+
11
+ unless method_defined?(:log_without_ey_logging)
12
+ alias_method :log_without_ey_logging, :log
13
+ alias_method :log, :ey_log
14
+ end
15
+
16
+ def close
17
+ device.close if @needs_close
18
+ EYLogger.close if EYLogger.setup?
19
+ end
20
+ end
21
+
22
+ class EYLogger
23
+
24
+ # Sets up the EYLogger to beging capturing capistrano's logging. You should pass the capistrno configuration
25
+ # and the deploy type as a string. The deploy type is for reporting purposes only but must be included.
26
+ def self.setup(configuration, deploy_type, options = {})
27
+ @_configuration = configuration
28
+ @_deploy_type = deploy_type.gsub(/:/, "_")
29
+ @_log_path = options[:deploy_log_path] || Dir.tmpdir
30
+ @_log_path << "/" unless @_log_path =~ /\/$/
31
+ FileUtils.mkdir_p(@_log_path)
32
+ @_setup = true
33
+ @_success = true
34
+ end
35
+
36
+ def self.log(level, message, line_prefix=nil)
37
+ return nil unless setup?
38
+ @release_name = @_configuration[:release_name] if @release_name.nil?
39
+ @_log_file_path = @_log_path + @release_name + ".log" unless @_log_file_path
40
+ @_deploy_log_file = File.open(@_log_file_path, "w") if @_deploy_log_file.nil?
41
+
42
+ indent = "%*s" % [Logger::MAX_LEVEL, "*" * (Logger::MAX_LEVEL - level)]
43
+ message.each do |line|
44
+ if line_prefix
45
+ @_deploy_log_file << "#{indent} [#{line_prefix}] #{line.strip}\n"
46
+ else
47
+ @_deploy_log_file << "#{indent} #{line.strip}\n"
48
+ end
49
+ end
50
+ end
51
+
52
+ def self.post_process
53
+ unless ::Interrupt === $!
54
+ puts "\n\nPlease wait while the log file is processed\n"
55
+ # Should dump the stack trace of an exception if there is one
56
+ error = $!
57
+ unless error.nil?
58
+ @_deploy_log_file << error.message << "\n"
59
+ @_deploy_log_file << error.backtrace.join("\n")
60
+ @_success = false
61
+ end
62
+ self.close
63
+
64
+ hooks = [:any]
65
+ hooks << self.successful? ? :success : :failure
66
+ puts "Executing Post Processing Hooks"
67
+ hooks.each do |h|
68
+ @_post_process_hooks[h].each do |key|
69
+ @_configuration.parent.find_and_execute_task(key)
70
+ end
71
+ end
72
+ puts "Finished Post Processing Hooks"
73
+ end
74
+ end
75
+
76
+ # Adds a post processing hook.
77
+ #
78
+ # Provide a task name to execute. These tasks are executed after capistrano has actually run its course.
79
+ #
80
+ # Takes a key to control when the hook is executed.'
81
+ # :any - always executed
82
+ # :success - only execute on success
83
+ # :failure - only execute on failure
84
+ #
85
+ # ==== Example
86
+ # Capistrano::EYLogger.post_process_hook( "ey_logger:upload_log_to_slice", :any)
87
+ #
88
+ def self.post_process_hook(task, key = :any)
89
+ @_post_process_hooks ||= Hash.new{|h,k| h[k] = []}
90
+ @_post_process_hooks[key] << task
91
+ end
92
+
93
+ def self.setup?
94
+ !!@_setup
95
+ end
96
+
97
+ def self.deploy_type
98
+ @_deploy_type
99
+ end
100
+
101
+ def self.successful?
102
+ !!@_success
103
+ end
104
+
105
+ def self.failure?
106
+ !@_success
107
+ end
108
+
109
+ def self.log_file_path
110
+ @_log_file_path
111
+ end
112
+
113
+ def self.remote_log_file_name
114
+ @_log_file_name ||= "#{@_configuration[:release_name]}-#{@_deploy_type}-#{self.successful? ? "SUCCESS" : "FAILURE"}.log"
115
+ end
116
+
117
+ def self.close
118
+ @_deploy_log_file.flush unless @_deploy_log_file.nil?
119
+ @_deploy_log_file.close unless @_deploy_log_file.nil?
120
+ @_setup = false
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,14 @@
1
+ require File.join(File.dirname(__FILE__), "ey_logger")
2
+
3
+ # These tasks are setup to use with the logger as post commit hooks.
4
+ Capistrano::Configuration.instance(:must_exist).load do
5
+ namespace :ey_logger do
6
+ task :upload_log_to_slice, :except => { :no_release => true} do
7
+ logger = Capistrano::EYLogger
8
+ run "mkdir -p #{shared_path}/deploy_logs"
9
+ put File.open(logger.log_file_path).read, "#{shared_path}/deploy_logs/#{logger.remote_log_file_name}"
10
+ end
11
+ end
12
+ end
13
+
14
+ Capistrano::EYLogger.post_process_hook("ey_logger:upload_log_to_slice")
@@ -0,0 +1,23 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :bdrb do
4
+ desc "After update_code you want to reindex"
5
+ task :reindex, :roles => :app, :only => {:backgroundrb => true} do
6
+ run "/engineyard/bin/searchd #{application} reindex"
7
+ end
8
+
9
+ desc "Start Backgroundrb"
10
+ task :start, :roles => :app, :only => {:backgroundrb => true} do
11
+ sudo "/usr/bin/monit start all -g backgroundrb_#{application}"
12
+ end
13
+ desc "Stop Backgroundrb"
14
+ task :stop, :roles => :app, :only => {:backgroundrb => true} do
15
+ sudo "/usr/bin/monit stop all -g backgroundrb_#{application}"
16
+ end
17
+ desc "Restart Backgroundrb"
18
+ task :restart, :roles => :app, :only => {:backgroundrb => true} do
19
+ sudo "/usr/bin/monit restart all -g backgroundrb_#{application}"
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,37 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :db do
4
+ task :backup_name, :only => { :primary => true } do
5
+ now = Time.now
6
+ run "mkdir -p #{shared_path}/db_backups"
7
+ backup_time = [now.year,now.month,now.day,now.hour,now.min,now.sec].join('-')
8
+ set :backup_file, "#{shared_path}/db_backups/#{environment_database}-snapshot-#{backup_time}.sql"
9
+ end
10
+
11
+ desc "Clone Production Database to Staging Database."
12
+ task :clone_prod_to_staging, :roles => :db, :only => { :primary => true } do
13
+ backup_name
14
+ on_rollback { run "rm -f #{backup_file}" }
15
+ run "mysqldump --add-drop-table -u #{dbuser} -h #{production_dbhost}-replica -p#{dbpass} #{production_database} > #{backup_file}"
16
+ run "mysql -u #{dbuser} -p#{dbpass} -h #{staging_dbhost} #{staging_database} < #{backup_file}"
17
+ run "rm -f #{backup_file}"
18
+ end
19
+
20
+ desc "Backup your database to shared_path+/db_backups"
21
+ task :dump, :roles => :db, :only => {:primary => true} do
22
+ backup_name
23
+ run "mysqldump --add-drop-table -u #{dbuser} -h #{environment_dbhost}-replica -p#{dbpass} #{environment_database} | bzip2 -c > #{backup_file}.bz2"
24
+ end
25
+
26
+ desc "Sync your production database to your local workstation"
27
+ task :clone_to_local, :roles => :db, :only => {:primary => true} do
28
+ backup_name
29
+ dump
30
+ get "#{backup_file}.bz2", "/tmp/#{application}.sql.gz"
31
+ development_info = YAML.load_file("config/database.yml")['development']
32
+ run_str = "bzcat /tmp/#{application}.sql.gz | mysql -u #{development_info['username']} -p#{development_info['password']} -h #{development_info['host']} #{development_info['database']}"
33
+ %x!#{run_str}!
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,90 @@
1
+ require File.join(File.dirname(__FILE__), "..", "lib", "ey_logger.rb")
2
+ Capistrano::Configuration.instance(:must_exist).load do
3
+
4
+ namespace :deploy do
5
+ # This is here to hook into the logger for deploy and deploy:long tasks
6
+ ["deploy", "deploy:long"].each do |tsk|
7
+ before(tsk) do
8
+ Capistrano::EYLogger.setup( self, tsk )
9
+ at_exit{ Capistrano::EYLogger.post_process if Capistrano::EYLogger.setup? }
10
+ end
11
+ end
12
+
13
+ desc "Link the database.yml and mongrel_cluster.yml files into the current release path."
14
+ task :symlink_configs, :roles => :app, :except => {:no_release => true} do
15
+ run <<-CMD
16
+ cd #{release_path} &&
17
+ ln -nfs #{shared_path}/config/database.yml #{release_path}/config/database.yml &&
18
+ ln -nfs #{shared_path}/config/mongrel_cluster.yml #{release_path}/config/mongrel_cluster.yml
19
+ CMD
20
+ end
21
+
22
+ desc "Display the maintenance.html page while deploying with migrations. Then it restarts and enables the site again."
23
+ task :long do
24
+ transaction do
25
+ update_code
26
+ web.disable
27
+ symlink
28
+ migrate
29
+ end
30
+
31
+ restart
32
+ web.enable
33
+ end
34
+
35
+ desc "Restart the Mongrel processes on the app slices."
36
+ task :restart, :roles => :app do
37
+ mongrel.restart
38
+ end
39
+
40
+ desc "Start the Mongrel processes on the app slices."
41
+ task :spinner, :roles => :app do
42
+ mongrel.start
43
+ end
44
+
45
+ desc "Start the Mongrel processes on the app slices."
46
+ task :start, :roles => :app do
47
+ mongrel.start
48
+ end
49
+
50
+ desc "Stop the Mongrel processes on the app slices."
51
+ task :stop, :roles => :app do
52
+ mongrel.stop
53
+ end
54
+
55
+ namespace :web do
56
+ desc <<-DESC
57
+ Present a maintenance page to visitors. Disables your application's web \
58
+ interface by writing a "maintenance.html" file to each web server. The \
59
+ servers must be configured to detect the presence of this file, and if \
60
+ it is present, always display it instead of performing the request.
61
+
62
+ By default, the maintenance page will just say the site is down for \
63
+ "maintenance", and will be back "shortly", but you can customize the \
64
+ page by specifying the REASON and UNTIL environment variables:
65
+
66
+ $ cap deploy:web:disable \\
67
+ REASON="hardware upgrade" \\
68
+ UNTIL="12pm Central Time"
69
+
70
+ Further customization copy your html file to shared_path+'/system/maintenance.html.custom'.
71
+ If this file exists it will be used instead of the default capistrano ugly page
72
+ DESC
73
+ task :disable, :roles => :web, :except => { :no_release => true } do
74
+ maint_file = "#{shared_path}/system/maintenance.html"
75
+ require 'erb'
76
+ on_rollback { run "rm #{shared_path}/system/maintenance.html" }
77
+
78
+ reason = ENV['REASON']
79
+ deadline = ENV['UNTIL']
80
+
81
+ template = File.read(File.join(File.dirname(__FILE__), "templates", "maintenance.rhtml"))
82
+ result = ERB.new(template).result(binding)
83
+
84
+ put result, "#{shared_path}/system/maintenance.html.tmp", :mode => 0644
85
+ run "if [ -f #{shared_path}/system/maintenance.html.custom ]; then cp #{shared_path}/system/maintenance.html.custom #{maint_file}; else cp #{shared_path}/system/maintenance.html.tmp #{maint_file}; fi"
86
+ end
87
+ end
88
+ end
89
+
90
+ end
@@ -0,0 +1,20 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :ferret do
4
+ desc "After update_code you want to symlink the index and ferret_server.yml file into place"
5
+ task :symlink_configs, :roles => :app, :except => {:no_release => true} do
6
+ run <<-CMD
7
+ cd #{release_path} &&
8
+ ln -nfs #{shared_path}/config/ferret_server.yml #{release_path}/config/ferret_server.yml &&
9
+ if [ -d #{release_path}/index ]; then mv #{release_path}/index #{release_path}/index.bak; fi &&
10
+ ln -nfs #{shared_path}/index #{release_path}/index
11
+ CMD
12
+ end
13
+ [:start,:stop,:restart].each do |op|
14
+ desc "#{op} ferret server"
15
+ task op, :roles => :app, :except => {:no_release => true} do
16
+ sudo "/usr/bin/monit #{op} all -g ferret_#{application}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,18 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :juggernaut do
4
+ desc "After update_code you want to symlink the juggernaut.yml file into place"
5
+ task :symlink_configs, :roles => :app, :except => {:no_release => true} do
6
+ run <<-CMD
7
+ cd #{release_path} &&
8
+ ln -nfs #{shared_path}/config/juggernaut.yml #{release_path}/config/juggernaut.yml
9
+ CMD
10
+ end
11
+ [:start,:stop,:restart].each do |op|
12
+ desc "#{op} juggernaut server"
13
+ task op, :roles => :app, :except => {:no_release => true} do
14
+ sudo "/usr/bin/monit #{op} all -g juggernaut_#{application}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,20 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :memcached do
3
+ desc "Start memcached"
4
+ task :start, :roles => :app, :only => {:memcached => true} do
5
+ sudo "/etc/init.d/memcached start"
6
+ end
7
+ desc "Stop memcached"
8
+ task :stop, :roles => :app, :only => {:memcached => true} do
9
+ sudo "/etc/init.d/memcached stop"
10
+ end
11
+ desc "Restart memcached"
12
+ task :restart, :roles => :app, :only => {:memcached => true} do
13
+ sudo "/etc/init.d/memcached restart"
14
+ end
15
+ desc "Symlink the memcached.yml file into place if it exists"
16
+ task :symlink_configs, :roles => :app, :only => {:memcached => true }, :except => { :no_release => true } do
17
+ run "if [ -f #{shared_path}/config/memcached.yml ]; then ln -nfs #{shared_path}/config/memcached.yml #{release_path}/config/memcached.yml; fi"
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :mongrel do
3
+ desc <<-DESC
4
+ Start Mongrel processes on the app server. This uses the :use_sudo variable to determine whether to use sudo or not. By default, :use_sudo is
5
+ set to true.
6
+ DESC
7
+ task :start, :roles => :app do
8
+ sudo "/usr/bin/monit start all -g #{monit_group}"
9
+ end
10
+
11
+ desc <<-DESC
12
+ Restart the Mongrel processes on the app server by starting and stopping the cluster. This uses the :use_sudo
13
+ variable to determine whether to use sudo or not. By default, :use_sudo is set to true.
14
+ DESC
15
+ task :restart, :roles => :app do
16
+ sudo "/usr/bin/monit restart all -g #{monit_group}"
17
+ end
18
+
19
+ desc <<-DESC
20
+ Stop the Mongrel processes on the app server. This uses the :use_sudo
21
+ variable to determine whether to use sudo or not. By default, :use_sudo is
22
+ set to true.
23
+ DESC
24
+ task :stop, :roles => :app do
25
+ sudo "/usr/bin/monit stop all -g #{monit_group}"
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,17 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :monit do
4
+ desc "Get the status of your mongrels"
5
+ task :status, :roles => :app do
6
+ @monit_output ||= { }
7
+ sudo "/usr/bin/monit status" do |channel, stream, data|
8
+ @monit_output[channel[:server].to_s] ||= [ ]
9
+ @monit_output[channel[:server].to_s].push(data.chomp)
10
+ end
11
+ @monit_output.each do |k,v|
12
+ puts "#{k} -> #{'*'*55}"
13
+ puts v.join("\n")
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :nginx do
4
+ desc "Start Nginx on the app slices."
5
+ task :start, :roles => :app do
6
+ sudo "/etc/init.d/nginx start"
7
+ end
8
+
9
+ desc "Restart the Nginx processes on the app slices."
10
+ task :restart , :roles => :app do
11
+ sudo "/etc/init.d/nginx restart"
12
+ end
13
+
14
+ desc "Stop the Nginx processes on the app slices."
15
+ task :stop , :roles => :app do
16
+ sudo "/etc/init.d/nginx stop"
17
+ end
18
+
19
+ desc "Tail the nginx access logs for this application"
20
+ task :tail, :roles => :app do
21
+ run "tail -f /var/log/engineyard/nginx/#{application}.access.log" do |channel, stream, data|
22
+ puts "#{channel[:server]}: #{data}" unless data =~ /^10\.[01]\.0/ # skips lb pull pages
23
+ break if stream == :err
24
+ end
25
+ end
26
+
27
+ desc "Tail the nginx error logs on the app slices"
28
+ task :tail_error, :roles => :app do
29
+ run "tail -f /var/log/engineyard/nginx/error.log" do |channel, stream, data|
30
+ puts "#{channel[:server]}: #{data}" unless data =~ /^10\.[01]\.0/ # skips lb pull pages
31
+ break if stream == :err
32
+ end
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,21 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :slice do
4
+ desc "Tail the Rails production log for this environment"
5
+ task :tail_production_logs, :roles => :app do
6
+ run "tail -f #{shared_path}/log/#{rails_env}.log" do |channel, stream, data|
7
+ puts # for an extra line break before the host name
8
+ puts "#{channel[:server]} -> #{data}"
9
+ break if stream == :err
10
+ end
11
+ end
12
+ desc "Tail the Mongrel logs this environment"
13
+ task :tail_mongrel_logs, :roles => :app do
14
+ run "tail -f #{shared_path}/log/mongrel*.log" do |channel, stream, data|
15
+ puts # for an extra line break before the host name
16
+ puts "#{channel[:server]} -> #{data}"
17
+ break if stream == :err
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,37 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :solr do
4
+ desc "After update_code you want to symlink the index and ferret_server.yml file into place"
5
+ task :symlink_configs, :roles => :app, :except => {:no_release => true} do
6
+ run <<-CMD
7
+ cd #{release_path} && ln -nfs #{shared_path}/config/solr.yml #{release_path}/config/solr.yml
8
+ CMD
9
+ end
10
+
11
+ [:start,:stop,:restart].each do |op|
12
+ desc "#{op} ferret server"
13
+ task op, :roles => :app, :only => {:solr => true} do
14
+ sudo "/usr/bin/monit #{op} all -g solr_#{application}"
15
+ end
16
+ end
17
+
18
+ namespace :tail do
19
+ desc "Tail the Solr logs this environment"
20
+ task :logs, :roles => :app, :only => {:solr => true} do
21
+ run "tail -f /var/log/engineyard/solr/#{application}.log" do |channel, stream, data|
22
+ puts # for an extra line break before the host name
23
+ puts "#{channel[:server]} -> #{data}"
24
+ break if stream == :err
25
+ end
26
+ end
27
+ desc "Tail the Solr error logs this environment"
28
+ task :errors, :roles => :app, :only => {:solr => true} do
29
+ run "tail -f /var/log/engineyard/solr/#{application}.err.log" do |channel, stream, data|
30
+ puts # for an extra line break before the host name
31
+ puts "#{channel[:server]} -> #{data}"
32
+ break if stream == :err
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,34 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ namespace :sphinx do
4
+ desc "After update_code you want to configure, then reindex"
5
+ task :configure, :roles => :app, :only => {:sphinx => true}, :except => {:no_release => true} do
6
+ run "/engineyard/bin/searchd #{application} configure"
7
+ end
8
+
9
+ desc "After configure you want to reindex"
10
+ task :reindex, :roles => :app, :only => {:sphinx => true} do
11
+ run "/engineyard/bin/searchd #{application} reindex"
12
+ end
13
+
14
+ desc "Start Sphinx Searchd"
15
+ task :start, :roles => :app, :only => {:sphinx => true} do
16
+ sudo "/usr/bin/monit start all -g sphinx_#{application}"
17
+ end
18
+ desc "Stop Sphinx Searchd"
19
+ task :stop, :roles => :app, :only => {:sphinx => true} do
20
+ sudo "/usr/bin/monit stop all -g sphinx_#{application}"
21
+ end
22
+ desc "Restart Sphinx Searchd"
23
+ task :restart, :roles => :app, :only => {:sphinx => true} do
24
+ sudo "/usr/bin/monit restart all -g sphinx_#{application}"
25
+ end
26
+
27
+ desc "Symlink the sphinx config file"
28
+ task :symlink, :roles => :app, :only => {:sphinx => true}, :except => {:no_release => true} do
29
+ run "if [ -d #{release_path}/config/ultrasphinx ]; then mv #{release_path}/config/ultrasphinx #{release_path}/config/ultrasphinx.bak; fi"
30
+ run "ln -nfs #{shared_path}/config/ultrasphinx #{release_path}/config/ultrasphinx"
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,53 @@
1
+
2
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
3
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
4
+
5
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
6
+
7
+ <head>
8
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
9
+ <title>System down for maintenance</title>
10
+
11
+ <style type="text/css">
12
+ div.outer {
13
+ position: absolute;
14
+ left: 50%;
15
+ top: 50%;
16
+ width: 500px;
17
+ height: 300px;
18
+ margin-left: -260px;
19
+ margin-top: -150px;
20
+ }
21
+
22
+ .DialogBody {
23
+ margin: 0;
24
+ padding: 10px;
25
+ text-align: left;
26
+ border: 1px solid #ccc;
27
+ border-right: 1px solid #999;
28
+ border-bottom: 1px solid #999;
29
+ background-color: #fff;
30
+ }
31
+
32
+ body { background-color: #fff; }
33
+ </style>
34
+ </head>
35
+
36
+ <body>
37
+
38
+ <div class="outer">
39
+ <div class="DialogBody" style="text-align: center;">
40
+ <div style="text-align: center; width: 200px; margin: 0 auto;">
41
+ <p style="color: red; font-size: 16px; line-height: 20px;">
42
+ The system is down for <%= reason ? reason : "maintenance" %>
43
+ as of <%= Time.now.strftime("%H:%M %Z") %>.
44
+ </p>
45
+ <p style="color: #666;">
46
+ It'll be back <%= deadline ? deadline : "shortly" %>.
47
+ </p>
48
+ </div>
49
+ </div>
50
+ </div>
51
+
52
+ </body>
53
+ </html>
@@ -0,0 +1,16 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+ namespace :tomcat do
3
+ desc "Start tomcat"
4
+ task :start, :roles => :app, :only => {:tomcat => true} do
5
+ sudo "/etc/init.d/tomcat start"
6
+ end
7
+ desc "Stop tomcat"
8
+ task :stop, :roles => :app, :only => {:tomcat => true} do
9
+ sudo "/etc/init.d/tomcat stop"
10
+ end
11
+ desc "Restart tomcat"
12
+ task :restart, :roles => :app, :only => {:tomcat => true} do
13
+ sudo "/etc/init.d/tomcat restart"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ require 'eycap/lib/ey_logger'
2
+ require 'eycap/lib/ey_logger_hooks'
3
+ require 'eycap/recipes/database'
4
+ require 'eycap/recipes/ferret'
5
+ require 'eycap/recipes/mongrel'
6
+ require 'eycap/recipes/nginx'
7
+ require 'eycap/recipes/slice'
8
+ require 'eycap/recipes/deploy'
9
+ require 'eycap/recipes/sphinx'
10
+ require 'eycap/recipes/backgroundrb'
11
+ require 'eycap/recipes/memcached'
12
+ require 'eycap/recipes/solr'
13
+ require 'eycap/recipes/monit'
14
+ require 'eycap/recipes/tomcat'
15
+ require 'eycap/recipes/juggernaut'
16
+
17
+ Capistrano::Configuration.instance(:must_exist).load do
18
+
19
+ default_run_options[:pty] = true if respond_to?(:default_run_options)
20
+ set :keep_releases, 3
21
+ set :runner, defer { user }
22
+
23
+ end
data/lib/eycap.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Eycap
2
+ VERSION = '0.3.3'
3
+ end
@@ -0,0 +1,11 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestEycap < Test::Unit::TestCase
4
+
5
+ def setup
6
+ end
7
+
8
+ def test_truth
9
+ assert true
10
+ end
11
+ end
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../lib/eycap'
metadata ADDED
@@ -0,0 +1,98 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: engineyard-eycap
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.3
5
+ platform: ruby
6
+ authors:
7
+ - Engine Yard
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-05-12 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: capistrano
17
+ version_requirement:
18
+ version_requirements: !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.2.0
23
+ version:
24
+ - !ruby/object:Gem::Dependency
25
+ name: hoe
26
+ version_requirement:
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - ">="
30
+ - !ruby/object:Gem::Version
31
+ version: 1.5.1
32
+ version:
33
+ description: A bunch of useful recipes to help deployment to Engine Yard slices
34
+ email: tech@engineyard.com
35
+ executables: []
36
+
37
+ extensions: []
38
+
39
+ extra_rdoc_files:
40
+ - History.txt
41
+ - Manifest.txt
42
+ - README.txt
43
+ files:
44
+ - History.txt
45
+ - Manifest.txt
46
+ - README.txt
47
+ - Rakefile
48
+ - lib/capistrano/recipes/deploy/strategy/filtered_remote_cache.rb
49
+ - lib/eycap.rb
50
+ - lib/eycap/lib/ey_logger.rb
51
+ - lib/eycap/lib/ey_logger_hooks.rb
52
+ - lib/eycap/recipes.rb
53
+ - lib/eycap/recipes/backgroundrb.rb
54
+ - lib/eycap/recipes/database.rb
55
+ - lib/eycap/recipes/deploy.rb
56
+ - lib/eycap/recipes/ferret.rb
57
+ - lib/eycap/recipes/juggernaut.rb
58
+ - lib/eycap/recipes/memcached.rb
59
+ - lib/eycap/recipes/mongrel.rb
60
+ - lib/eycap/recipes/monit.rb
61
+ - lib/eycap/recipes/nginx.rb
62
+ - lib/eycap/recipes/slice.rb
63
+ - lib/eycap/recipes/solr.rb
64
+ - lib/eycap/recipes/sphinx.rb
65
+ - lib/eycap/recipes/templates/maintenance.rhtml
66
+ - lib/eycap/recipes/tomcat.rb
67
+ - test/test_eycap.rb
68
+ - test/test_helper.rb
69
+ has_rdoc: true
70
+ homepage: http://eycap.rubyforge.org
71
+ post_install_message:
72
+ rdoc_options:
73
+ - --main
74
+ - README.txt
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ version: "0"
82
+ version:
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: "0"
88
+ version:
89
+ requirements: []
90
+
91
+ rubyforge_project: eycap
92
+ rubygems_version: 1.0.1
93
+ signing_key:
94
+ specification_version: 2
95
+ summary: Capistrano tasks for Engine Yard slices
96
+ test_files:
97
+ - test/test_eycap.rb
98
+ - test/test_helper.rb