kumogata 0.1.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.
@@ -0,0 +1,183 @@
1
+ describe 'Kumogata::Client#create' do
2
+ it 'create a stack from Ruby template' do
3
+ template = <<-EOS
4
+ Resources do
5
+ myEC2Instance do
6
+ Type "AWS::EC2::Instance"
7
+ Properties do
8
+ ImageId "ami-XXXXXXXX"
9
+ InstanceType "t1.micro"
10
+ end
11
+ end
12
+ end
13
+
14
+ Outputs do
15
+ AZ do
16
+ Value do
17
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
18
+ end
19
+ end
20
+ end
21
+ EOS
22
+
23
+ run_client(:create, :template => template) do |client, cf|
24
+ json = eval_template(template, :update_deletion_policy => true).to_json
25
+ stacks = double('status')
26
+
27
+ output = make_double('output') do |obj|
28
+ obj.should_receive(:key) { 'AZ' }
29
+ obj.should_receive(:value) { 'ap-northeast-1b' }
30
+ end
31
+
32
+ resource_summary = make_double('resource_summary') do |obj|
33
+ obj.should_receive(:[]).with(:logical_resource_id) { 'myEC2Instance' }
34
+ obj.should_receive(:[]).with(:physical_resource_id) { 'i-XXXXXXXX' }
35
+ obj.should_receive(:[]).with(:resource_type) { 'AWS::EC2::Instance' }
36
+ obj.should_receive(:[]).with(:resource_status) { 'CREATE_COMPLETE' }
37
+ obj.should_receive(:[]).with(:resource_status_reason) { nil }
38
+ obj.should_receive(:[]).with(:last_updated_timestamp) { '2014-03-02 04:35:12 UTC' }
39
+ end
40
+
41
+ stack = make_double('stack') do |obj|
42
+ obj.should_receive(:status).and_return(
43
+ 'CREATE_COMPLETE', 'CREATE_COMPLETE',
44
+ 'DELETE_COMPLETE', 'DELETE_COMPLETE', 'DELETE_COMPLETE')
45
+ obj.should_receive(:outputs) { [output] }
46
+ obj.should_receive(:resource_summaries) { [resource_summary] }
47
+ obj.should_receive(:delete)
48
+ end
49
+
50
+ stacks = make_double('stacks') do |obj|
51
+ obj.should_receive(:create)
52
+ .with('kumogata-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', json, {}) { stack }
53
+ obj.should_receive(:[])
54
+ .with('kumogata-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX') { stack }
55
+ end
56
+
57
+ cf.should_receive(:stacks).twice { stacks }
58
+ end
59
+ end
60
+
61
+ it 'create a stack from Ruby template with parameters' do
62
+ template = <<-EOS
63
+ Parameters do
64
+ InstanceType do
65
+ Default "t1.micro"
66
+ Description "Instance Type"
67
+ Type "String"
68
+ end
69
+ end
70
+
71
+ Resources do
72
+ myEC2Instance do
73
+ Type "AWS::EC2::Instance"
74
+ Properties do
75
+ ImageId "ami-XXXXXXXX"
76
+ InstanceType { Ref "InstanceType" }
77
+ end
78
+ end
79
+ end
80
+
81
+ Outputs do
82
+ AZ do
83
+ Value do
84
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
85
+ end
86
+ end
87
+ end
88
+ EOS
89
+
90
+ run_client(:create, :template => template, :options => {:parameters => ['InstanceType=m1.large']}) do |client, cf|
91
+ json = eval_template(template, :update_deletion_policy => true).to_json
92
+ stacks = double('stacks')
93
+
94
+ output = make_double('output') do |obj|
95
+ obj.should_receive(:key) { 'AZ' }
96
+ obj.should_receive(:value) { 'ap-northeast-1b' }
97
+ end
98
+
99
+ resource_summary = make_double('resource_summary') do |obj|
100
+ obj.should_receive(:[]).with(:logical_resource_id) { 'myEC2Instance' }
101
+ obj.should_receive(:[]).with(:physical_resource_id) { 'i-XXXXXXXX' }
102
+ obj.should_receive(:[]).with(:resource_type) { 'AWS::EC2::Instance' }
103
+ obj.should_receive(:[]).with(:resource_status) { 'CREATE_COMPLETE' }
104
+ obj.should_receive(:[]).with(:resource_status_reason) { nil }
105
+ obj.should_receive(:[]).with(:last_updated_timestamp) { '2014-03-02 04:35:12 UTC' }
106
+ end
107
+
108
+ stack = make_double('stack') do |obj|
109
+ obj.should_receive(:status).and_return(
110
+ 'CREATE_COMPLETE', 'CREATE_COMPLETE',
111
+ 'DELETE_COMPLETE', 'DELETE_COMPLETE', 'DELETE_COMPLETE')
112
+ obj.should_receive(:outputs) { [output] }
113
+ obj.should_receive(:resource_summaries) { [resource_summary] }
114
+ obj.should_receive(:delete)
115
+ end
116
+
117
+ stacks = make_double('stacks') do |obj|
118
+ obj.should_receive(:create)
119
+ .with('kumogata-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', json, {:parameters=>{"InstanceType"=>"m1.large"}}) { stack }
120
+ obj.should_receive(:[])
121
+ .with('kumogata-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX') { stack }
122
+ end
123
+
124
+ cf.should_receive(:stacks).twice { stacks }
125
+ end
126
+ end
127
+
128
+ it 'create a stack from Ruby template with stack name' do
129
+ template = <<-EOS
130
+ Resources do
131
+ myEC2Instance do
132
+ Type "AWS::EC2::Instance"
133
+ Properties do
134
+ ImageId "ami-XXXXXXXX"
135
+ InstanceType "t1.micro"
136
+ end
137
+ end
138
+ end
139
+
140
+ Outputs do
141
+ AZ do
142
+ Value do
143
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
144
+ end
145
+ end
146
+ end
147
+ EOS
148
+
149
+ run_client(:create, :arguments => ['MyStack'], :template => template) do |client, cf|
150
+ json = eval_template(template).to_json
151
+ stacks = double('status')
152
+
153
+ output = make_double('output') do |obj|
154
+ obj.should_receive(:key) { 'AZ' }
155
+ obj.should_receive(:value) { 'ap-northeast-1b' }
156
+ end
157
+
158
+ resource_summary = make_double('resource_summary') do |obj|
159
+ obj.should_receive(:[]).with(:logical_resource_id) { 'myEC2Instance' }
160
+ obj.should_receive(:[]).with(:physical_resource_id) { 'i-XXXXXXXX' }
161
+ obj.should_receive(:[]).with(:resource_type) { 'AWS::EC2::Instance' }
162
+ obj.should_receive(:[]).with(:resource_status) { 'CREATE_COMPLETE' }
163
+ obj.should_receive(:[]).with(:resource_status_reason) { nil }
164
+ obj.should_receive(:[]).with(:last_updated_timestamp) { '2014-03-02 04:35:12 UTC' }
165
+ end
166
+
167
+ stack = make_double('stack') do |obj|
168
+ obj.should_receive(:status).and_return(
169
+ 'CREATE_COMPLETE',
170
+ 'CREATE_COMPLETE')
171
+ obj.should_receive(:outputs) { [output] }
172
+ obj.should_receive(:resource_summaries) { [resource_summary] }
173
+ end
174
+
175
+ stacks = make_double('status') do |obj|
176
+ obj.should_receive(:create)
177
+ .with('MyStack', json, {}) { stack }
178
+ end
179
+
180
+ cf.should_receive(:stacks) { stacks }
181
+ end
182
+ end
183
+ end
@@ -0,0 +1,20 @@
1
+ describe 'Kumogata::Client#delete' do
2
+ it 'update a stack from Ruby template' do
3
+ run_client(:delete, :arguments => ['MyStack'], :options => {:force => true}) do |client, cf|
4
+ stacks = double('status')
5
+
6
+ stack = make_double('stack') do |obj|
7
+ obj.should_receive(:delete).with(no_args())
8
+ obj.should_receive(:status).and_return(
9
+ 'DELETE_COMPLETE', 'DELETE_COMPLETE', 'DELETE_COMPLETE')
10
+ end
11
+
12
+ stacks = make_double('stacks') do |obj|
13
+ obj.should_receive(:[])
14
+ .with('MyStack') { stack }
15
+ end
16
+
17
+ cf.should_receive(:stacks) { stacks }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,121 @@
1
+ describe 'Kumogata::Client#update' do
2
+ it 'update a stack from Ruby template' do
3
+ template = <<-EOS
4
+ Resources do
5
+ myEC2Instance do
6
+ Type "AWS::EC2::Instance"
7
+ Properties do
8
+ ImageId "ami-XXXXXXXX"
9
+ InstanceType "t1.micro"
10
+ end
11
+ end
12
+ end
13
+
14
+ Outputs do
15
+ AZ do
16
+ Value do
17
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
18
+ end
19
+ end
20
+ end
21
+ EOS
22
+
23
+ run_client(:update, :arguments => ['MyStack'], :template => template) do |client, cf|
24
+ json = eval_template(template).to_json
25
+ stacks = double('status')
26
+
27
+ output = make_double('output') do |obj|
28
+ obj.should_receive(:key) { 'AZ' }
29
+ obj.should_receive(:value) { 'ap-northeast-1b' }
30
+ end
31
+
32
+ resource_summary = make_double('resource_summary') do |obj|
33
+ obj.should_receive(:[]).with(:logical_resource_id) { 'myEC2Instance' }
34
+ obj.should_receive(:[]).with(:physical_resource_id) { 'i-XXXXXXXX' }
35
+ obj.should_receive(:[]).with(:resource_type) { 'AWS::EC2::Instance' }
36
+ obj.should_receive(:[]).with(:resource_status) { 'UPDATE_COMPLETE' }
37
+ obj.should_receive(:[]).with(:resource_status_reason) { nil }
38
+ obj.should_receive(:[]).with(:last_updated_timestamp) { '2014-03-02 04:35:12 UTC' }
39
+ end
40
+
41
+ stack = make_double('stack') do |obj|
42
+ obj.should_receive(:update).with(:template => json)
43
+ obj.should_receive(:status).and_return(
44
+ 'UPDATE_COMPLETE', 'UPDATE_COMPLETE', 'UPDATE_COMPLETE')
45
+ obj.should_receive(:outputs) { [output] }
46
+ obj.should_receive(:resource_summaries) { [resource_summary] }
47
+ end
48
+
49
+ stacks = make_double('stacks') do |obj|
50
+ obj.should_receive(:[])
51
+ .with('MyStack') { stack }
52
+ end
53
+
54
+ cf.should_receive(:stacks) { stacks }
55
+ end
56
+ end
57
+
58
+ it 'update a stack from Ruby template with parameters' do
59
+ template = <<-EOS
60
+ Parameters do
61
+ InstanceType do
62
+ Default "t1.micro"
63
+ Description "Instance Type"
64
+ Type "String"
65
+ end
66
+ end
67
+
68
+ Resources do
69
+ myEC2Instance do
70
+ Type "AWS::EC2::Instance"
71
+ Properties do
72
+ ImageId "ami-XXXXXXXX"
73
+ InstanceType { Ref "InstanceType" }
74
+ end
75
+ end
76
+ end
77
+
78
+ Outputs do
79
+ AZ do
80
+ Value do
81
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
82
+ end
83
+ end
84
+ end
85
+ EOS
86
+
87
+ run_client(:update, :arguments => ['MyStack'], :template => template, :options => {:parameters => ['InstanceType=m1.large']}) do |client, cf|
88
+ json = eval_template(template).to_json
89
+ stacks = double('status')
90
+
91
+ output = make_double('output') do |obj|
92
+ obj.should_receive(:key) { 'AZ' }
93
+ obj.should_receive(:value) { 'ap-northeast-1b' }
94
+ end
95
+
96
+ resource_summary = make_double('resource_summary') do |obj|
97
+ obj.should_receive(:[]).with(:logical_resource_id) { 'myEC2Instance' }
98
+ obj.should_receive(:[]).with(:physical_resource_id) { 'i-XXXXXXXX' }
99
+ obj.should_receive(:[]).with(:resource_type) { 'AWS::EC2::Instance' }
100
+ obj.should_receive(:[]).with(:resource_status) { 'UPDATE_COMPLETE' }
101
+ obj.should_receive(:[]).with(:resource_status_reason) { nil }
102
+ obj.should_receive(:[]).with(:last_updated_timestamp) { '2014-03-02 04:35:12 UTC' }
103
+ end
104
+
105
+ stack = make_double('stack') do |obj|
106
+ obj.should_receive(:update).with(:template => json, :parameters=>{"InstanceType"=>"m1.large"})
107
+ obj.should_receive(:status).and_return(
108
+ 'UPDATE_COMPLETE', 'UPDATE_COMPLETE', 'UPDATE_COMPLETE')
109
+ obj.should_receive(:outputs) { [output] }
110
+ obj.should_receive(:resource_summaries) { [resource_summary] }
111
+ end
112
+
113
+ stacks = make_double('stacks') do |obj|
114
+ obj.should_receive(:[])
115
+ .with('MyStack') { stack }
116
+ end
117
+
118
+ cf.should_receive(:stacks) { stacks }
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,135 @@
1
+ describe 'Kumogata::Client#validate' do
2
+ it 'validate Ruby template (without error)' do
3
+ template = <<-EOS
4
+ Resources do
5
+ myEC2Instance do
6
+ Type "AWS::EC2::Instance"
7
+ Properties do
8
+ ImageId "ami-XXXXXXXX"
9
+ InstanceType "t1.micro"
10
+ end
11
+ end
12
+ end
13
+
14
+ Outputs do
15
+ AZ do
16
+ Value do
17
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
18
+ end
19
+ end
20
+ end
21
+ EOS
22
+
23
+ run_client(:validate, :template => template) do |client, cf|
24
+ json = eval_template(template).to_json
25
+
26
+ cf.should_receive(:validate_template).with(json) {
27
+ {}
28
+ }
29
+ end
30
+ end
31
+
32
+ it 'validate Ruby template (with error)' do
33
+ template = <<-EOS
34
+ Resources do
35
+ myEC2Instance do
36
+ Type "AWS::EC2::Instance"
37
+ Properties do
38
+ ImageId "ami-XXXXXXXX"
39
+ InstanceType "t1.micro"
40
+ end
41
+ end
42
+ end
43
+
44
+ #Outputs do
45
+ AZ do
46
+ Value do
47
+ Fn__GetAtt "myEC2Instance", "AvailabilityZone"
48
+ end
49
+ end
50
+ #end
51
+ EOS
52
+
53
+ expect {
54
+ run_client(:validate, :template => template) do |client, cf|
55
+ json = eval_template(template).to_json
56
+
57
+ cf.should_receive(:validate_template).with(json) {
58
+ {
59
+ :code => 'CODE',
60
+ :message => 'MESSAGE'
61
+ }
62
+ }
63
+ end
64
+ }.to raise_error('CODE: MESSAGE')
65
+ end
66
+
67
+ it 'validate JSON template (without error)' do
68
+ template = <<-EOS
69
+ {
70
+ "Resources": {
71
+ "myEC2Instance": {
72
+ "Type": "AWS::EC2::Instance",
73
+ "Properties": {
74
+ "ImageId": "ami-XXXXXXXX",
75
+ "InstanceType": "t1.micro"
76
+ }
77
+ }
78
+ },
79
+ "AZ": {
80
+ "Value": {
81
+ "Fn::GetAtt": [
82
+ "myEC2Instance",
83
+ "AvailabilityZone"
84
+ ]
85
+ }
86
+ }
87
+ }
88
+ EOS
89
+
90
+ run_client(:validate, :template => template, :template_ext => '.template') do |client, cf|
91
+ json = JSON.parse(template).to_json
92
+
93
+ cf.should_receive(:validate_template).with(json) {
94
+ {}
95
+ }
96
+ end
97
+ end
98
+
99
+ it 'validate JSON template (with error)' do
100
+ template = <<-EOS
101
+ {
102
+ "Resources": {
103
+ "myEC2Instance": {
104
+ "Type": "AWS::EC2::Instance",
105
+ "Properties": {
106
+ "ImageId": "ami-XXXXXXXX",
107
+ "InstanceType": "t1.micro"
108
+ }
109
+ }
110
+ },
111
+ "AZ": {
112
+ "Value": {
113
+ "Fn::GetAtt": [
114
+ "myEC2Instance",
115
+ "AvailabilityZone"
116
+ ]
117
+ }
118
+ }
119
+ }
120
+ EOS
121
+
122
+ expect {
123
+ run_client(:validate, :template => template, :template_ext => '.template') do |client, cf|
124
+ json = JSON.parse(template).to_json
125
+
126
+ cf.should_receive(:validate_template).with(json) {
127
+ {
128
+ :code => 'CODE',
129
+ :message => 'MESSAGE'
130
+ }
131
+ }
132
+ end
133
+ }.to raise_error('CODE: MESSAGE')
134
+ end
135
+ end
@@ -0,0 +1,68 @@
1
+ require 'kumogata'
2
+ require 'tempfile'
3
+ require 'uuidtools'
4
+
5
+ class UUIDTools::UUID
6
+ def self.timestamp_create; 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'; end
7
+ end
8
+
9
+ def tempfile(content, template_ext)
10
+ basename = "#{File.basename __FILE__}.#{$$}"
11
+ basename = [basename, template_ext]
12
+
13
+ Tempfile.open(basename) do |f|
14
+ f << content
15
+ f.flush
16
+ f.rewind
17
+ yield(f)
18
+ end
19
+ end
20
+
21
+ def run_client(command, options = {})
22
+ $stdout = open('/dev/null', 'w')
23
+
24
+ kumogata_template = options[:template]
25
+ kumogata_arguments = options[:arguments] || []
26
+ kumogata_options = Kumogata::ArgumentParser::DEFAULT_OPTIONS.merge(options[:options] || {})
27
+ template_ext = options[:template_ext] || '.rb'
28
+
29
+ client = Kumogata::Client.new(kumogata_options)
30
+ cloud_formation = client.instance_variable_get(:@cloud_formation)
31
+ yield(client, cloud_formation) if block_given?
32
+
33
+ if kumogata_template
34
+ tempfile(kumogata_template, template_ext) do |f|
35
+ kumogata_arguments.unshift(f.path)
36
+ client.send(command, *kumogata_arguments)
37
+ end
38
+ else
39
+ client.send(command, *kumogata_arguments)
40
+ end
41
+ end
42
+
43
+ def eval_template(template, options = {})
44
+ kumogata_options = Kumogata::ArgumentParser::DEFAULT_OPTIONS.merge(options[:options] || {})
45
+ template_ext = options[:template_ext] || '.rb'
46
+
47
+ template = tempfile(template, template_ext) do |f|
48
+ Kumogata::Client.new(kumogata_options).send(:evaluate_template, f)
49
+ end
50
+
51
+ if options[:update_deletion_policy]
52
+ update_deletion_policy(template)
53
+ end
54
+
55
+ return template
56
+ end
57
+
58
+ def update_deletion_policy(template)
59
+ template['Resources'].each do |k, v|
60
+ v['DeletionPolicy'] = 'Retain'
61
+ end
62
+ end
63
+
64
+ def make_double(name)
65
+ obj = double(name)
66
+ yield(obj)
67
+ return obj
68
+ end