ey-deploy 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/lib/ey-deploy.rb +4 -0
  2. data/lib/ey-deploy/cli.rb +27 -16
  3. data/lib/ey-deploy/deploy.rb +13 -13
  4. data/lib/ey-deploy/deploy_hook.rb +13 -6
  5. data/lib/ey-deploy/logged_output.rb +58 -0
  6. data/lib/ey-deploy/server.rb +5 -5
  7. data/lib/ey-deploy/strategies/git.rb +5 -5
  8. data/lib/ey-deploy/task.rb +6 -12
  9. data/lib/ey-deploy/version.rb +1 -1
  10. data/lib/vendor/dataflow/HISTORY +52 -0
  11. data/lib/vendor/dataflow/LICENSE +19 -0
  12. data/lib/vendor/dataflow/README.textile +290 -0
  13. data/lib/vendor/dataflow/Rakefile +36 -0
  14. data/lib/vendor/dataflow/dataflow.rb +120 -0
  15. data/lib/vendor/dataflow/dataflow/actor.rb +22 -0
  16. data/lib/vendor/dataflow/dataflow/equality.rb +28 -0
  17. data/lib/vendor/dataflow/dataflow/future_queue.rb +24 -0
  18. data/lib/vendor/dataflow/dataflow/port.rb +54 -0
  19. data/lib/vendor/dataflow/examples/barrier.rb +9 -0
  20. data/lib/vendor/dataflow/examples/data_driven.rb +17 -0
  21. data/lib/vendor/dataflow/examples/dataflow_http_gets.rb +13 -0
  22. data/lib/vendor/dataflow/examples/flow.rb +20 -0
  23. data/lib/vendor/dataflow/examples/future_http_gets.rb +12 -0
  24. data/lib/vendor/dataflow/examples/future_queue.rb +11 -0
  25. data/lib/vendor/dataflow/examples/instance_variables.rb +15 -0
  26. data/lib/vendor/dataflow/examples/laziness.rb +9 -0
  27. data/lib/vendor/dataflow/examples/local_variables.rb +11 -0
  28. data/lib/vendor/dataflow/examples/messages.rb +26 -0
  29. data/lib/vendor/dataflow/examples/port_http_gets.rb +13 -0
  30. data/lib/vendor/dataflow/examples/port_send.rb +10 -0
  31. data/lib/vendor/dataflow/examples/ring.rb +21 -0
  32. data/lib/vendor/dataflow/spec/actor_spec.rb +28 -0
  33. data/lib/vendor/dataflow/spec/anonymous_variables_spec.rb +21 -0
  34. data/lib/vendor/dataflow/spec/barrier_spec.rb +25 -0
  35. data/lib/vendor/dataflow/spec/by_need_spec.rb +55 -0
  36. data/lib/vendor/dataflow/spec/dataflow_spec.rb +151 -0
  37. data/lib/vendor/dataflow/spec/equality_spec.rb +40 -0
  38. data/lib/vendor/dataflow/spec/flow_spec.rb +25 -0
  39. data/lib/vendor/dataflow/spec/forker_spec.rb +28 -0
  40. data/lib/vendor/dataflow/spec/future_queue_spec.rb +31 -0
  41. data/lib/vendor/dataflow/spec/inspect_spec.rb +19 -0
  42. data/lib/vendor/dataflow/spec/need_later_spec.rb +12 -0
  43. data/lib/vendor/dataflow/spec/port_spec.rb +26 -0
  44. data/lib/vendor/dataflow/spec/spec.opts +1 -0
  45. data/lib/vendor/dataflow/spec/spec_helper.rb +10 -0
  46. data/lib/vendor/open4/lib/open4.rb +403 -0
  47. data/spec/deploy_hook_spec.rb +16 -2
  48. data/spec/fixtures/invalid_hook.rb +1 -0
  49. data/spec/fixtures/valid_hook.rb +1 -0
  50. metadata +43 -4
  51. data/lib/ey-deploy/verbose_system.rb +0 -12
@@ -1,7 +1,11 @@
1
1
  require 'escape'
2
2
 
3
3
  $LOAD_PATH.push(File.expand_path("ey-deploy", File.dirname(__FILE__)))
4
+ $LOAD_PATH.unshift File.expand_path('vendor/thor/lib', File.dirname(__FILE__))
5
+ $LOAD_PATH.unshift File.expand_path('vendor/open4/lib', File.dirname(__FILE__))
6
+ $LOAD_PATH.unshift File.expand_path('vendor/dataflow', File.dirname(__FILE__))
4
7
 
