stackster 0.2.9 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/CHANGELOG +5 -0
- data/Rakefile +7 -0
- data/lib/stackster/aws/simpledb.rb +1 -1
- data/lib/stackster/entry.rb +3 -2
- data/lib/stackster/instance/instance_reader.rb +0 -3
- data/lib/stackster/stack.rb +0 -4
- data/lib/stackster/version.rb +1 -1
- data/script/ci_setup +5 -5
- data/spec/aws/cloud_formation/error_spec.rb +32 -2
- data/spec/aws/cloud_formation_spec.rb +167 -3
- data/spec/aws/ec2_spec.rb +17 -1
- data/spec/aws/simpledb_spec.rb +65 -3
- data/spec/entry_spec.rb +3 -5
- data/spec/spec_helper.rb +5 -0
- data/spec/stack/stack_formater_spec.rb +23 -3
- data/spec/stack/stack_reader_spec.rb +68 -3
- data/spec/stack_spec.rb +131 -18
- data/stackster.gemspec +1 -0
- metadata +24 -19
data/.gitignore
CHANGED
data/CHANGELOG
CHANGED
data/Rakefile
CHANGED
data/lib/stackster/entry.rb
CHANGED
@@ -24,7 +24,7 @@ module Stackster
|
|
24
24
|
end
|
25
25
|
|
26
26
|
def save
|
27
|
-
|
27
|
+
set_default_attributes
|
28
28
|
|
29
29
|
attributes.each_pair do |key,value|
|
30
30
|
@logger.debug "Setting attribute #{key}=#{value}"
|
@@ -45,8 +45,9 @@ module Stackster
|
|
45
45
|
|
46
46
|
private
|
47
47
|
|
48
|
-
def
|
48
|
+
def set_default_attributes
|
49
49
|
attributes.merge!('Name' => name)
|
50
|
+
attributes.merge!('CreatedAt' => Time.now.utc)
|
50
51
|
end
|
51
52
|
|
52
53
|
def get_attributes
|
data/lib/stackster/stack.rb
CHANGED
data/lib/stackster/version.rb
CHANGED
data/script/ci_setup
CHANGED
@@ -2,13 +2,13 @@
|
|
2
2
|
|
3
3
|
# Source RVM profile and set ruby / gemset
|
4
4
|
. /etc/profile
|
5
|
-
|
5
|
+
|
6
|
+
# Exit with error if any command returns non zero
|
7
|
+
set -e
|
6
8
|
|
7
9
|
# Bundle gems
|
10
|
+
rvm use "1.9.3-p125@stackster" --create
|
8
11
|
bundle
|
9
12
|
|
10
|
-
# Create blank deployment config
|
11
|
-
touch $HOME/.stackster.yml
|
12
|
-
|
13
13
|
# Run spec tests
|
14
|
-
|
14
|
+
rake spec
|
@@ -1,9 +1,39 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Stackster do
|
4
|
+
before do
|
5
|
+
#@logger_stub = stub 'logger stub', :info => 'true', :warn => 'true'
|
6
|
+
@logger_mock = mock 'Logger'
|
7
|
+
@config_stub = stub 'Config', :logger => @logger_mock, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
|
4
8
|
|
5
|
-
|
6
|
-
|
9
|
+
@exception_stub1 = stub 'Excon::Response'
|
10
|
+
@exception_stub1.stub(:response).and_return(@exception_stub1)
|
11
|
+
@exception_stub1.stub(:body).and_return('<opt><Error><Message>No updates are to be performed.</Message></Error></opt>')
|
12
|
+
|
13
|
+
@exception_stub2 = stub 'Excon::Response'
|
14
|
+
@exception_stub2.stub(:response).and_return(@exception_stub2)
|
15
|
+
@exception_stub2.stub(:body).and_return('<opt><Error><Message>Oops.</Message></Error></opt>')
|
7
16
|
end
|
8
17
|
|
18
|
+
describe 'process' do
|
19
|
+
it 'should process no update messages' do
|
20
|
+
@logger_mock.should_receive(:info).with('No updates are to be performed.')
|
21
|
+
|
22
|
+
error = Stackster::AWS::CloudFormation::Error.new :exception => @exception_stub1, :config => @config_stub
|
23
|
+
error.process
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should process general messages' do
|
27
|
+
@logger_mock.should_receive(:error).with('Oops.')
|
28
|
+
|
29
|
+
error = Stackster::AWS::CloudFormation::Error.new :exception => @exception_stub2, :config => @config_stub
|
30
|
+
|
31
|
+
begin
|
32
|
+
error.process
|
33
|
+
fail 'should have exited'
|
34
|
+
rescue SystemExit => e
|
35
|
+
e.status.should == 1
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
9
39
|
end
|
@@ -1,10 +1,174 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Stackster do
|
4
|
+
before do
|
5
|
+
@logger_stub = stub 'logger stub', :info => 'true', :warn => 'true'
|
6
|
+
@config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
|
7
|
+
@error_stub = stub 'Error', :process => 'Processed Error'
|
8
|
+
@response_stub = stub 'Excon::Response', :body => {
|
9
|
+
'Stacks' => [{'StackStatus' => 'green', 'Outputs' => [{'key' => 'value'}]}],
|
10
|
+
'StackResources' => [{'StackName' => 'my_stack'}],
|
11
|
+
'StackEvents' => ['event1', 'event2'],
|
12
|
+
'TemplateBody' => '{EIP: "string"}'
|
13
|
+
}
|
4
14
|
|
5
|
-
|
6
|
-
|
7
|
-
|
15
|
+
@cf_mock = mock 'CloudFormation'
|
16
|
+
Fog::AWS::CloudFormation.stub(:new).and_return(@cf_mock)
|
17
|
+
|
18
|
+
@args = {
|
19
|
+
:parameters => { 'parameter1' => 'my_param' },
|
20
|
+
:name => 'my_stack',
|
21
|
+
:template => 'my_template'
|
22
|
+
}
|
23
|
+
|
24
|
+
@exception = Exception.new('Failed')
|
25
|
+
|
26
|
+
@cf = Stackster::AWS::CloudFormation.new(:config => @config_stub)
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "create" do
|
30
|
+
it "should create the stack on Cloud Formation" do
|
31
|
+
@cf_mock.should_receive(:create_stack).with('my_stack',
|
32
|
+
{ 'Capabilities' => ['CAPABILITY_IAM'],
|
33
|
+
'TemplateBody' => 'my_template',
|
34
|
+
'Parameters' => { 'parameter1' => 'my_param' }
|
35
|
+
})
|
36
|
+
|
37
|
+
@cf.create(@args)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should trap exceptions" do
|
41
|
+
@cf_mock.should_receive(:create_stack).with('my_stack',
|
42
|
+
{ 'Capabilities' => ['CAPABILITY_IAM'],
|
43
|
+
'TemplateBody' => 'my_template',
|
44
|
+
'Parameters' => { 'parameter1' => 'my_param' }
|
45
|
+
}).and_raise(@exception)
|
46
|
+
Stackster::AWS::CloudFormation::Error.should_receive(:new).
|
47
|
+
with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
|
48
|
+
|
49
|
+
@cf.create(@args).should == 'Processed Error'
|
50
|
+
end
|
8
51
|
end
|
9
52
|
|
53
|
+
describe "update" do
|
54
|
+
it "should update the stack on Cloud Formation" do
|
55
|
+
@cf_mock.should_receive(:update_stack).with('my_stack',
|
56
|
+
{ 'Capabilities' => ['CAPABILITY_IAM'],
|
57
|
+
'TemplateBody' => 'my_template',
|
58
|
+
'Parameters' => { 'parameter1' => 'my_param' }
|
59
|
+
})
|
60
|
+
|
61
|
+
@cf.update(@args)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should trap exceptions" do
|
65
|
+
@cf_mock.should_receive(:update_stack).with('my_stack',
|
66
|
+
{ 'Capabilities' => ['CAPABILITY_IAM'],
|
67
|
+
'TemplateBody' => 'my_template',
|
68
|
+
'Parameters' => { 'parameter1' => 'my_param' }
|
69
|
+
}).and_raise(@exception)
|
70
|
+
Stackster::AWS::CloudFormation::Error.should_receive(:new).
|
71
|
+
with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
|
72
|
+
|
73
|
+
@cf.update(@args).should == 'Processed Error'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
describe 'destroy' do
|
79
|
+
it "should delete the stack on Cloud Formation" do
|
80
|
+
@cf_mock.should_receive(:delete_stack).with('my_stack')
|
81
|
+
|
82
|
+
@cf.destroy('my_stack')
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should trap exceptions" do
|
86
|
+
@cf_mock.should_receive(:delete_stack).with('my_stack').and_raise(@exception)
|
87
|
+
Stackster::AWS::CloudFormation::Error.should_receive(:new).
|
88
|
+
with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
|
89
|
+
|
90
|
+
@cf.destroy('my_stack').should == 'Processed Error'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
describe 'describe_stack' do
|
96
|
+
it "should return the Cloud Formation description of the stack" do
|
97
|
+
@cf_mock.should_receive(:describe_stacks).with('StackName' => 'my_stack').and_return(@response_stub)
|
98
|
+
|
99
|
+
@cf.describe_stack('my_stack').should == [{'StackStatus' => 'green', 'Outputs' => [{'key' => 'value'}]}]
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should trap exceptions" do
|
103
|
+
@cf_mock.should_receive(:describe_stacks).with('StackName' => 'my_stack').and_raise(@exception)
|
104
|
+
Stackster::AWS::CloudFormation::Error.should_receive(:new).
|
105
|
+
with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
|
106
|
+
|
107
|
+
@cf.describe_stack('my_stack').should == 'Processed Error'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe "stack_resources" do
|
112
|
+
it "should return the Cloud Formation description of the stack resources" do
|
113
|
+
@cf_mock.should_receive(:describe_stack_resources).with('StackName' => 'my_stack').and_return(@response_stub)
|
114
|
+
|
115
|
+
@cf.stack_resources('my_stack').should == [{'StackName' => 'my_stack'}]
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should trap exceptions" do
|
119
|
+
@cf_mock.should_receive(:describe_stack_resources).with('StackName' => 'my_stack').and_raise(@exception)
|
120
|
+
Stackster::AWS::CloudFormation::Error.should_receive(:new).
|
121
|
+
with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
|
122
|
+
|
123
|
+
@cf.stack_resources('my_stack').should == 'Processed Error'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe "stack_events" do
|
128
|
+
it "should return the Cloud Formation description of the stack events" do
|
129
|
+
@cf_mock.should_receive(:describe_stack_events).with('my_stack').and_return(@response_stub)
|
130
|
+
|
131
|
+
@cf.stack_events('my_stack', 2).should == ['event1', 'event2']
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should trap exceptions" do
|
135
|
+
@cf_mock.should_receive(:describe_stack_events).with('my_stack').and_raise(@exception)
|
136
|
+
Stackster::AWS::CloudFormation::Error.should_receive(:new).
|
137
|
+
with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
|
138
|
+
|
139
|
+
@cf.stack_events('my_stack', 2).should == 'Processed Error'
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe "stack_status" do
|
144
|
+
it "should return the Cloud Formation status of the stack" do
|
145
|
+
@cf_mock.should_receive(:describe_stacks).with('StackName' => 'my_stack').and_return(@response_stub)
|
146
|
+
|
147
|
+
@cf.stack_status('my_stack').should == 'green'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe "stack_outputs" do
|
152
|
+
it "should return the Cloud Formation outputs for the stack" do
|
153
|
+
@cf_mock.should_receive(:describe_stacks).with('StackName' => 'my_stack').and_return(@response_stub)
|
154
|
+
|
155
|
+
@cf.stack_outputs('my_stack').should == [{'key' => 'value'}]
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe "template" do
|
160
|
+
it "should return the Cloud Formation template for the stack" do
|
161
|
+
@cf_mock.should_receive(:get_template).with('my_stack').and_return(@response_stub)
|
162
|
+
|
163
|
+
@cf.template('my_stack').should == '{EIP: "string"}'
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should trap exceptions" do
|
167
|
+
@cf_mock.should_receive(:get_template).with('my_stack').and_raise(@exception)
|
168
|
+
Stackster::AWS::CloudFormation::Error.should_receive(:new).
|
169
|
+
with(:config => @config_stub, :exception => @exception).and_return(@error_stub)
|
170
|
+
|
171
|
+
@cf.template('my_stack').should == 'Processed Error'
|
172
|
+
end
|
173
|
+
end
|
10
174
|
end
|
data/spec/aws/ec2_spec.rb
CHANGED
@@ -1,7 +1,23 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Stackster do
|
4
|
+
before do
|
5
|
+
@config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
|
6
|
+
@response_stub = stub 'Excon::Response', :body => {
|
7
|
+
'reservationSet' => [{'instanceSet' => [{'ipAddress' => '192.168.1.1'}]}]
|
8
|
+
}
|
4
9
|
|
5
|
-
|
10
|
+
@cf_mock = mock 'CloudFormation'
|
11
|
+
Fog::Compute::AWS.stub(:new).and_return(@cf_mock)
|
6
12
|
|
13
|
+
@ec2 = Stackster::AWS::EC2.new(:config => @config_stub)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "describe_instances" do
|
17
|
+
it "should return the Cloud Formation description of the instances" do
|
18
|
+
@cf_mock.should_receive(:describe_instances).and_return(@response_stub)
|
19
|
+
|
20
|
+
@ec2.describe_instances.should == [{'instanceSet' => [{'ipAddress' => '192.168.1.1'}]}]
|
21
|
+
end
|
22
|
+
end
|
7
23
|
end
|
data/spec/aws/simpledb_spec.rb
CHANGED
@@ -1,10 +1,72 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Stackster do
|
4
|
+
before do
|
5
|
+
@config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
|
6
|
+
@response_stub = stub 'Excon::Response', :body => {
|
7
|
+
'RequestId' => 'rid',
|
8
|
+
'Domains' => ['domain1', 'domain2'],
|
9
|
+
'Items' => { 'item1' => { 'key' => ['value'] } }
|
10
|
+
}
|
4
11
|
|
5
|
-
|
6
|
-
|
7
|
-
|
12
|
+
@db_mock = mock 'SimpleDB'
|
13
|
+
Fog::AWS::SimpleDB.stub(:new).and_return(@db_mock)
|
14
|
+
@db_mock.stub(:list_domains).and_return(@response_stub)
|
15
|
+
|
16
|
+
@db = Stackster::AWS::SimpleDB.new(:config => @config_stub)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe 'domains' do
|
20
|
+
it 'should return a list of domains' do
|
21
|
+
@db.domains.should == ['domain1', 'domain2']
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'domain_exists?' do
|
26
|
+
it 'should return true for existing domains' do
|
27
|
+
@db.domain_exists?('domain1').should be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should return false for non-existent domains' do
|
31
|
+
@db.domain_exists?('baddomain1').should_not be_true
|
32
|
+
end
|
8
33
|
end
|
9
34
|
|
35
|
+
describe 'create_domain' do
|
36
|
+
it 'should create a new domain' do
|
37
|
+
@db_mock.should_receive(:create_domain).with('newdomain').and_return(@response_stub)
|
38
|
+
|
39
|
+
@db.create_domain('newdomain').body['RequestId'].should == 'rid'
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'should not create a duplicate domain' do
|
43
|
+
@db_mock.should_not_receive(:create_domain)
|
44
|
+
|
45
|
+
@db.create_domain('domain1').should be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe 'put_attributes' do
|
50
|
+
it 'should update the specified domain' do
|
51
|
+
@db_mock.should_receive(:put_attributes).with('domain1', 'item1', { 'key' => 'value' }, {}).and_return(@response_stub)
|
52
|
+
|
53
|
+
@db.put_attributes('domain1', 'item1', { 'key' => 'value' }, {}).body['RequestId'].should == 'rid'
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'select' do
|
58
|
+
it 'should return query items' do
|
59
|
+
@db_mock.should_receive(:select).with('item1', { "ConsistentRead" => true } ).and_return(@response_stub)
|
60
|
+
|
61
|
+
@db.select('item1').should == { 'item1' => { 'key' => ['value'] } }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe 'delete' do
|
66
|
+
it 'should delete the attributes identified by domain and key' do
|
67
|
+
@db_mock.should_receive(:delete_attributes).with('domain1', 'item1').and_return(@response_stub)
|
68
|
+
|
69
|
+
@db.delete('domain1', 'item1').body['RequestId'].should == 'rid'
|
70
|
+
end
|
71
|
+
end
|
10
72
|
end
|
data/spec/entry_spec.rb
CHANGED
@@ -57,14 +57,12 @@ describe Stackster do
|
|
57
57
|
@entry.name.should == 'test-stack-us-west-1'
|
58
58
|
end
|
59
59
|
|
60
|
-
it "should set the
|
61
|
-
|
62
|
-
it "should set the attributes in simple db" do
|
60
|
+
it "should set the attributes in simple db including default attributes" do
|
63
61
|
@simple_db_mock.should_receive(:put_attributes).
|
64
62
|
with("stacks",
|
65
63
|
"test-stack-us-west-1",
|
66
|
-
{ "key" => "value", "Name" => "test-stack-us-west-1" },
|
67
|
-
{ :replace => ["key", "Name"] } )
|
64
|
+
{ "key" => "value", "Name" => "test-stack-us-west-1", "CreatedAt" => anything },
|
65
|
+
{ :replace => ["key", "Name", "CreatedAt"] } )
|
68
66
|
@entry.attributes = {"key"=>"value"}
|
69
67
|
|
70
68
|
@entry.save
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,30 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Stackster do
|
4
|
+
before do
|
5
|
+
@logger_stub = stub 'logger stub', :info => 'true', :warn => 'true'
|
6
|
+
@config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
@stack_reader_mock = mock 'StackReader'
|
9
|
+
Stackster::StackReader.stub(:new).and_return(@stack_reader_mock)
|
10
|
+
@stack_reader_mock.stub(:attributes).and_return(:chef_repo_bucket_prefix => 'chef_repo_bp')
|
11
|
+
@stack_reader_mock.stub(:outputs).and_return([{'key' => 'value'}])
|
12
|
+
@stack_reader_mock.stub(:status).and_return('green')
|
13
|
+
@stack_reader_mock.stub(:events).and_return(['event1', 'event2', 'event3'])
|
14
|
+
@stack_reader_mock.stub(:resources).and_return([{'StackName' => 'my_stack'}])
|
15
|
+
|
16
|
+
@stack_formater = Stackster::StackFormater.new(:name => 'my_stack', :config => @config_stub)
|
8
17
|
end
|
9
18
|
|
19
|
+
describe 'display' do
|
20
|
+
it 'should return formatted information for the stack' do
|
21
|
+
@stack_formater.display.should == {
|
22
|
+
'attributes' => { :chef_repo_bucket_prefix => 'chef_repo_bp' },
|
23
|
+
'status' => 'green',
|
24
|
+
'outputs' => [{'key' => 'value'}],
|
25
|
+
'events' => ['event1', 'event2', 'event3'],
|
26
|
+
'resources' => [{'StackName' => 'my_stack'}]
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
10
30
|
end
|
@@ -1,10 +1,75 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Stackster do
|
4
|
+
before do
|
5
|
+
@logger_stub = stub 'logger stub', :info => 'true', :warn => 'true'
|
6
|
+
@config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west1'
|
4
7
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
@entry_mock = mock 'Entry'
|
9
|
+
@entry_mock.stub(:attributes).and_return(:chef_repo_bucket_prefix => 'chef_repo_bp')
|
10
|
+
Stackster::Entry.stub(:new).and_return(@entry_mock)
|
11
|
+
|
12
|
+
@cf_mock = mock 'CloudFormation'
|
13
|
+
Stackster::AWS::CloudFormation.stub(:new).and_return(@cf_mock)
|
14
|
+
@cf_mock.stub(:stack_outputs).and_return([{'key' => 'value'}])
|
15
|
+
@cf_mock.stub(:stack_status).and_return('green')
|
16
|
+
@cf_mock.stub(:stack_events).and_return(['event1', 'event2'])
|
17
|
+
@cf_mock.stub(:stack_resources).and_return([{'StackName' => 'my_stack'}])
|
18
|
+
@cf_mock.stub(:template).and_return('{"Parameters": {"EIP": "string"}}')
|
19
|
+
|
20
|
+
@instance_reader_mock = mock 'InstanceReader'
|
21
|
+
Stackster::InstanceReader.stub(:new).and_return(@instance_reader_mock)
|
22
|
+
@instance_reader_mock.stub(:list_stack_instances).and_return(['instance1', 'instance2'])
|
23
|
+
|
24
|
+
@stack_reader = Stackster::StackReader.new(:name => 'my_stack', :config => @config_stub)
|
25
|
+
end
|
26
|
+
|
27
|
+
|
28
|
+
describe 'attributes' do
|
29
|
+
it 'should return the stack attributes' do
|
30
|
+
@stack_reader.attributes.should == { :chef_repo_bucket_prefix => 'chef_repo_bp' }
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe 'outputs' do
|
35
|
+
it 'should return the stack outputs' do
|
36
|
+
@stack_reader.outputs.should == [{'key' => 'value'}]
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'status' do
|
41
|
+
it 'should return the stack status' do
|
42
|
+
@stack_reader.status.should == 'green'
|
43
|
+
end
|
8
44
|
end
|
9
45
|
|
46
|
+
describe 'events' do
|
47
|
+
it 'should return the stack events' do
|
48
|
+
@stack_reader.events(2).should == ['event1', 'event2']
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe 'resources' do
|
53
|
+
it 'should return the stack resources' do
|
54
|
+
@stack_reader.resources.should == [{'StackName' => 'my_stack'}]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'template' do
|
59
|
+
it 'should return the stack template' do
|
60
|
+
@stack_reader.template.should == '{"Parameters": {"EIP": "string"}}'
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe 'parameters' do
|
65
|
+
it 'should return the stack parameters' do
|
66
|
+
@stack_reader.parameters.should == ['EIP']
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe 'instances' do
|
71
|
+
it 'should return the stack instances' do
|
72
|
+
@stack_reader.instances.should == ['instance1', 'instance2']
|
73
|
+
end
|
74
|
+
end
|
10
75
|
end
|
data/spec/stack_spec.rb
CHANGED
@@ -26,11 +26,12 @@ describe Stackster do
|
|
26
26
|
|
27
27
|
describe "mocking a stack object" do
|
28
28
|
before do
|
29
|
-
@
|
30
|
-
|
29
|
+
@logger_stub = stub 'logger stub', :info => 'true', :warn => 'true', :error => 'true'
|
30
|
+
@config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west-1'
|
31
|
+
Stackster::Config.should_receive(:new).and_return @config_stub
|
31
32
|
@entry_mock = mock 'entry mock'
|
32
33
|
Stackster::Entry.should_receive(:new).with(:name => 'test-stack',
|
33
|
-
:config => @
|
34
|
+
:config => @config_stub).
|
34
35
|
and_return @entry_mock
|
35
36
|
@stack = Stackster::Stack.new :name => 'test-stack',
|
36
37
|
:config => 'my-config',
|
@@ -38,7 +39,6 @@ describe Stackster do
|
|
38
39
|
end
|
39
40
|
|
40
41
|
context "when creating a stack" do
|
41
|
-
|
42
42
|
it "should create a new stack" do
|
43
43
|
stack_creater_mock = mock 'stack creater'
|
44
44
|
@entry_mock.should_receive(:set_attributes).
|
@@ -48,7 +48,7 @@ describe Stackster do
|
|
48
48
|
with(:name => 'test-stack',
|
49
49
|
:entry => @entry_mock,
|
50
50
|
:template_file => 'template_file',
|
51
|
-
:config => @
|
51
|
+
:config => @config_stub).
|
52
52
|
and_return stack_creater_mock
|
53
53
|
stack_creater_mock.should_receive(:create)
|
54
54
|
|
@@ -56,13 +56,22 @@ describe Stackster do
|
|
56
56
|
:attributes => { 'test-attr' => 'test-value' }
|
57
57
|
end
|
58
58
|
|
59
|
-
it "should not create a stack entry if the create fails"
|
60
|
-
|
59
|
+
it "should not create a stack entry if the create fails" do
|
60
|
+
@entry_mock.should_receive(:set_attributes).
|
61
|
+
with({ 'test-attr' => 'test-value' })
|
62
|
+
@entry_mock.should_not_receive(:save)
|
63
|
+
|
64
|
+
begin
|
65
|
+
@stack.create :template => 'template_file',
|
66
|
+
:attributes => { 'test-attr' => 'test-value' }
|
67
|
+
fail "should have raised Errno::ENOENT"
|
68
|
+
rescue Errno::ENOENT
|
69
|
+
end
|
70
|
+
end
|
61
71
|
end
|
62
72
|
|
63
73
|
context "when updating a stack" do
|
64
|
-
|
65
|
-
it "should should update an existing stack" do
|
74
|
+
it "should update an existing stack" do
|
66
75
|
stack_updater_mock = mock 'stack updater'
|
67
76
|
stack_reader_mock = mock 'stack reader'
|
68
77
|
@entry_mock.should_receive(:set_attributes).
|
@@ -72,20 +81,47 @@ describe Stackster do
|
|
72
81
|
|
73
82
|
Stackster::StackReader.should_receive(:new).
|
74
83
|
with(:name => 'test-stack',
|
75
|
-
:config => @
|
84
|
+
:config => @config_stub).
|
76
85
|
and_return stack_reader_mock
|
77
86
|
Stackster::StackUpdater.should_receive(:new).
|
78
87
|
with(:name => 'test-stack',
|
79
88
|
:entry => @entry_mock,
|
80
89
|
:template_body => 'template-body-json',
|
81
|
-
:config => @
|
90
|
+
:config => @config_stub).
|
82
91
|
and_return stack_updater_mock
|
83
92
|
stack_updater_mock.should_receive(:update_stack_if_parameters_changed).
|
84
93
|
and_return true
|
85
94
|
@stack.update :attributes => { 'update' => 'test-attrs' }
|
86
95
|
end
|
87
96
|
|
88
|
-
it "should not update a stack entry if the
|
97
|
+
it "should not update a stack entry if the update fails" do
|
98
|
+
@entry_mock.should_receive(:set_attributes).
|
99
|
+
with({ 'update' => 'test-attrs' })
|
100
|
+
@entry_mock.should_not_receive(:save)
|
101
|
+
|
102
|
+
stack_reader_mock = mock 'stack reader'
|
103
|
+
stack_reader_mock.should_receive(:template).and_return('template-body-json')
|
104
|
+
Stackster::StackReader.should_receive(:new).
|
105
|
+
with(:name => 'test-stack',
|
106
|
+
:config => @config_stub).
|
107
|
+
and_return stack_reader_mock
|
108
|
+
|
109
|
+
stack_updater_mock = mock 'stack updater'
|
110
|
+
Stackster::StackUpdater.should_receive(:new).
|
111
|
+
with(:name => 'test-stack',
|
112
|
+
:entry => @entry_mock,
|
113
|
+
:template_body => 'template-body-json',
|
114
|
+
:config => @config_stub).
|
115
|
+
and_return stack_updater_mock
|
116
|
+
stack_updater_mock.should_receive(:update_stack_if_parameters_changed).
|
117
|
+
and_raise('test-stack has not reached a stable state')
|
118
|
+
|
119
|
+
begin
|
120
|
+
@stack.update :attributes => { 'update' => 'test-attrs' }
|
121
|
+
fail 'should have raised RuntimeException'
|
122
|
+
rescue RuntimeError
|
123
|
+
end
|
124
|
+
end
|
89
125
|
end
|
90
126
|
|
91
127
|
context "when destroying a stack" do
|
@@ -93,20 +129,97 @@ describe Stackster do
|
|
93
129
|
stack_destroyer_mock = mock 'stack destroyer'
|
94
130
|
Stackster::StackDestroyer.should_receive(:new).
|
95
131
|
with(:name => 'test-stack',
|
96
|
-
:config => @
|
132
|
+
:config => @config_stub).
|
97
133
|
and_return stack_destroyer_mock
|
98
134
|
stack_destroyer_mock.should_receive(:destroy)
|
99
135
|
@entry_mock.should_receive(:delete_attributes)
|
100
136
|
@stack.destroy
|
101
137
|
end
|
102
138
|
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe 'wrapper methods' do
|
142
|
+
before do
|
143
|
+
@logger_stub = stub 'logger stub', :info => 'true', :warn => 'true', :error => 'true'
|
144
|
+
@config_stub = stub 'Config', :logger => @logger_stub, :access_key => 'key', :secret_key => 'XXX', :region => 'us-west-1'
|
145
|
+
@entry_stub = stub 'Entry'
|
146
|
+
Stackster::Config.should_receive(:new).and_return(@config_stub)
|
147
|
+
Stackster::Entry.should_receive(:new).and_return(@entry_stub)
|
148
|
+
|
149
|
+
@stack = Stackster::Stack.new :name => 'test-stack',
|
150
|
+
:config => @config_stub,
|
151
|
+
:logger => @logger_stub
|
152
|
+
end
|
103
153
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
154
|
+
context "formater" do
|
155
|
+
before do
|
156
|
+
@stack_formater_mock = mock 'StackFormater'
|
157
|
+
Stackster::StackFormater.should_receive(:new).and_return(@stack_formater_mock)
|
158
|
+
@stack_formater_mock.stub(:display).and_return({
|
159
|
+
'attributes' => { :chef_repo_bucket_prefix => 'chef_repo_bp' },
|
160
|
+
'status' => 'green',
|
161
|
+
'outputs' => [{'key' => 'value'}],
|
162
|
+
'events' => ['event1', 'event2', 'event3'],
|
163
|
+
'resources' => [{'StackName' => 'test-stack'}]
|
164
|
+
})
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should display formatted stack attributes' do
|
168
|
+
@stack.display.should == {
|
169
|
+
'attributes' => { :chef_repo_bucket_prefix => 'chef_repo_bp' },
|
170
|
+
'status' => 'green',
|
171
|
+
'outputs' => [{'key' => 'value'}],
|
172
|
+
'events' => ['event1', 'event2', 'event3'],
|
173
|
+
'resources' => [{'StackName' => 'test-stack'}]
|
174
|
+
}
|
175
|
+
end
|
108
176
|
end
|
109
177
|
|
110
|
-
|
178
|
+
context 'reader' do
|
179
|
+
before do
|
180
|
+
@stack_reader_mock = mock 'StackReader'
|
181
|
+
Stackster::StackReader.should_receive(:new).and_return(@stack_reader_mock)
|
182
|
+
@stack_reader_mock.stub(:attributes).and_return(:chef_repo_bucket_prefix => 'chef_repo_bp')
|
183
|
+
@stack_reader_mock.stub(:outputs).and_return([{'key' => 'value'}])
|
184
|
+
@stack_reader_mock.stub(:status).and_return('green')
|
185
|
+
@stack_reader_mock.stub(:events).and_return(['event1', 'event2', 'event3'])
|
186
|
+
@stack_reader_mock.stub(:resources).and_return([{'StackName' => 'my_stack'}])
|
187
|
+
@stack_reader_mock.stub(:template).and_return('{"Parameters": {"EIP": "string"}}')
|
188
|
+
@stack_reader_mock.stub(:parameters).and_return(['EIP'])
|
189
|
+
@stack_reader_mock.stub(:instances).and_return(['instance1', 'instance2'])
|
190
|
+
end
|
191
|
+
|
192
|
+
it 'should return the stack attributes' do
|
193
|
+
@stack.attributes.should == { :chef_repo_bucket_prefix => 'chef_repo_bp' }
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should return the stack outputs' do
|
197
|
+
@stack.outputs.should == [{'key' => 'value'}]
|
198
|
+
end
|
111
199
|
|
200
|
+
it 'should return the stack status' do
|
201
|
+
@stack.status.should == 'green'
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should return the stack events' do
|
205
|
+
@stack.events(3).should == ['event1', 'event2', 'event3']
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should return the stack resources' do
|
209
|
+
@stack.resources.should == [{'StackName' => 'my_stack'}]
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should return the stack template' do
|
213
|
+
@stack.template.should == '{"Parameters": {"EIP": "string"}}'
|
214
|
+
end
|
215
|
+
|
216
|
+
it 'should return the stack parameters' do
|
217
|
+
@stack.parameters.should == ['EIP']
|
218
|
+
end
|
219
|
+
|
220
|
+
it 'should return the stack instances' do
|
221
|
+
@stack.instances.should == ['instance1', 'instance2']
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
112
225
|
end
|
data/stackster.gemspec
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stackster
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-10-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rspec
|
16
|
-
requirement: &
|
16
|
+
requirement: &2160251380 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,21 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2160251380
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: simplecov
|
27
|
+
requirement: &2160250100 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2160250100
|
25
36
|
- !ruby/object:Gem::Dependency
|
26
37
|
name: fog
|
27
|
-
requirement: &
|
38
|
+
requirement: &2160248940 !ruby/object:Gem::Requirement
|
28
39
|
none: false
|
29
40
|
requirements:
|
30
41
|
- - ! '>='
|
@@ -32,10 +43,10 @@ dependencies:
|
|
32
43
|
version: '0'
|
33
44
|
type: :runtime
|
34
45
|
prerelease: false
|
35
|
-
version_requirements: *
|
46
|
+
version_requirements: *2160248940
|
36
47
|
- !ruby/object:Gem::Dependency
|
37
48
|
name: logger
|
38
|
-
requirement: &
|
49
|
+
requirement: &2160247880 !ruby/object:Gem::Requirement
|
39
50
|
none: false
|
40
51
|
requirements:
|
41
52
|
- - ! '>='
|
@@ -43,10 +54,10 @@ dependencies:
|
|
43
54
|
version: '0'
|
44
55
|
type: :runtime
|
45
56
|
prerelease: false
|
46
|
-
version_requirements: *
|
57
|
+
version_requirements: *2160247880
|
47
58
|
- !ruby/object:Gem::Dependency
|
48
59
|
name: trollop
|
49
|
-
requirement: &
|
60
|
+
requirement: &2160246820 !ruby/object:Gem::Requirement
|
50
61
|
none: false
|
51
62
|
requirements:
|
52
63
|
- - ! '>='
|
@@ -54,10 +65,10 @@ dependencies:
|
|
54
65
|
version: '0'
|
55
66
|
type: :runtime
|
56
67
|
prerelease: false
|
57
|
-
version_requirements: *
|
68
|
+
version_requirements: *2160246820
|
58
69
|
- !ruby/object:Gem::Dependency
|
59
70
|
name: xml-simple
|
60
|
-
requirement: &
|
71
|
+
requirement: &2160244280 !ruby/object:Gem::Requirement
|
61
72
|
none: false
|
62
73
|
requirements:
|
63
74
|
- - ! '>='
|
@@ -65,7 +76,7 @@ dependencies:
|
|
65
76
|
version: '0'
|
66
77
|
type: :runtime
|
67
78
|
prerelease: false
|
68
|
-
version_requirements: *
|
79
|
+
version_requirements: *2160244280
|
69
80
|
description: Thats what I do
|
70
81
|
email:
|
71
82
|
- brett@weav.net
|
@@ -135,21 +146,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
135
146
|
- - ! '>='
|
136
147
|
- !ruby/object:Gem::Version
|
137
148
|
version: '0'
|
138
|
-
segments:
|
139
|
-
- 0
|
140
|
-
hash: 107402892190402761
|
141
149
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
142
150
|
none: false
|
143
151
|
requirements:
|
144
152
|
- - ! '>='
|
145
153
|
- !ruby/object:Gem::Version
|
146
154
|
version: '0'
|
147
|
-
segments:
|
148
|
-
- 0
|
149
|
-
hash: 107402892190402761
|
150
155
|
requirements: []
|
151
156
|
rubyforge_project: stackster
|
152
|
-
rubygems_version: 1.8.
|
157
|
+
rubygems_version: 1.8.10
|
153
158
|
signing_key:
|
154
159
|
specification_version: 3
|
155
160
|
summary: I make deployments easier
|