simple_deploy 0.5.6 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -3,19 +3,20 @@ require 'spec_helper'
3
3
  describe SimpleDeploy do
4
4
 
5
5
  before do
6
- @attributes = { 'key' => 'val',
7
- 'ssh_gateway' => '1.2.3.4',
8
- 'chef_repo' => 'chef_repo',
6
+ @attributes = { 'key' => 'val',
7
+ 'chef_repo' => 'chef_repo',
9
8
  'chef_repo_bucket_prefix' => 'chef_repo_bp',
10
- 'chef_repo_domain' => 'chef_repo_d',
11
- 'app' => 'app',
12
- 'app_bucket_prefix' => 'app_bp',
13
- 'app_domain' => 'app_d',
14
- 'cookbooks' => 'cookbooks',
9
+ 'chef_repo_domain' => 'chef_repo_d',
10
+ 'app' => 'app',
11
+ 'app_bucket_prefix' => 'app_bp',
12
+ 'app_domain' => 'app_d',
13
+ 'cookbooks' => 'cookbooks',
15
14
  'cookbooks_bucket_prefix' => 'cookbooks_bp',
16
- 'cookbooks_domain' => 'cookbooks_d' }
15
+ 'cookbooks_domain' => 'cookbooks_d' }
17
16
  @logger_stub = stub 'logger stub'
18
- @logger_stub.stub :debug => 'true', :info => 'true'
17
+ @logger_stub.stub :debug => 'true',
18
+ :info => 'true',
19
+ :error => 'true'
19
20
 
20
21
  @config_mock = mock 'config mock'
21
22
  @config_mock.stub(:logger) { @logger_stub }
@@ -24,6 +25,8 @@ describe SimpleDeploy do
24
25
  @stack_mock = mock 'stack mock'
25
26
  @stack_mock.stub(:attributes) { @attributes }
26
27
 
28
+ @status_mock = mock 'status mock'
29
+
27
30
  options = { :config => @config_mock,
28
31
  :instances => ['1.2.3.4', '4.3.2.1'],
29
32
  :environment => 'test-us-west-1',
@@ -31,112 +34,139 @@ describe SimpleDeploy do
31
34
  :ssh_key => 'key',
32
35
  :stack => @stack_mock,
33
36
  :name => 'stack-name' }
34
- @stack = SimpleDeploy::Stack::Deployment.new options
37
+ @deployment = SimpleDeploy::Stack::Deployment.new options
38
+ @deployment.stub(:sleep) { false }
35
39
  end
36
40
 
37
- it "should not blow up creating a new deployment" do
38
- @stack.class.should == SimpleDeploy::Stack::Deployment
39
- end
41
+ context "manage locks" do
42
+ before do
43
+ status_options = { :name => 'stack-name',
44
+ :environment => 'test-us-west-1',
45
+ :ssh_user => 'user',
46
+ :config => @config_mock,
47
+ :stack => @stack_mock }
48
+ SimpleDeploy::Stack::Deployment::Status.should_receive(:new).
49
+ with(status_options).
50
+ and_return @status_mock
51
+ end
40
52
 
41
- describe "creating a deploy" do
42
- it "should gracefully tell the user there are no running instances" do
43
- options = { :config => @config_mock,
44
- :instances => [],
45
- :environment => 'test-us-west-1',
46
- :ssh_user => 'user',
47
- :ssh_key => 'key',
48
- :stack => @stack_mock,
49
- :name => 'stack-name' }
50
- stack = SimpleDeploy::Stack::Deployment.new options
51
-
52
- expect {
53
- stack.create_deployment
54
- }.to raise_error(RuntimeError, 'There are no running instances to deploy to')
53
+ describe "clear_for_deployment?" do
54
+ it "should test the clear_for_deployment method" do
55
+ @status_mock.stub :clear_for_deployment? => true
56
+ @deployment.clear_for_deployment?.should be_true
57
+ end
55
58
  end
59
+
60
+ describe "clear_deployment_lock" do
61
+ it "should test the clear_deployment_lock" do
62
+ @status_mock.should_receive(:clear_deployment_lock).
63
+ with(true).
64
+ and_return true
65
+ @deployment.clear_deployment_lock(true).should be_true
66
+ end
67
+ end
68
+
56
69
  end
57
70
 
58
71
  describe "executing a deploy" do
59
72
  before do