8
+ require 'dataflow'
5
9
  require 'version'
6
10
  require 'strategies/git'
7
11
  require 'task'
@@ -1,9 +1,9 @@
1
- $:.unshift File.expand_path('../vendor/thor/lib', File.dirname(__FILE__))
2
-
3
1
  require 'thor'
4
2
 
5
3
  module EY
6
4
  class CLI < Thor
5
+ include Dataflow
6
+
7
7
  def self.start(*)
8
8
  super
9
9
  rescue RemoteFailure
@@ -36,9 +36,17 @@ module EY
36
36
  method_option :instances, :type => :array,
37
37
  :desc => "Instances in cluster"
38
38
 
39
+ method_option :verbose, :type => :boolean,
40
+ :default => false,
41
+ :desc => "Verbose output",
42
+ :aliases => ["-v"]
43
+
39
44
  desc "deploy", "Deploy code from /data/<app>"
40
45
  def deploy(default_task=:deploy)
41
46
  EY::Server.all = parse_instances(options[:instances])
47
+ EY::LoggedOutput.verbose = options[:verbose]
48
+ EY::LoggedOutput.logfile = File.join(ENV['HOME'], "#{options[:app]}-deploy.log")
49
+
42
50
  invoke :propagate
43
51
  EY::Deploy.run(options.merge("default_task" => default_task))
44
52
  end
@@ -88,25 +96,28 @@ module EY
88
96
 
89
97
  EY::Server.config = config
90
98
 
