engineyard-serverside 2.1.4 → 2.2.0.pre
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/engineyard-serverside.rb +0 -1
- data/lib/engineyard-serverside/cli.rb +32 -13
- data/lib/engineyard-serverside/configuration.rb +1 -1
- data/lib/engineyard-serverside/dependency_manager/composer.rb +2 -2
- data/lib/engineyard-serverside/deploy.rb +3 -4
- data/lib/engineyard-serverside/maintenance.rb +1 -1
- data/lib/engineyard-serverside/rails_assets.rb +8 -3
- data/lib/engineyard-serverside/server.rb +12 -0
- data/lib/engineyard-serverside/servers.rb +32 -27
- data/lib/engineyard-serverside/shell.rb +2 -14
- data/lib/engineyard-serverside/shell/command_result.rb +3 -7
- data/lib/engineyard-serverside/spawner.rb +187 -0
- data/lib/engineyard-serverside/strategies/git.rb +1 -1
- data/lib/engineyard-serverside/task.rb +2 -2
- data/lib/engineyard-serverside/version.rb +1 -1
- data/spec/bundler_deploy_spec.rb +5 -3
- data/spec/deploy_hook_spec.rb +8 -10
- data/spec/git_strategy_spec.rb +1 -1
- data/spec/nodejs_deploy_spec.rb +11 -10
- data/spec/php_deploy_spec.rb +40 -48
- data/spec/server_spec.rb +5 -5
- data/spec/spec_helper.rb +122 -8
- data/spec/support/integration.rb +0 -1
- metadata +10 -24
- data/lib/engineyard-serverside/propagator.rb +0 -75
- data/lib/vendor/systemu/LICENSE +0 -3
- data/lib/vendor/systemu/lib/systemu.rb +0 -363
- data/lib/vendor/systemu/systemu.gemspec +0 -45
- data/spec/propagator_spec.rb +0 -95
@@ -77,11 +77,11 @@ Please consider:
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def run(cmd, &block)
|
80
|
-
servers.roles(@roles).run(
|
80
|
+
servers.roles(@roles).run(cmd, &block)
|
81
81
|
end
|
82
82
|
|
83
83
|
def sudo(cmd, &block)
|
84
|
-
servers.roles(@roles).sudo(
|
84
|
+
servers.roles(@roles).sudo(cmd, &block)
|
85
85
|
end
|
86
86
|
|
87
87
|
end
|
data/spec/bundler_deploy_spec.rb
CHANGED
@@ -38,7 +38,9 @@ describe "Deploying an application that uses Bundler" do
|
|
38
38
|
end
|
39
39
|
|
40
40
|
it "generates bundler binstubs" do
|
41
|
-
|
41
|
+
pending "doesn't work with mocked bundler" do
|
42
|
+
deploy_dir.join('current', 'ey_bundler_binstubs', 'rake').should exist
|
43
|
+
end
|
42
44
|
end
|
43
45
|
end
|
44
46
|
|
@@ -72,14 +74,14 @@ describe "Deploying an application that uses Bundler" do
|
|
72
74
|
context "with a failing Gemfile" do
|
73
75
|
before(:all) do
|
74
76
|
begin
|
75
|
-
deploy_test_application('bundle_fails',
|
77
|
+
deploy_test_application('bundle_fails', 'bundle_install_fails' => true, 'verbose' => false)
|
76
78
|
rescue EY::Serverside::RemoteFailure
|
77
79
|
end
|
78
80
|
end
|
79
81
|
|
80
82
|
it "prints the failure to the log" do
|
81
83
|
out = read_output
|
82
|
-
out.should =~ %r|
|
84
|
+
out.should =~ %r|bundle install failure|
|
83
85
|
deploy_dir.join('current', 'after_bundle.ran' ).should_not exist
|
84
86
|
end
|
85
87
|
end
|
data/spec/deploy_hook_spec.rb
CHANGED
@@ -89,20 +89,18 @@ describe "deploy hooks" do
|
|
89
89
|
|
90
90
|
it "runs things with sudo" do
|
91
91
|
hook = deploy_hook
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
hook.eval_hook('sudo("do it as root") || raise("failed")')
|
92
|
+
mock_sudo do
|
93
|
+
hook.eval_hook('sudo("true") || raise("failed")')
|
94
|
+
end
|
96
95
|
end
|
97
96
|
|
98
97
|
it "raises when the bang method alternative is used" do
|
99
98
|
hook = deploy_hook
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
}.should raise_error(RuntimeError)
|
99
|
+
mock_sudo do
|
100
|
+
lambda {
|
101
|
+
hook.eval_hook('sudo!("false")')
|
102
|
+
}.should raise_error(RuntimeError)
|
103
|
+
end
|
106
104
|
out = read_output
|
107
105
|
out.should =~ %r|FATAL: Exception raised in deploy hook /data/app_name/releases/\d+/deploy/fake_test_hook.rb.|
|
108
106
|
out.should =~ %r|RuntimeError: .*sudo!.*Command failed. false|
|
data/spec/git_strategy_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe "the git deploy strategy" do
|
4
4
|
subject do
|
5
5
|
fixtures_dir = Pathname.new(__FILE__).dirname.join("fixtures")
|
6
|
-
gitrepo_dir = tmpdir.join("gitrepo-#{Time.now.
|
6
|
+
gitrepo_dir = tmpdir.join("gitrepo-#{Time.now.utc.strftime("%Y%m%d%H%M%S")}#{Time.now.tv_usec}-#{$$}")
|
7
7
|
gitrepo_dir.mkdir
|
8
8
|
system "tar xzf #{fixtures_dir.join('gitrepo.tar.gz')} --strip-components 1 -C #{gitrepo_dir}"
|
9
9
|
|
data/spec/nodejs_deploy_spec.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe "Deploying an application that uses Node.js and NPM" do
|
4
|
-
|
5
|
-
|
4
|
+
with_npm_mocked do |mocked|
|
5
|
+
before(:all) do
|
6
|
+
mock_npm if mocked
|
7
|
+
deploy_test_application('nodejs')
|
8
|
+
end
|
9
|
+
|
10
|
+
it "runs 'npm install'" do
|
11
|
+
install_cmd = @deployer.commands.grep(/npm install/).first
|
12
|
+
install_cmd.should_not be_nil
|
13
|
+
end
|
6
14
|
end
|
7
|
-
|
8
|
-
it "runs 'npm install'" do
|
9
|
-
install_cmd = @deployer.commands.grep(/npm install/).first
|
10
|
-
install_cmd.should_not be_nil
|
11
|
-
end
|
12
|
-
end if $NPM_INSTALLED
|
13
|
-
|
14
|
-
|
15
|
+
end
|
data/spec/php_deploy_spec.rb
CHANGED
@@ -2,75 +2,67 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe "Deploying an application that uses PHP and Composer" do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
with_composer_mocked do |mocked|
|
6
|
+
context "with composer available" do
|
7
|
+
before(:all) { mock_composer if mocked }
|
8
|
+
context "with a composer.lock" do
|
9
|
+
before(:all) do
|
10
|
+
deploy_test_application('php_composer_lock')
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
it "runs 'composer install'" do
|
14
|
+
install_cmd = @deployer.commands.grep(/composer install/).first
|
15
|
+
install_cmd.should_not be_nil
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
18
|
+
it "runs 'composer self-update' before 'composer install'" do
|
19
|
+
update_cmd = nil
|
20
|
+
@deployer.commands.each do |cmd|
|
21
|
+
update_cmd ||= /composer self-update/.match(cmd)
|
22
|
+
if /composer install/.match(cmd)
|
23
|
+
update_cmd.should_not be nil
|
24
|
+
end
|
23
25
|
end
|
24
26
|
end
|
25
27
|
end
|
26
|
-
end
|
27
28
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
29
|
+
context "WITHOUT a composer.lock but with composer.json" do
|
30
|
+
before(:all) do
|
31
|
+
deploy_test_application('php_no_composer_lock')
|
32
|
+
end
|
32
33
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
it "outputs a warning about deploying without a .lock" do
|
35
|
+
warning_out = read_output.should include("WARNING: composer.json found but composer.lock missing!")
|
36
|
+
warning_out.should_not be_nil
|
37
|
+
end
|
37
38
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
it "runs 'composer install'" do
|
40
|
+
install_cmd = @deployer.commands.grep(/composer install/).first
|
41
|
+
install_cmd.should_not be_nil
|
42
|
+
end
|
42
43
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
it "runs 'composer self-update' before 'composer install'" do
|
45
|
+
update_cmd = nil
|
46
|
+
@deployer.commands.each do |cmd|
|
47
|
+
update_cmd ||= /composer self-update/.match(cmd)
|
48
|
+
if /composer install/.match(cmd)
|
49
|
+
update_cmd.should_not be nil
|
50
|
+
end
|
49
51
|
end
|
50
52
|
end
|
53
|
+
|
51
54
|
end
|
52
55
|
|
53
56
|
end
|
54
57
|
|
55
|
-
|
56
|
-
|
57
|
-
context "without composer available" do
|
58
|
-
|
59
|
-
context "with a composer.lock" do
|
58
|
+
context "without composer available" do
|
60
59
|
|
61
60
|
it "fails to deploy" do
|
62
61
|
expect {deploy_test_application('php_composer_lock')}.to raise_error EY::Serverside::RemoteFailure
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context "WITHOUT a composer.lock but with composer.json" do
|
67
|
-
|
68
|
-
it "fails to deploy" do
|
69
62
|
expect {deploy_test_application('php_no_composer_lock')}.to raise_error EY::Serverside::RemoteFailure
|
70
63
|
end
|
71
64
|
|
72
65
|
end
|
73
|
-
|
74
|
-
end if !$COMPOSER_INSTALLED
|
66
|
+
end
|
75
67
|
end
|
76
68
|
|
data/spec/server_spec.rb
CHANGED
@@ -2,11 +2,11 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe EY::Serverside::Server do
|
4
4
|
it "starts off empty" do
|
5
|
-
EY::Serverside::Servers.new([]).should be_empty
|
5
|
+
EY::Serverside::Servers.new([], test_shell).should be_empty
|
6
6
|
end
|
7
7
|
|
8
8
|
it "loads from hashes" do
|
9
|
-
servers = EY::Serverside::Servers.from_hashes([{:hostname => 'otherhost', :roles => %w[fire water]}])
|
9
|
+
servers = EY::Serverside::Servers.from_hashes([{:hostname => 'otherhost', :roles => %w[fire water]}], test_shell)
|
10
10
|
servers.size.should == 1
|
11
11
|
end
|
12
12
|
|
@@ -15,12 +15,12 @@ describe EY::Serverside::Server do
|
|
15
15
|
EY::Serverside::Servers.from_hashes([
|
16
16
|
{:hostname => 'otherhost', :roles => [:fire]},
|
17
17
|
{:hostname => 'otherhost', :roles => [:water]},
|
18
|
-
])
|
18
|
+
], test_shell)
|
19
19
|
end.should raise_error(EY::Serverside::Servers::DuplicateHostname)
|
20
20
|
end
|
21
21
|
|
22
22
|
it "makes sure your roles are symbols at creation time" do
|
23
|
-
servers = EY::Serverside::Servers.from_hashes([{:hostname => 'otherhost', :roles => %w[fire water]}])
|
23
|
+
servers = EY::Serverside::Servers.from_hashes([{:hostname => 'otherhost', :roles => %w[fire water]}], test_shell)
|
24
24
|
servers.each { |server| server.roles.should == Set[:fire, :water] }
|
25
25
|
end
|
26
26
|
|
@@ -30,7 +30,7 @@ describe EY::Serverside::Server do
|
|
30
30
|
{:hostname => 'localhost', :roles => [:ice, :cold]},
|
31
31
|
{:hostname => 'firewater', :roles => [:fire, :water]},
|
32
32
|
{:hostname => 'icewater', :roles => [:ice, :water]},
|
33
|
-
])
|
33
|
+
], test_shell)
|
34
34
|
end
|
35
35
|
|
36
36
|
it "#roles works with strings or symbols" do
|
data/spec/spec_helper.rb
CHANGED
@@ -20,6 +20,7 @@ require File.expand_path('../support/integration', __FILE__)
|
|
20
20
|
FIXTURES_DIR = Pathname.new(__FILE__).dirname.join("fixtures")
|
21
21
|
TMPDIR = Pathname.new(__FILE__).dirname.parent.join('tmp')
|
22
22
|
GROUP = `id -gn`.strip
|
23
|
+
INTERNAL_KEY = Pathname.new("~/.ssh/id_rsa").expand_path
|
23
24
|
|
24
25
|
module EY
|
25
26
|
module Serverside
|
@@ -31,15 +32,35 @@ module EY
|
|
31
32
|
class Strategies::Git
|
32
33
|
def short_log_message(_) "" end
|
33
34
|
end
|
35
|
+
|
36
|
+
|
37
|
+
class Paths
|
38
|
+
# This needs to be patched for the tests to succeed, but
|
39
|
+
# the chances of 2 real deploys colliding in the same second
|
40
|
+
# is very very low.
|
41
|
+
def active_release
|
42
|
+
@active_release ||= if Time.now.utc.strftime("%L") =~ /L/ # old ruby
|
43
|
+
path(:releases, Time.now.utc.strftime("%Y%m%d%H%M%S#{Time.now.tv_usec}"))
|
44
|
+
else
|
45
|
+
path(:releases, Time.now.utc.strftime("%Y%m%d%H%M%S%L"))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
34
50
|
end
|
35
51
|
end
|
36
52
|
|
37
|
-
|
53
|
+
module SpecDependencyHelpers
|
38
54
|
$NPM_INSTALLED = system('which npm 2>&1')
|
39
55
|
unless $NPM_INSTALLED
|
40
56
|
$stderr.puts "npm not found; skipping Node.js specs."
|
41
57
|
end
|
42
58
|
|
59
|
+
def with_npm_mocked(&block)
|
60
|
+
context("mocked") { yield true }
|
61
|
+
context("unmocked") { yield false } if $NPM_INSTALLED
|
62
|
+
end
|
63
|
+
|
43
64
|
$COMPOSER_INSTALLED = system('command -v composer > /dev/null')
|
44
65
|
if $COMPOSER_INSTALLED
|
45
66
|
$stderr.puts "composer found; skipping tests that expect it to be missing."
|
@@ -47,6 +68,15 @@ Spec::Runner.configure do |config|
|
|
47
68
|
$stderr.puts "composer not found; skipping tests that expect it to be available."
|
48
69
|
end
|
49
70
|
|
71
|
+
def with_composer_mocked(&block)
|
72
|
+
context("mocked") { yield true }
|
73
|
+
context("unmocked") { yield false } if $COMPOSER_INSTALLED
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
RSpec.configure do |config|
|
78
|
+
config.extend SpecDependencyHelpers
|
79
|
+
|
50
80
|
config.before(:all) do
|
51
81
|
make_tmpdir
|
52
82
|
EY::Serverside.dna_json = MultiJson.dump({})
|
@@ -111,7 +141,7 @@ Spec::Runner.configure do |config|
|
|
111
141
|
|
112
142
|
def test_shell(verbose=true)
|
113
143
|
@test_shell ||= begin
|
114
|
-
@log_path = tmpdir.join("serverside-deploy-#{Time.now.
|
144
|
+
@log_path = tmpdir.join("serverside-deploy-#{Time.now.to_f}-#{$$}.log")
|
115
145
|
EY::Serverside::Shell.new(:verbose => verbose, :log_path => @log_path, :stdout => stdout, :stderr => stderr)
|
116
146
|
end
|
117
147
|
end
|
@@ -120,13 +150,87 @@ Spec::Runner.configure do |config|
|
|
120
150
|
be_exist
|
121
151
|
end
|
122
152
|
|
153
|
+
def bindir
|
154
|
+
@bindir ||= begin
|
155
|
+
dir = tmpdir.join("ey_test_cmds_#{Time.now.to_f}_#{$$}")
|
156
|
+
dir.mkpath
|
157
|
+
dir
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
def mock_command(cmd, contents, &block)
|
162
|
+
bindir.join(cmd).open('w') do |f|
|
163
|
+
f.write contents
|
164
|
+
f.chmod(0755)
|
165
|
+
end
|
166
|
+
with_mocked_commands(&block) if block_given?
|
167
|
+
end
|
168
|
+
|
169
|
+
def mock_bundler(failure = false, &block)
|
170
|
+
mock_command('bundle', <<-SCRIPT, &block)
|
171
|
+
#!#{`which ruby`}
|
172
|
+
puts "Bundling gems"
|
173
|
+
$stdout.flush
|
174
|
+
#{failure && '$stderr.puts "bundle install failure"; exit 1'}
|
175
|
+
SCRIPT
|
176
|
+
end
|
177
|
+
|
178
|
+
def mock_npm(&block)
|
179
|
+
mock_command('npm', <<-SCRIPT, &block)
|
180
|
+
#!/bin/bash
|
181
|
+
echo "Running npm with $@"
|
182
|
+
SCRIPT
|
183
|
+
end
|
184
|
+
|
185
|
+
def mock_composer(&block)
|
186
|
+
mock_command('composer', <<-SCRIPT, &block)
|
187
|
+
#!/bin/bash
|
188
|
+
echo "Running composer with $@"
|
189
|
+
SCRIPT
|
190
|
+
end
|
191
|
+
|
192
|
+
def mock_sudo(&block)
|
193
|
+
mock_command('sudo', <<-SCRIPT, &block)
|
194
|
+
#!/bin/bash
|
195
|
+
echo "$@"
|
196
|
+
exec "$@"
|
197
|
+
SCRIPT
|
198
|
+
end
|
199
|
+
|
200
|
+
def with_mocked_commands(&block)
|
201
|
+
with_env('PATH' => "#{bindir}:#{ENV['PATH']}", &block)
|
202
|
+
end
|
203
|
+
|
204
|
+
def with_env(new_env_vars)
|
205
|
+
raise ArgumentError, "with_env takes a block" unless block_given?
|
206
|
+
|
207
|
+
old_env_vars = {}
|
208
|
+
new_env_vars.each do |k, v|
|
209
|
+
if ENV.has_key?(k)
|
210
|
+
old_env_vars[k] = ENV[k]
|
211
|
+
end
|
212
|
+
ENV[k] = v if v
|
213
|
+
end
|
214
|
+
|
215
|
+
yield
|
216
|
+
ensure
|
217
|
+
new_env_vars.keys.each do |k|
|
218
|
+
if old_env_vars.has_key?(k)
|
219
|
+
ENV[k] = old_env_vars[k]
|
220
|
+
else
|
221
|
+
ENV.delete(k)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
|
123
227
|
def deploy_dir
|
124
|
-
@deploy_dir ||= tmpdir.join("serverside-deploy-#{Time.now.
|
228
|
+
@deploy_dir ||= tmpdir.join("serverside-deploy-#{Time.now.to_f}-#{$$}")
|
125
229
|
end
|
126
230
|
|
127
231
|
# set up EY::Serverside::Server like we're on a solo
|
128
232
|
def test_servers
|
129
|
-
@test_servers ||= EY::Serverside::Servers.from_hashes([{:hostname => 'localhost', :roles => %w[solo], :user => ENV['USER']}])
|
233
|
+
@test_servers ||= EY::Serverside::Servers.from_hashes([{:hostname => 'localhost', :roles => %w[solo], :user => ENV['USER']}], test_shell)
|
130
234
|
end
|
131
235
|
|
132
236
|
# When a repo fixture name is specified, the files found in the specified
|
@@ -178,8 +282,12 @@ Spec::Runner.configure do |config|
|
|
178
282
|
|
179
283
|
@binpath = File.expand_path(File.join(File.dirname(__FILE__), '..', 'bin', 'engineyard-serverside'))
|
180
284
|
FullTestDeploy.on_create_callback = block
|
181
|
-
|
182
|
-
|
285
|
+
|
286
|
+
mock_bundler(options['bundle_install_fails'])
|
287
|
+
with_mocked_commands do
|
288
|
+
capture do
|
289
|
+
EY::Serverside::CLI.start(@argv)
|
290
|
+
end
|
183
291
|
end
|
184
292
|
ensure
|
185
293
|
@deployer = EY::Serverside::Deploy.deployer
|
@@ -188,6 +296,7 @@ Spec::Runner.configure do |config|
|
|
188
296
|
|
189
297
|
def redeploy_test_application(extra_config = {}, &block)
|
190
298
|
raise "Please deploy_test_application first" unless @argv
|
299
|
+
bundle_install_fails = extra_config.delete('bundle_install_fails')
|
191
300
|
|
192
301
|
@action = @adapter.deploy do |args|
|
193
302
|
extra_config.each do |key,val|
|
@@ -202,8 +311,13 @@ Spec::Runner.configure do |config|
|
|
202
311
|
@argv = @action.commands.last.to_argv[2..-1]
|
203
312
|
|
204
313
|
FullTestDeploy.on_create_callback = block
|
205
|
-
|
206
|
-
|
314
|
+
|
315
|
+
mock_bundler(bundle_install_fails)
|
316
|
+
|
317
|
+
with_mocked_commands do
|
318
|
+
capture do
|
319
|
+
EY::Serverside::CLI.start(@argv)
|
320
|
+
end
|
207
321
|
end
|
208
322
|
ensure
|
209
323
|
@deployer = EY::Serverside::Deploy.deployer
|