60
- @deployment_mock = mock 'cap config'
61
- @variables_mock = mock 'variables mock'
62
- @artifact_mock = mock 'artifact mock'
63
- level_stub = stub 'level'
64
- level_stub.should_receive(:level=).with(3)
65
- Capistrano::Configuration.should_receive(:new).and_return @deployment_mock
66
- @deployment_mock.should_receive(:logger).and_return level_stub
67
- @deployment_mock.should_receive(:set).with :gateway, '1.2.3.4'
68
- @deployment_mock.should_receive(:set).with :user, 'user'
69
- @deployment_mock.should_receive(:variables).and_return @variables_mock
70
- @variables_mock.should_receive(:[]=).
71
- with :ssh_options, ( { :keys => 'key',
72
- :paranoid => false } )
73
- @deployment_mock.should_receive(:server).with '1.2.3.4', :instances
74
- @deployment_mock.should_receive(:server).with '4.3.2.1', :instances
75
- @config_mock.should_receive(:artifacts).
76
- and_return ['cookbooks']
77
- @config_mock.should_receive(:artifact_deploy_variable).with('cookbooks').
78
- and_return 'deploy_var'
79
- SimpleDeploy::Artifact.should_receive(:new).and_return @artifact_mock
80
- @artifact_mock.should_receive(:endpoints).
81
- and_return('s3' => 's3://bucket/dir/key')
82
- @stack_mock.should_receive(:instances).exactly(2).times.
83
- and_return [ { 'instancesSet' =>
84
- [ { 'privateIpAddress' => '10.1.2.3' } ] } ]
85
- @config_mock.should_receive(:deploy_script).and_return 'script.sh'
86
- @deployment_mock.should_receive(:load).with({:string=>"task :simpledeploy do\n sudo 'env deploy_var=s3://bucket/dir/key PRIMARY_HOST=10.1.2.3 script.sh'\n end"}).and_return true
87
- @stack.create_deployment
88
- end
89
-
90
- it "should deploy if the stack is clear to deploy" do
91
- status_mock = mock 'status mock'
73
+ @config_mock.stub(:artifacts) { ['chef_repo', 'cookbooks', 'app'] }
74
+ @config_mock.stub(:deploy_script) { '/tmp/script' }
75
+ @stack_mock.stub(:instances) { [ { 'instancesSet' =>
76
+ [ { 'privateIpAddress' => '10.1.2.3' } ] } ] }
77
+
78
+ status_options = { :name => 'stack-name',
79
+ :environment => 'test-us-west-1',
80
+ :ssh_user => 'user',
81
+ :config => @config_mock,
82
+ :stack => @stack_mock }
92
83
  SimpleDeploy::Stack::Deployment::Status.should_receive(:new).
93
- and_return status_mock
94
- status_mock.stub(:clear_for_deployment?).and_return true
95
- status_mock.should_receive(:set_deployment_in_progress)
96
- @deployment_mock.should_receive(:simpledeploy)
97
- status_mock.should_receive(:unset_deployment_in_progress)
98
-
99
- @stack.execute.should == true
84
+ with(status_options).
85
+ and_return @status_mock
100
86
  end
101
87
 
102
- it "should deploy if the stack is not clear to deploy but forced" do
103
- status_mock = mock 'status mock'
104
- SimpleDeploy::Stack::Deployment::Status.should_receive(:new).
105
- and_return status_mock
106
- status_mock.should_receive(:clear_for_deployment?).and_return false, true, true
107
- status_mock.should_receive(:clear_deployment_lock).with(true)
108
- status_mock.should_receive(:set_deployment_in_progress)
109
- @deployment_mock.should_receive(:simpledeploy)
110
- status_mock.should_receive(:unset_deployment_in_progress)
111
-
112
- @stack.execute(true).should == true
113
- end
88
+ describe "when succesful" do
89
+ before do
90
+ @execute_mock = mock "execute"
91
+ execute_options = { :name => 'stack-name',
92
+ :environment => 'test-us-west-1',
93
+ :instances => ['1.2.3.4', '4.3.2.1'],
94
+ :ssh_user => 'user',
95
+ :ssh_key => 'key',
96
+ :config => @config_mock,
97
+ :stack => @stack_mock }
98
+ SimpleDeploy::Stack::Execute.should_receive(:new).
99
+ with(execute_options).
100
+ and_return @execute_mock
101
+ @config_mock.should_receive(:artifact_deploy_variable).
102
+ with("cookbooks").
103
+ and_return('CHEF_REPO_URL')
104
+ @config_mock.should_receive(:artifact_deploy_variable).
105
+ with("app").
106
+ and_return('APP_URL')
107
+ @config_mock.should_receive(:artifact_deploy_variable).
108
+ with("chef_repo").
109
+ and_return('CHEF_REPO_URL')
110
+ @execute_mock.should_receive(:execute).
111
+ with( {:sudo=>true, :command=>"env CHEF_REPO_URL=s3://cookbooks_bp-test-us-west-1/cookbooks_d/cookbooks.tar.gz APP_URL=s3://app_bp-test-us-west-1/app_d/app.tar.gz PRIMARY_HOST=10.1.2.3 /tmp/script"} )
112
+ end
113
+
114
+ it "should deploy if the stack is clear to deploy" do
115
+ @status_mock.stub :clear_for_deployment? => true
116
+ @status_mock.should_receive(:set_deployment_in_progress)
117
+ @status_mock.should_receive(:unset_deployment_in_progress)
118
+ @deployment.execute(false).should be_true
119
+ end
120
+
121
+ it "should deploy if the stack is not clear to deploy but forced and clear in time" do
122
+ @status_mock.should_receive(:clear_for_deployment?).
123
+ and_return(false)
124
+ @status_mock.should_receive(:clear_deployment_lock).
125
+ with(true)
126
+ @status_mock.should_receive(:clear_for_deployment?).
127
+ exactly(2).times.
128
+ and_return(true)
129
+ @status_mock.should_receive(:set_deployment_in_progress)
130
+ @status_mock.should_receive(:unset_deployment_in_progress)
131
+ @deployment.execute(true).should be_true
132
+ end
114
133
 