91
- EY::Server.all.find_all do |server|
99
+ barrier(*(EY::Server.all.find_all do |server|
92
100
  !server.local? # of course this machine has it
93
- end.find_all do |server|
94
- egrep_escaped_version = VERSION.gsub(/\./, '\.')
95
- # the [,)] is to stop us from looking for e.g. 0.5.1, seeing
96
- # 0.5.11, and mistakenly thinking 0.5.1 is there
97
- has_gem_cmd = "#{gem_binary} list ey-deploy | grep \"ey-deploy \" | egrep -q '#{egrep_escaped_version}[,)]'"
98
- !server.run(has_gem_cmd) # doesn't have this exact version
99
- end.each do |server|
100
- puts "~> Installing ey-deploy on #{server.hostname}"
101
-
102
- system(Escape.shell_command([
101
+ end.map do |server|
102
+ need_later do
103
+ egrep_escaped_version = VERSION.gsub(/\./, '\.')
104
+ # the [,)] is to stop us from looking for e.g. 0.5.1, seeing
105
+ # 0.5.11, and mistakenly thinking 0.5.1 is there
106
+ has_gem_cmd = "#{gem_binary} list ey-deploy | grep \"ey-deploy \" | egrep -q '#{egrep_escaped_version}[,)]'"
107
+
108
+ if !server.run(has_gem_cmd) # doesn't have this exact version
109
+ puts "~> Installing ey-deploy on #{server.hostname}"
110
+
111
+ system(Escape.shell_command([
103
112
  'scp', '-i', "#{ENV['HOME']}/.ssh/internal",
104
113
  "-o", "StrictHostKeyChecking=no",
105
114
  local_gem_file,
106
- "#{config.user}@#{server.hostname}:#{remote_gem_file}",
115
+ "#{config.user}@#{server.hostname}:#{remote_gem_file}",
107
116
  ]))
108
- server.run("sudo #{gem_binary} install --no-rdoc --no-ri '#{remote_gem_file}'")
109
- end
117
+ server.run("sudo #{gem_binary} install --no-rdoc --no-ri '#{remote_gem_file}'")
118
+ end
119
+ end
120
+ end))
110
121
  end
111
122
 
112
123
  private
@@ -31,7 +31,7 @@ module EY
31
31
 
32
32
  cleanup_old_releases
33
33
 
34
- puts "~> finalizing deploy"
34
+ puts "~> Finalizing deploy"
35
35
  rescue Exception
36
36
  puts_deploy_failure
37
37
  raise
@@ -87,20 +87,21 @@ module EY
87
87
  # task
88
88
  def push_code
89
89
  puts "~> Pushing code to all servers"
90
- EY::Server.all.each do |server|
91
- server.push_code
92
- end
90
+ barrier *(EY::Server.all.map do |server|
91
+ need_later { server.push_code }
92
+ end)
93
93
  end
94
94
 
95
95
  # task
96
96
  def restart
97
97
  @restart_failed = true
98
98
  puts "~> Restarting app servers"
99
- puts "~> restarting app: #{c.latest_release}"
100
99
  roles :app_master, :app, :solo do
101
100
  restart_command = case c.stack
102
101
  when "nginx_unicorn"
103
- sudo(%Q{if [ ! -d /proc/`cat /var/run/engineyard/unicorn_#{c.app}.pid` ]; then rm -f /var/run/engineyard/unicorn_#{c.app}.pid; fi})
102
+ pidfile = "/var/run/engineyard/unicorn_#{c.app}.pid"
103
+ condition = "[ -e #{pidfile} ] && [ ! -d /proc/`cat #{pidfile}` ]"
104
+ sudo("if #{condition}; then rm -f #{pidfile}; fi")
104
105
  sudo("/etc/init.d/unicorn_#{c.app} deploy")
105
106
  when "nginx_mongrel"
106
107
  sudo("monit restart all -g #{c.app}")
@@ -135,7 +136,7 @@ module EY
135
136
  # task
136
137
  def cleanup_old_releases
137
138
  @cleanup_failed = true
138
- puts "~> cleaning up old releases"
139
+ puts "~> Cleaning up old releases"
139
140
  sudo "ls #{c.release_dir} | head -n -3 | xargs -I{} rm -rf #{c.release_dir}/{}"
140
141
  @cleanup_failed = false
141
142
  end
@@ -143,12 +144,12 @@ module EY
143
144
  # task
144
145
  def rollback
145
146
  if c.all_releases.size > 1
146
- puts "~> rolling back to previous release"
147
+ puts "~> Rolling back to previous release"
147
148
  c.release_path = c.previous_release
148
149
  run_with_callbacks(:symlink, c.previous_release)
149
150
  cleanup_latest_release
150
151
  bundle
151
- puts "~> restarting with previous release"
152
+ puts "~> Restarting with previous release"
152
153
  with_maintenance_page { run_with_callbacks(:restart) }
153
154
  else
154
155
  puts "~> Already at oldest release, nothing to roll back to"
@@ -161,7 +162,6 @@ module EY
161
162
  return unless c.migrate?
162
163
  @migrations_reached = true
163
164
  roles :app_master, :solo do
164
- puts "~> migrating"
165
165
  cmd = "cd #{c.latest_release} && #{c.framework_envs} #{c.migration_command}"
166
166
  puts "~> Migrating: #{cmd}"
167
167
  run(cmd)
@@ -170,10 +170,10 @@ module EY
170
170
 
171
171
  # task
172
172
  def copy_repository_cache
173
- puts "~> copying to #{c.release_path}"
173
+ puts "~> Copying to #{c.release_path}"
174
174
  sudo("mkdir -p #{c.release_path} && rsync -aq #{c.exclusions} #{c.repository_cache}/ #{c.release_path}")
175
175
 
176
- puts "~> ensuring proper ownership"
176
+ puts "~> Ensuring proper ownership"
177
177
  sudo("chown -R #{c.user}:#{c.group} #{c.deploy_to}")
178
178
  end
179
179
 
@@ -199,7 +199,7 @@ module EY
199
199
 
200
200
  # task
201
201
  def symlink(release_to_link=c.latest_release)
202
- puts "~> symlinking code"
202
+ puts "~> Symlinking code"
203
203
  sudo "rm -f #{c.current_path} && ln -nfs #{release_to_link} #{c.current_path} && chown -R #{c.user}:#{c.group} #{c.current_path}"
204
204
  @symlink_changed = true
205
205
  rescue Exception
@@ -1,9 +1,5 @@
1
- require 'ey-deploy/verbose_system'
2
-
3
1
  module EY
4
2
  class DeployHook < Task
5
- include VerboseSystem
6
-
7
3
  def initialize(options)
8
4
  super(EY::Deploy::Configuration.new(options))
9
5
  end
@@ -13,14 +9,25 @@ module EY
13
9
  end
14
10
 
15
11
  def run(hook)
16
- if File.exist?("#{c.latest_release}/deploy/#{hook}.rb")
12
+ hook_path = "#{c.latest_release}/deploy/#{hook}.rb"
13
+ if File.exist?(hook_path)
17
14
  Dir.chdir(c.latest_release) do
18
15
  puts "~> running deploy hook: deploy/#{hook}.rb"
19
- callback_context.instance_eval(IO.read("#{c.latest_release}/deploy/#{hook}.rb"))
16
+ if desc = syntax_error(hook_path)
17
+ hook_name = File.basename(hook_path)
18
+ abort "*** [Error] Invalid Ruby syntax in hook: #{hook_name} ***\n*** #{desc.chomp} ***"
19
+ else
20
+ callback_context.instance_eval(IO.read(hook_path))
21
+ end
20
22
  end
21
23
  end
22
24
  end
23
25
 
26
+ def syntax_error(file)
27
+ valid = Kernel.system("ruby -c #{file} 2>/tmp/ey_invalid_deploy_hook | grep 'Syntax OK' --quiet")
28
+ File.new("/tmp/ey_invalid_deploy_hook").gets unless valid
29
+ end
30
+
24
31
  class CallbackContext
25
32
  def initialize(config)
26
33
  @configuration = config
@@ -0,0 +1,58 @@
1
+ require 'open4'
2
+
3
+ module EY
4
+ module LoggedOutput
5
+
6
+ class Tee
7
+ def initialize(*streams)
8
+ @streams = streams.flatten
9
+ end
10
+
11
+ def <<(output)
12
+ @streams.each { |s| s << output }
13
+ self
14
+ end
15
+ end # Tee
16
+
17
+ @@logfile = File.join(ENV['HOME'], 'ey.log')
18
+ def self.logfile=(filename)
19
+ File.unlink filename if File.exist?(filename) # start fresh
20
+ @@logfile = filename
21
+ end
22
+
23
+ def self.logfile
24
+ @@logfile
25
+ end
26
+
27
+ @@verbose = false
28
+ def self.verbose=(v)
29
+ @@verbose = !!v
30
+ end
31
+
32
+ def self.verbose?
33
+ @@verbose
34
+ end
35
+
36
+ def verbose?
37
+ EY::LoggedOutput.verbose?
38
+ end
39
+
40
+ def logfile
41
+ EY::LoggedOutput.logfile
42
+ end
43
+
44
+ def logged_system(cmd)
45
+ File.open(logfile, 'a') do |log|
46
+ out = verbose? ? Tee.new($stdout, log) : log
47
+ err = Tee.new($stderr, log) # we always want to see errors
48
+
49
+ out << ":: running #{cmd}\n"
50
+
51
+ # :quiet means don't raise an error on nonzero exit status
52
+ status = Open4.spawn cmd, 0 => '', 1 => out, 2 => err, :quiet => true
53
+ status.exitstatus == 0
54
+ end
55
+ end
56
+
57
+ end
58
+ end
@@ -1,9 +1,9 @@
1
1
  require 'open-uri'
2
- require 'ey-deploy/verbose_system'
2
+ require 'ey-deploy/logged_output'
3
3
 
4
4
  module EY
5
5
  class Server < Struct.new(:hostname, :role, :name)
6
- include VerboseSystem
6
+ include LoggedOutput
7
7
 
8
8
  def initialize(*fields)
9
9
  super
@@ -52,14 +52,14 @@ module EY
52
52
  def push_code
53
53
  return if local?
54
54
  run "mkdir -p #{config.repository_cache}"
55
- system(%|rsync --delete -aq -e "#{ssh_command}" #{config.repository_cache}/ #{config.user}@#{hostname}:#{config.repository_cache}|)
55
+ logged_system(%|rsync --delete -aq -e "#{ssh_command}" #{config.repository_cache}/ #{config.user}@#{hostname}:#{config.repository_cache}|)
56
56
  end
57
57
 
58
58
  def run(command)
59
59
  if local?
60
- system(command)
60
+ logged_system(command)
61
61
  else
62
- system(ssh_command + " " + Escape.shell_command(["#{config.user}@#{hostname}", command]))
62
+ logged_system(ssh_command + " " + Escape.shell_command(["#{config.user}@#{hostname}", command]))
63
63
  end
64
64
  end
65
65
 
@@ -1,4 +1,4 @@
1
- require 'ey-deploy/verbose_system'
1
+ require 'ey-deploy/logged_output'
2
2
 
3
3
  module EY
4
4
  module Strategies
@@ -24,7 +24,7 @@ module EY
24
24
  end
25
25
  end
26
26
 
27
- include VerboseSystem
27
+ include LoggedOutput
28
28
 
29
29
  attr_reader :opts
30
30
 
@@ -39,10 +39,10 @@ module EY
39
39
 
40
40
  def fetch
41
41
  if usable_repository?
42
- system("#{git} fetch origin")
42
+ logged_system("#{git} fetch -q origin")
43
43
  else
44
44
  FileUtils.rm_rf(opts[:repository_cache])
45
- system("git clone #{opts[:repo]} #{opts[:repository_cache]}")
45
+ logged_system("git clone -q #{opts[:repo]} #{opts[:repository_cache]}")
46
46
  end
47
47
  end
48
48
 
@@ -53,7 +53,7 @@ module EY
53
53
  opts[:ref]
54
54
  end
55
55
 
56
- system("#{git} checkout '#{to_checkout}'") || system("#{git} reset --hard '#{to_checkout}'")
56
+ logged_system("#{git} checkout -q '#{to_checkout}'") || logged_system("#{git} reset -q --hard '#{to_checkout}'")
57
57
  end
58
58
 
59
59
  def create_revision_file(dir)
@@ -1,5 +1,6 @@
1
1
  module EY
2
2
  class Task
3
+ include Dataflow
3
4
 
4
5
  attr_reader :config
5
6
  alias :c :config
@@ -44,22 +45,15 @@ module EY
44
45
  run_on_roles(cmd, %w[sudo sh -l -c], &blk)
45
46
  end
46
47
 
47
- def prepare_run(command)
48
- Escape.shell_command ["sh", "-l", "-c", command]
49
- end
50
-
51
- def prepare_sudo(command)
52
- Escape.shell_command ["sudo", "sh", "-l", "-c", command]
53
- end
54
-
55
48
  private
56
49
 
57
50
  def run_on_roles(cmd, wrapper=%w[sh -l -c])
58
- EY::Server.from_roles(@roles).inject(false) do |acc, server|
51
+ results = EY::Server.from_roles(@roles).map do |server|
59
52
  to_run = block_given? ? yield(server, cmd.dup) : cmd
60
- failure = !server.run(Escape.shell_command(wrapper + [to_run]))
61
- acc || failure
62
- end && raise(EY::RemoteFailure)
53
+ need_later { server.run(Escape.shell_command(wrapper + [to_run])) }
54
+ end
55
+ barrier *results
56
+ results.all? || raise(EY::RemoteFailure)
63
57
  end
64
58
  end
65
59
  end
@@ -1,3 +1,3 @@
1
1
  module EY
2
- VERSION = '0.7.0'
2
+ VERSION = '0.7.1'
3
3
  end
@@ -0,0 +1,52 @@
1
+ == 0.3.0 / 2009-08-29
2
+
3
+ * Major enhancements
4
+
5
+ * "flow" abstraction for threading (use it to create threads and optionally
6
+ pass it a variable to be bound output, or override it to modify need_later
7
+ for other threading strategies such as thread pools)
8
+
9
+ * Dataflow::FutureQueue
10
+
11
+ * Nested binding through variables possible
12
+
13
+ * Minor enhancements
14
+
15
+ * Better #inspect and UnificationError debugging output
16
+
17
+ * "barrier" abstraction for manually preventing execution until variable
18
+ arguments have been bound
19
+
20
+ * Use mixin methods as class/module methods optionally
21
+ e.g. Dataflow.local {|v| v }
22
+
23
+ == 0.2.1 / 2009-07-29
24
+
25
+ * Minor enhancements
26
+
27
+ * Leave __send__ and __id__ alone when acting as a proxy
28
+
29
+ == 0.2.0 / 2009-07-09
30
+
31
+ * Major enhancements
32
+
33
+ * Made equality between objects and dataflow variables more transparent
34
+ (load equality changes with: require 'dataflow/equality')
35
+
36
+ * Minor enhancements
37
+
38
+ * Made #inspect work with unbound variables to not crash deubggers/repls/etc
39
+
40
+ * Made relationship between lazy and dataflow behavior more strict
41
+
42
+ == 0.1.1 / 2009-06-13
43
+
44
+ * Minor enhancements
45
+
46
+ * Got the "require_path" set correctly so rubygems can be used =)
47
+
48
+ == 0.1.0 / 2009-06-13
49
+
50
+ * 1 major enhancement
51
+
52
+ * Birthday!
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2009 Larry Diehl
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.