forked from sous-chefs/aws
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcloudformation_stack.rb
More file actions
115 lines (102 loc) · 3.79 KB
/
Copy pathcloudformation_stack.rb
File metadata and controls
115 lines (102 loc) · 3.79 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
property :stack_name, String, name_property: true
# location of the template body, located in the "files" cookbook dir
property :template_source, String, required: true
property :parameters, Array, default: []
property :disable_rollback, [true, false], default: false
property :iam_capability, [true, false], default: false
property :named_iam_capability, [true, false], default: false
property :stack_policy_body, String
property :region, String, default: lazy { fallback_region }
# authentication
property :aws_access_key, String
property :aws_secret_access_key, String, sensitive: true
property :aws_session_token, String, sensitive: true
property :aws_assume_role_arn, String
property :aws_role_session_name, String
include AwsCookbook::Ec2 # needed for aws_region helper
action :create do
load_template_path
if stack_exists?(new_resource.stack_name)
# only update if stack changed
if cfn_stack_changed? || cfn_params_chagned?
converge_by("update stack #{new_resource.stack_name}") do
options = build_cfn_options
options.delete(:disable_rollback)
cfn.update_stack(options)
end
end
else
converge_by("create stack #{new_resource.stack_name}") do
options = build_cfn_options
cfn.create_stack(options)
end
end
end
action :delete do
if stack_exists?(new_resource.stack_name)
converge_by("delete stack #{new_resource.stack_name}") do
cfn.delete_stack(stack_name: new_resource.stack_name)
end
end
end
action_class do
include AwsCookbook::Ec2
require 'fileutils'
def cfn
require 'aws-sdk-cloudformation'
Chef::Log.debug('Initializing the CloudFormation Client')
@cfn ||= create_aws_interface(::Aws::CloudFormation::Client, region: new_resource.region)
end
def load_template_path
cookbook = run_context.cookbook_collection[new_resource.cookbook_name]
file_cache_location = cookbook.preferred_filename_on_disk_location(run_context.node, :files, new_resource.template_source)
if file_cache_location.nil?
raise "Cannot find #{new_resource.template_source} in cookbook!"
else
@template_path = file_cache_location
end
end
# build_cfn_options - build options hash for create_stack based off of
# new_resource data
def build_cfn_options
options = {
stack_name: new_resource.stack_name,
# make sure you call this after you save the file
template_body: ::IO.read(@template_path),
parameters: new_resource.parameters,
disable_rollback: new_resource.disable_rollback,
capabilities: [],
}
options[:stack_policy_body] = new_resource.stack_policy_body unless new_resource.stack_policy_body.nil?
options[:capabilities] << 'CAPABILITY_IAM' if new_resource.iam_capability
options[:capabilities] << 'CAPABILITY_NAMED_IAM' if new_resource.named_iam_capability
options
end
# cfn_stack_changed - get the stack JSON, and compare with local template
def cfn_stack_changed?
resp = cfn.get_template(stack_name: new_resource.stack_name)
!(resp.template_body == ::IO.read(@template_path))
end
# cfn_params_chagned - see if parameters have updated
def cfn_params_chagned?
resp = cfn.describe_stacks(stack_name: new_resource.stack_name)
resp.stacks[0].parameters.each do |existing_param|
new_params = new_resource.parameters
index = new_params.index { |x| x[:parameter_key] == existing_param[:parameter_key] }
next if index.nil?
return true unless new_params[index][:parameter_value] == existing_param[:parameter_value]
end
false
end
# does_stack_exist - logic for checking if the stack exists
def stack_exists?(stack_name)
resp = cfn.describe_stacks(stack_name: stack_name)
if !resp.empty?
true
else
false
end
rescue ::Aws::CloudFormation::Errors::ValidationError
false
end
end