115
- it "should not deploy if the stack is not clear to deploy and not forced" do
116
- status_mock = mock 'status mock'
117
- SimpleDeploy::Stack::Deployment::Status.should_receive(:new).
118
- and_return status_mock
119
- status_mock.stub(:clear_for_deployment?).and_return false
120
- @logger_stub.should_receive(:error)
134
+ end
121
135
 
122
- @stack.execute.should == false
136
+ describe "when unsuccesful" do
137
+ it "should not deploy if the stack is not clear to deploy but forced however does not clear in time" do
138
+ @status_mock.stub(:clear_for_deployment?) { false }
139
+ @status_mock.should_receive(:clear_deployment_lock).
140
+ with(true)
141
+ @deployment.execute(true).should be_false
142
+ end
143
+
144
+ it "should not deploy if the stack is not clear to deploy and not forced" do
145
+ @status_mock.should_receive(:clear_deployment_lock).never
146
+ @status_mock.stub :clear_for_deployment? => false
147
+ @deployment.execute(false).should be_false
148
+ end
123
149
  end
124
150
  end
125
151
 
126
152
  describe "get_artifact_endpoints" do
127
153
  before do
128
154
  @config_mock.stub(:artifacts) { ['chef_repo', 'cookbooks', 'app'] }
129
- @config_mock.should_receive(:artifact_deploy_variable).with('chef_repo').and_return('CHEF_REPO_URL')
130
- @config_mock.should_receive(:artifact_deploy_variable).with('app').and_return('APP_URL')
131
- @config_mock.should_receive(:artifact_deploy_variable).with('cookbooks').and_return('COOKBOOKS_URL')
155
+ @config_mock.should_receive(:artifact_deploy_variable).
156
+ with('chef_repo').and_return('CHEF_REPO_URL')
157
+ @config_mock.should_receive(:artifact_deploy_variable).
158
+ with('app').and_return('APP_URL')
159
+ @config_mock.should_receive(:artifact_deploy_variable).
160
+ with('cookbooks').and_return('COOKBOOKS_URL')
132
161
  end
133
162
 
134
163
  it "should create S3 endpoints" do
135
- endpoints = @stack.send :get_artifact_endpoints
164
+ endpoints = @deployment.send :get_artifact_endpoints
136
165
 
137
166
  endpoints['CHEF_REPO_URL'].should == 's3://chef_repo_bp-test-us-west-1/chef_repo_d/chef_repo.tar.gz'
138
167
  endpoints['APP_URL'].should == 's3://app_bp-test-us-west-1/app_d/app.tar.gz'
139
168
  endpoints['COOKBOOKS_URL'].should == 's3://cookbooks_bp-test-us-west-1/cookbooks_d/cookbooks.tar.gz'
140
169
  end
170
+
141
171
  end
142
172
  end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleDeploy::Stack::Execute do
