ey-deploy 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/ey-deploy.rb +4 -0
- data/lib/ey-deploy/cli.rb +27 -16
- data/lib/ey-deploy/deploy.rb +13 -13
- data/lib/ey-deploy/deploy_hook.rb +13 -6
- data/lib/ey-deploy/logged_output.rb +58 -0
- data/lib/ey-deploy/server.rb +5 -5
- data/lib/ey-deploy/strategies/git.rb +5 -5
- data/lib/ey-deploy/task.rb +6 -12
- data/lib/ey-deploy/version.rb +1 -1
- data/lib/vendor/dataflow/HISTORY +52 -0
- data/lib/vendor/dataflow/LICENSE +19 -0
- data/lib/vendor/dataflow/README.textile +290 -0
- data/lib/vendor/dataflow/Rakefile +36 -0
- data/lib/vendor/dataflow/dataflow.rb +120 -0
- data/lib/vendor/dataflow/dataflow/actor.rb +22 -0
- data/lib/vendor/dataflow/dataflow/equality.rb +28 -0
- data/lib/vendor/dataflow/dataflow/future_queue.rb +24 -0
- data/lib/vendor/dataflow/dataflow/port.rb +54 -0
- data/lib/vendor/dataflow/examples/barrier.rb +9 -0
- data/lib/vendor/dataflow/examples/data_driven.rb +17 -0
- data/lib/vendor/dataflow/examples/dataflow_http_gets.rb +13 -0
- data/lib/vendor/dataflow/examples/flow.rb +20 -0
- data/lib/vendor/dataflow/examples/future_http_gets.rb +12 -0
- data/lib/vendor/dataflow/examples/future_queue.rb +11 -0
- data/lib/vendor/dataflow/examples/instance_variables.rb +15 -0
- data/lib/vendor/dataflow/examples/laziness.rb +9 -0
- data/lib/vendor/dataflow/examples/local_variables.rb +11 -0
- data/lib/vendor/dataflow/examples/messages.rb +26 -0
- data/lib/vendor/dataflow/examples/port_http_gets.rb +13 -0
- data/lib/vendor/dataflow/examples/port_send.rb +10 -0
- data/lib/vendor/dataflow/examples/ring.rb +21 -0
- data/lib/vendor/dataflow/spec/actor_spec.rb +28 -0
- data/lib/vendor/dataflow/spec/anonymous_variables_spec.rb +21 -0
- data/lib/vendor/dataflow/spec/barrier_spec.rb +25 -0
- data/lib/vendor/dataflow/spec/by_need_spec.rb +55 -0
- data/lib/vendor/dataflow/spec/dataflow_spec.rb +151 -0
- data/lib/vendor/dataflow/spec/equality_spec.rb +40 -0
- data/lib/vendor/dataflow/spec/flow_spec.rb +25 -0
- data/lib/vendor/dataflow/spec/forker_spec.rb +28 -0
- data/lib/vendor/dataflow/spec/future_queue_spec.rb +31 -0
- data/lib/vendor/dataflow/spec/inspect_spec.rb +19 -0
- data/lib/vendor/dataflow/spec/need_later_spec.rb +12 -0
- data/lib/vendor/dataflow/spec/port_spec.rb +26 -0
- data/lib/vendor/dataflow/spec/spec.opts +1 -0
- data/lib/vendor/dataflow/spec/spec_helper.rb +10 -0
- data/lib/vendor/open4/lib/open4.rb +403 -0
- data/spec/deploy_hook_spec.rb +16 -2
- data/spec/fixtures/invalid_hook.rb +1 -0
- data/spec/fixtures/valid_hook.rb +1 -0
- metadata +43 -4
- data/lib/ey-deploy/verbose_system.rb +0 -12
data/lib/ey-deploy.rb
CHANGED
@@ -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'
|
data/lib/ey-deploy/cli.rb
CHANGED
@@ -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.
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
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
|
-
|
115
|
+
"#{config.user}@#{server.hostname}:#{remote_gem_file}",
|
107
116
|
]))
|
108
|
-
|
109
|
-
|
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
|
data/lib/ey-deploy/deploy.rb
CHANGED
@@ -31,7 +31,7 @@ module EY
|
|
31
31
|
|
32
32
|
cleanup_old_releases
|
33
33
|
|
34
|
-
puts "~>
|
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.
|
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
|
-
|
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 "~>
|
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 "~>
|
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 "~>
|
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 "~>
|
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 "~>
|
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 "~>
|
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
|
-
|
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
|
-
|
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
|
data/lib/ey-deploy/server.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'open-uri'
|
2
|
-
require 'ey-deploy/
|
2
|
+
require 'ey-deploy/logged_output'
|
3
3
|
|
4
4
|
module EY
|
5
5
|
class Server < Struct.new(:hostname, :role, :name)
|
6
|
-
include
|
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
|
-
|
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
|
-
|
60
|
+
logged_system(command)
|
61
61
|
else
|
62
|
-
|
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/
|
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
|
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
|
-
|
42
|
+
logged_system("#{git} fetch -q origin")
|
43
43
|
else
|
44
44
|
FileUtils.rm_rf(opts[:repository_cache])
|
45
|
-
|
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
|
-
|
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)
|
data/lib/ey-deploy/task.rb
CHANGED
@@ -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).
|
51
|
+
results = EY::Server.from_roles(@roles).map do |server|
|
59
52
|
to_run = block_given? ? yield(server, cmd.dup) : cmd
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
data/lib/ey-deploy/version.rb
CHANGED
@@ -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.
|