simple_deploy 0.5.6 → 0.6.0

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.
@@ -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