4
+ before do
5
+ @ssh_mock = mock 'ssh'
6
+ options = { :config => @config,
7
+ :instances => @instances,
8
+ :environment => @environment,
9
+ :ssh_user => @ssh_user,
10
+ :ssh_key => @ssh_key,
11
+ :stack => @stack,
12
+ :name => @name }
13
+
14
+ SimpleDeploy::Stack::SSH.should_receive(:new).
15
+ with(options).
16
+ and_return @ssh_mock
17
+ @execute = SimpleDeploy::Stack::Execute.new options
18
+ end
19
+
20
+ it "should call execute with the given options" do
21
+ options = { :sudo => true, :command => 'uname' }
22
+ @ssh_mock.should_receive(:execute).
23
+ with(options).
24
+ and_return true
25
+ @execute.execute(options).should be_true
26
+ end
27
+ end
@@ -0,0 +1,86 @@
1
+ require 'spec_helper'
2
+
3
+ describe SimpleDeploy::Stack::SSH do
4
+ before do
5
+ @stack_mock = mock 'stack'
6
+ @task_mock = mock 'task'
7
+ @config_mock = mock 'config'
8
+ @logger_stub = stub 'logger', :debug => true,
9
+ :info => true,
10
+ :error => true
11
+ @config_mock.stub :logger => @logger_stub
12
+ @config_mock.should_receive(:region).
13
+ with('test-env').
14
+ and_return 'test-us-west-1'
15
+ @stack_mock.stub :attributes => { :ssh_gateway => false }
16
+ end
17
+
18
+ context "when unsuccessful" do
19
+ it "should notify the user there are no running instances" do
20
+ options = { :config => @config_mock,
21
+ :instances => [],
22
+ :environment => 'test-env',
23
+ :ssh_user => 'user',
24
+ :ssh_key => 'key',
25
+ :stack => @stack_mock,
26
+ :name => 'test-stack' }
27
+ @ssh = SimpleDeploy::Stack::SSH.new options
28
+ error = 'There are no running instances to execute this command.'
29
+ expect { @ssh.execute(:sudo => true,
30
+ :command => 'uname') }.to raise_error(RuntimeError, error)
31
+
32
+ end
33
+ end
34
+
35
+ context "when successful" do
36
+ before do
37
+ options = { :config => @config_mock,
38
+ :instances => ['1.2.3.4', '4.3.2.1'],
39
+ :environment => 'test-env',
40
+ :ssh_user => 'user',
41
+ :ssh_key => 'key',
42
+ :stack => @stack_mock,
43
+ :name => 'test-stack' }
44
+ @ssh = SimpleDeploy::Stack::SSH.new options
45
+ end
46
+
47
+ describe "when execute called" do
48
+ before do
49
+ task_logger_mock = mock 'task_logger'
50
+ @ssh_options = Hash.new
51
+ Capistrano::Configuration.should_receive(:new).
52
+ with(:output => @logger_stub).
53
+ and_return @task_mock
54
+ @task_mock.stub :logger => task_logger_mock,
55
+ :variables => @ssh_options
56
+ task_logger_mock.should_receive(:level=).with(3)
57
+ @task_mock.should_receive(:set).with :user, 'user'
58
+ @task_mock.should_receive(:server).with('1.2.3.4', :instances)
59
+ @task_mock.should_receive(:server).with('4.3.2.1', :instances)
60
+ end
61
+
62
+ describe "when succesful" do
63
+ it "should execute a task with sudo" do
64
+ @task_mock.should_receive(:load).with({:string=>"task :execute do\n sudo 'uname'\n end"})
65
+ @task_mock.should_receive(:execute).and_return true
66
+ @ssh.execute(:sudo => true,
67
+ :command => 'uname').should be_true
68
+ end
69
+
70
+ it "should execute a task as the calling user " do
71
+ @task_mock.should_receive(:load).with({:string=>"task :execute do\n run 'uname'\n end"})
72
+ @task_mock.should_receive(:execute).and_return true
73
+ @ssh.execute(:sudo => false,
74
+ :command => 'uname').should be_true
75
+ end
76
+ end
77
+
78
+ after do
79
+ @ssh_options.should == { :ssh_options => {
80
+ :keys => 'key', :paranoid => false
81
+ }
82
+ }
83
+ end
84
+ end
85
+ end
86
+ end
data/spec/stack_spec.rb CHANGED
@@ -98,6 +98,7 @@ describe SimpleDeploy do
98
98
  deployment_mock.should_receive(:clear_for_deployment?).and_return(false, true, true)
99
99
  deployment_mock.should_receive(:clear_deployment_lock).with(true)
100
100
  @stack.stub(:deployment).and_return(deployment_mock)
101
+ @stack.stub(:sleep).and_return(false)
101
102
 
