aws-sdk-utils 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/cfndsl_converge +3 -1
- data/lib/aws-sdk-utils.rb +2 -1
- data/lib/cfndsl_converger.rb +16 -3
- data/lib/changeset_util.rb +76 -0
- data/lib/cloudformation_tag_parser.rb +22 -0
- metadata +6 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcde772fb63322ea4c57c8f4578898dc05e2aa8a
|
4
|
+
data.tar.gz: ec27fb8da8367e39837598da893fad40be6cc959
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93204c776fc345624600d8fc18147f3d0307fb7abb72ecb1f9ecb9724240366c9e8457c669f4997da7e4428c7aa178a1369f18f6a39813db450a0b15fd2624c4
|
7
|
+
data.tar.gz: f61f02e3d0a141c1de16c1a797cfd28292b3978a9bc7bcad6ef20c48dedb86258adeaf04541abef977b4f697c96bfd6340f55978c05f0f19d1e07dd112528a93
|
data/bin/cfndsl_converge
CHANGED
@@ -7,12 +7,14 @@ opts = Trollop::options do
|
|
7
7
|
opt :path_to_stack, '', type: :string, required: true
|
8
8
|
opt :stack_name, '', type: :string, required: true
|
9
9
|
opt :path_to_yaml, '', type: :string, required: false
|
10
|
+
opt :fail_on_changes_to_immutable_resource, '', type: :boolean, default: false, required: false
|
10
11
|
end
|
11
12
|
|
12
13
|
bindings = opts[:path_to_yaml].nil? ? nil : YAML.load_file(opts[:path_to_yaml])
|
13
14
|
|
14
15
|
outputs = CfndslConverger.new.converge(stack_name: opts[:stack_name],
|
15
16
|
path_to_stack: opts[:path_to_stack],
|
16
|
-
bindings: bindings
|
17
|
+
bindings: bindings,
|
18
|
+
fail_on_changes_to_immutable_resource: opts[:fail_on_changes_to_immutable_resource])
|
17
19
|
|
18
20
|
puts outputs.to_yaml
|
data/lib/aws-sdk-utils.rb
CHANGED
data/lib/cfndsl_converger.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'aws-sdk'
|
2
2
|
require 'cfndsl'
|
3
3
|
require 'tempfile'
|
4
|
+
require 'changeset_util'
|
4
5
|
|
5
6
|
class CfndslConverger
|
6
7
|
|
@@ -18,7 +19,8 @@ class CfndslConverger
|
|
18
19
|
|
19
20
|
def converge(stack_name:,
|
20
21
|
path_to_stack:,
|
21
|
-
bindings: nil
|
22
|
+
bindings: nil,
|
23
|
+
fail_on_changes_to_immutable_resource: false)
|
22
24
|
extras = []
|
23
25
|
unless bindings.nil?
|
24
26
|
temp_file = Tempfile.new('cfnstackfortesting')
|
@@ -33,8 +35,19 @@ class CfndslConverger
|
|
33
35
|
extras,
|
34
36
|
verbose)
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
+
if fail_on_changes_to_immutable_resource
|
39
|
+
unsafe_logical_resource_id = ChangesetUtil.new.immutable_resources_that_would_change stack_name: stack_name,
|
40
|
+
template_body: model.to_json
|
41
|
+
if unsafe_logical_resource_id.nil?
|
42
|
+
outputs = converge_stack stack_name: stack_name,
|
43
|
+
stack_body: model.to_json
|
44
|
+
else
|
45
|
+
raise "update would modify or delete immutable resource #{unsafe_logical_resource_id}"
|
46
|
+
end
|
47
|
+
else
|
48
|
+
outputs = converge_stack stack_name: stack_name,
|
49
|
+
stack_body: model.to_json
|
50
|
+
end
|
38
51
|
outputs
|
39
52
|
end
|
40
53
|
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require_relative 'cloudformation_tag_parser'
|
2
|
+
require 'aws-sdk'
|
3
|
+
|
4
|
+
class ChangesetUtil
|
5
|
+
|
6
|
+
def immutable_resources_that_would_change(stack_name:,
|
7
|
+
template_body:)
|
8
|
+
|
9
|
+
potentially_unsafe_changes = changes_that_modify_or_remove stack_name: stack_name,
|
10
|
+
template_body: template_body
|
11
|
+
|
12
|
+
logical_resource_ids = potentially_unsafe_changes.map { |change| change.resource_change.logical_resource_id }
|
13
|
+
|
14
|
+
logical_resource_ids.each do |logical_resource_id|
|
15
|
+
tags = CloudFormationTagParser.new.tags cloudformation_json: template_body,
|
16
|
+
logical_resource_id: logical_resource_id
|
17
|
+
if tags.find { |tag| tag['Key'] == 'immutable' and tag['Value'] == 'true' }
|
18
|
+
return logical_resource_id
|
19
|
+
end
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
|
24
|
+
|
25
|
+
##
|
26
|
+
# hmmmm how to handle parameters? if it uses the previous value...?
|
27
|
+
#
|
28
|
+
def changes_that_modify_or_remove(stack_name:,
|
29
|
+
template_body:,
|
30
|
+
parameters: [])
|
31
|
+
|
32
|
+
change_set_name = "changeSet#{Time.now.to_i}"
|
33
|
+
client_token = "clientToken#{Time.now.to_i}"
|
34
|
+
|
35
|
+
create_change_set_response = cloudformation_client.create_change_set stack_name: stack_name,
|
36
|
+
template_body: template_body,
|
37
|
+
capabilities: %w(CAPABILITY_IAM),
|
38
|
+
change_set_name: change_set_name,
|
39
|
+
client_token: client_token,
|
40
|
+
parameters: convert_parameters(parameters)
|
41
|
+
|
42
|
+
change_set_id = create_change_set_response.id
|
43
|
+
|
44
|
+
describe_change_set_response = describe_change_set change_set_id: change_set_id
|
45
|
+
|
46
|
+
describe_change_set_response.changes.select { |change| %w(Modify Remove).include? change.resource_change.action }
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def describe_change_set(change_set_id:)
|
52
|
+
done = false
|
53
|
+
while not done
|
54
|
+
describe_change_set_response = cloudformation_client.describe_change_set change_set_name: change_set_id
|
55
|
+
done = %w(CREATE_COMPLETE FAILED).include?(describe_change_set_response.status)
|
56
|
+
sleep 10 unless done
|
57
|
+
end
|
58
|
+
describe_change_set_response
|
59
|
+
end
|
60
|
+
|
61
|
+
def cloudformation_client
|
62
|
+
Aws::CloudFormation::Client.new
|
63
|
+
end
|
64
|
+
|
65
|
+
def convert_parameters(parameters)
|
66
|
+
result = []
|
67
|
+
parameters.each do |key, value|
|
68
|
+
result << {
|
69
|
+
parameter_key: key,
|
70
|
+
parameter_value: value,
|
71
|
+
use_previous_value: false
|
72
|
+
}
|
73
|
+
end
|
74
|
+
result
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
class CloudFormationTagParser
|
4
|
+
|
5
|
+
def tags(cloudformation_json:,
|
6
|
+
logical_resource_id:)
|
7
|
+
|
8
|
+
cloudformation = JSON.load(cloudformation_json)
|
9
|
+
if cloudformation['Resources'].nil?
|
10
|
+
raise 'malformed json, must have Resources key at least'
|
11
|
+
end
|
12
|
+
|
13
|
+
resource = cloudformation['Resources'][logical_resource_id]
|
14
|
+
if resource.nil?
|
15
|
+
raise "logical resource id #{logical_resource_id} is not found"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Properties isn't there is a blow error, but jsut ignore that... need a better all-round parser for cfn in the first place
|
19
|
+
tags = resource['Properties']['Tags']
|
20
|
+
tags.nil? ? [] : tags
|
21
|
+
end
|
22
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-sdk-utils
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- someguy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.2.
|
19
|
+
version: 2.2.31
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.2.
|
26
|
+
version: 2.2.31
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: cfndsl
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -64,7 +64,9 @@ files:
|
|
64
64
|
- bin/yaml_get
|
65
65
|
- lib/aws-sdk-utils.rb
|
66
66
|
- lib/cfndsl_converger.rb
|
67
|
+
- lib/changeset_util.rb
|
67
68
|
- lib/cloudformation_converger.rb
|
69
|
+
- lib/cloudformation_tag_parser.rb
|
68
70
|
- lib/lambda_alias_switcher.rb
|
69
71
|
- lib/waf_util.rb
|
70
72
|
homepage: https://github.com/stelligent/aws-sdk-utils
|