stackster 0.2.9 → 0.3.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.
- 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
|