102
103
  Stackster::Stack.should_receive(:new).with(:environment => 'test-env',
103
104
  :name => 'test-stack',
@@ -167,10 +168,10 @@ describe SimpleDeploy do
167
168
 
168
169
  it 'should use the private IP when vpc' do
169
170
  stack = SimpleDeploy::Stack.new :environment => 'test-env',
170
- :name => 'test-stack',
171
- :logger => 'my-logger',
172
- :config => @config_stub,
173
- :internal => false
171
+ :name => 'test-stack',
172
+ :logger => 'my-logger',
173
+ :config => @config_stub,
174
+ :internal => false
174
175
  stack.stub(:stack) { @stack_mock }
175
176
 
176
177
  @instances.first['instancesSet'].first['vpcId'] = 'my-vpc'
@@ -181,10 +182,10 @@ describe SimpleDeploy do
181
182
 
182
183
  it 'should use the private IP when internal' do
183
184
  stack = SimpleDeploy::Stack.new :environment => 'test-env',
184
- :name => 'test-stack',
185
- :logger => 'my-logger',
186
- :config => @config_stub,
187
- :internal => true
185
+ :name => 'test-stack',
186
+ :logger => 'my-logger',
187
+ :config => @config_stub,
188
+ :internal => true
188
189
  stack.stub(:stack) { @stack_mock }
189
190
  @stack_mock.stub(:instances).and_return(@instances)
190
191
 
@@ -193,10 +194,10 @@ describe SimpleDeploy do
193
194
 
194
195
  it 'should use the public IP when not vpc and not internal' do
195
196
  stack = SimpleDeploy::Stack.new :environment => 'test-env',
196
- :name => 'test-stack',
197
- :logger => 'my-logger',
198
- :config => @config_stub,
199
- :internal => false
197
+ :name => 'test-stack',
198
+ :logger => 'my-logger',
199
+ :config => @config_stub,
200
+ :internal => false
200
201
  stack.stub(:stack) { @stack_mock }
201
202
  @stack_mock.stub(:instances).and_return(@instances)
202
203
 
@@ -209,14 +210,65 @@ describe SimpleDeploy do
209
210
  { 'ipAddress' => '50.40.30.21', 'privateIpAddress' => '10.1.2.4' }] }]
210
211
 
211
212
  stack = SimpleDeploy::Stack.new :environment => 'test-env',
213
+ :name => 'test-stack',
214
+ :logger => 'my-logger',
215
+ :config => @config_stub,
216
+ :internal => false
217
+ stack.stub(:stack) { @stack_mock }
218
+ @stack_mock.stub(:instances).and_return(@instances)
219
+
220
+ stack.instances.should == ['50.40.30.20', '50.40.30.21']
221
+ end
222
+ end
223
+
224
+ describe 'deploy' do
225
+ before do
226
+ @stack = SimpleDeploy::Stack.new :environment => 'test-env',
212
227
  :name => 'test-stack',
213
228
  :logger => 'my-logger',
214
229
  :config => @config_stub,
215
230
  :internal => false
216
- stack.stub(:stack) { @stack_mock }
217
- @stack_mock.stub(:instances).and_return(@instances)
231
+ @deployment_mock = mock "deployment"
232
+ @stack.stub(:deployment).and_return(@deployment_mock)
233
+ end
218
234
 
219
- stack.instances.should == ['50.40.30.20', '50.40.30.21']
235
+ it "should call exec on deployment" do
236
+ @deployment_mock.should_receive(:execute).with(true).and_return true
237
+ @stack.deploy(true).should be_true
238
+ end
239
+
240
+ it "should not force the deployment by default" do
241
+ @deployment_mock.should_receive(:execute).with(false).and_return true
242
+ @stack.deploy.should be_true
243
+ end
244
+
245
+ it "should return false if the deployment fails" do
246
+ @deployment_mock.should_receive(:execute).with(false).and_return false
247
+ @stack.deploy.should be_false
248
+ end
249
+ end
250
+
251
+ describe 'execute' do
252
+ before do
253
+ @stack = SimpleDeploy::Stack.new :environment => 'test-env',
254
+ :name => 'test-stack',
255
+ :logger => 'my-logger',
256
+ :config => @config_stub,
257
+ :internal => false
258
+ @execute_mock = mock "execute"
259
+ @stack.stub(:executer).and_return(@execute_mock)
260
+ end
261
+
262
+ it "should call exec with the given args" do
263
+ @execute_mock.should_receive(:execute).
264
+ with(:arg => 'val').and_return true
265
+ @stack.execute(:arg => 'val').should be_true
266
+ end
267
+
268
+ it "should return false if the exec fails" do
269
+ @execute_mock.should_receive(:execute).
270
+ with(:arg => 'val').and_return false
271
+ @stack.execute(:arg => 'val').should be_false
220
272
  end
221
273
  end
222
274
  end