knife-cloudformation 0.0.1 → 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.
- data/CHANGELOG.md +3 -0
- data/knife-cloudformation-0.0.1.gem +0 -0
- data/lib/chef/knife/cloudformation_base.rb +28 -3
- data/lib/chef/knife/cloudformation_create.rb +114 -76
- data/lib/chef/knife/cloudformation_events.rb +2 -2
- data/lib/chef/knife/cloudformation_update.rb +31 -0
- data/lib/knife-cloudformation/sparkle_attribute.rb +67 -0
- data/lib/knife-cloudformation/sparkle_formation.rb +31 -0
- data/lib/knife-cloudformation/version.rb +1 -1
- metadata +5 -2
data/CHANGELOG.md
CHANGED
Binary file
|
@@ -2,6 +2,18 @@ require 'chef/knife'
|
|
2
2
|
|
3
3
|
class Chef
|
4
4
|
class Knife
|
5
|
+
|
6
|
+
# Populate up the hashes so they are available for knife config
|
7
|
+
# with issues of nils
|
8
|
+
['knife.cloudformation.credentials', 'knife.cloudformation.options'].each do |stack|
|
9
|
+
stack.split('.').inject(Chef::Config) do |memo, item|
|
10
|
+
memo[item.to_sym] = Mash.new unless memo[item.to_sym]
|
11
|
+
memo[item.to_sym]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
Chef::Config[:knife][:cloudformation] ||= Mash.new
|
16
|
+
|
5
17
|
module CloudformationDefault
|
6
18
|
class << self
|
7
19
|
def included(klass)
|
@@ -89,9 +101,13 @@ class Chef
|
|
89
101
|
|
90
102
|
def get_titles(thing, format=false)
|
91
103
|
unless(@titles)
|
92
|
-
|
93
|
-
|
94
|
-
|
104
|
+
attrs = allowed_attributes
|
105
|
+
if(attrs.empty?)
|
106
|
+
hash = thing.is_a?(Array) ? thing.first : thing
|
107
|
+
hash ||= {}
|
108
|
+
attrs = hash.keys
|
109
|
+
end
|
110
|
+
@titles = attrs.map do |key|
|
95
111
|
next unless attribute_allowed?(key)
|
96
112
|
key.gsub(/([a-z])([A-Z])/, '\1 \2')
|
97
113
|
end.compact
|
@@ -172,6 +188,15 @@ class Chef
|
|
172
188
|
JSON.read(thing)
|
173
189
|
end
|
174
190
|
end
|
191
|
+
|
192
|
+
def _format_json(thing)
|
193
|
+
thing = _from_json(thing) if thing.is_a?(String)
|
194
|
+
if(try_json_compat)
|
195
|
+
Chef::JSONCompat.to_json_pretty(thing)
|
196
|
+
else
|
197
|
+
JSON.pretty_generate(thing)
|
198
|
+
end
|
199
|
+
end
|
175
200
|
end
|
176
201
|
end
|
177
202
|
end
|
@@ -7,73 +7,91 @@ class Chef
|
|
7
7
|
|
8
8
|
banner 'knife cloudformation create NAME'
|
9
9
|
|
10
|
+
module Options
|
11
|
+
class << self
|
12
|
+
def included(klass)
|
13
|
+
klass.class_eval do
|
14
|
+
|
15
|
+
attr_accessor :action_type
|
16
|
+
|
17
|
+
option(:parameter,
|
18
|
+
:short => '-p KEY:VALUE',
|
19
|
+
:long => '--parameter KEY:VALUE',
|
20
|
+
:description => 'Set parameter. Can be used multiple times.',
|
21
|
+
:proc => lambda {|val|
|
22
|
+
key,value = val.split(':')
|
23
|
+
Chef::Config[:knife][:cloudformation][:options][:parameters] ||= Mash.new
|
24
|
+
Chef::Config[:knife][:cloudformation][:options][:parameters][key] = value
|
25
|
+
}
|
26
|
+
)
|
27
|
+
option(:timeout,
|
28
|
+
:short => '-t MIN',
|
29
|
+
:long => '--timeout MIN',
|
30
|
+
:description => 'Set timeout for stack creation',
|
31
|
+
:proc => lambda {|val|
|
32
|
+
Chef::Config[:knife][:cloudformation][:options][:timeout_in_minutes] = val
|
33
|
+
}
|
34
|
+
)
|
35
|
+
option(:disable_rollback,
|
36
|
+
:short => '-R',
|
37
|
+
:long => '--disable-rollback',
|
38
|
+
:description => 'Disable rollback on stack creation failure',
|
39
|
+
:proc => lambda {|val| Chef::Config[:knife][:cloudformation][:options][:disable_rollback] = true }
|
40
|
+
)
|
41
|
+
option(:capability,
|
42
|
+
:short => '-C CAPABILITY',
|
43
|
+
:long => '--capability CAPABILITY',
|
44
|
+
:description => 'Specify allowed capabilities. Can be used multiple times.',
|
45
|
+
:proc => lambda {|val|
|
46
|
+
Chef::Config[:knife][:cloudformation][:options][:capabilities] ||= []
|
47
|
+
Chef::Config[:knife][:cloudformation][:options][:capabilities].push(val).uniq!
|
48
|
+
}
|
49
|
+
)
|
50
|
+
option(:enable_processing,
|
51
|
+
:long => '--enable-processing',
|
52
|
+
:description => 'Call the unicorns.',
|
53
|
+
:proc => lambda {|val| Chef::Config[:knife][:cloudformation][:enable_processing] = true }
|
54
|
+
)
|
55
|
+
option(:disable_polling,
|
56
|
+
:long => '--disable-polling',
|
57
|
+
:description => 'Disable stack even polling.',
|
58
|
+
:proc => lambda {|val| Chef::Config[:knife][:cloudformation][:disable_polling] = true }
|
59
|
+
)
|
60
|
+
option(:notifications,
|
61
|
+
:long => '--notification ARN',
|
62
|
+
:description => 'Add notification ARN. Can be used multiple times.',
|
63
|
+
:proc => lambda {|val|
|
64
|
+
Chef::Config[:knife][:cloudformation][:options][:notification_ARNs] ||= []
|
65
|
+
Chef::Config[:knife][:cloudformation][:options][:notification_ARNs].push(val).uniq!
|
66
|
+
}
|
67
|
+
)
|
68
|
+
option(:file,
|
69
|
+
:short => '-f PATH',
|
70
|
+
:long => '--file PATH',
|
71
|
+
:description => 'Path to Cloud Formation to process',
|
72
|
+
:proc => lambda {|val|
|
73
|
+
Chef::Config[:knife][:cloudformation][:file] = val
|
74
|
+
}
|
75
|
+
)
|
76
|
+
option(:disable_interactive_parameters,
|
77
|
+
:long => '--no-parameter-prompts',
|
78
|
+
:description => 'Do not prompt for input on dynamic parameters'
|
79
|
+
)
|
80
|
+
|
81
|
+
option(:print_only,
|
82
|
+
:long => '--print-only',
|
83
|
+
:description => 'Print template and exit'
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
10
90
|
include CloudformationDefault
|
11
|
-
|
12
|
-
option(:parameter,
|
13
|
-
:short => '-p KEY:VALUE',
|
14
|
-
:long => '--parameter KEY:VALUE',
|
15
|
-
:description => 'Set parameter. Can be used multiple times.',
|
16
|
-
:proc => lambda {|val|
|
17
|
-
key,value = val.split(':')
|
18
|
-
Chef::Config[:knife][:cloudformation][:options][:parameters] ||= Mash.new
|
19
|
-
Chef::Config[:knife][:cloudformation][:options][:parameters][key] = value
|
20
|
-
}
|
21
|
-
)
|
22
|
-
option(:timeout,
|
23
|
-
:short => '-t MIN',
|
24
|
-
:long => '--timeout MIN',
|
25
|
-
:description => 'Set timeout for stack creation',
|
26
|
-
:proc => lambda {|val|
|
27
|
-
Chef::Config[:knife][:cloudformation][:options][:timeout_in_minutes] = val
|
28
|
-
}
|
29
|
-
)
|
30
|
-
option(:disable_rollback,
|
31
|
-
:short => '-R',
|
32
|
-
:long => '--disable-rollback',
|
33
|
-
:description => 'Disable rollback on stack creation failure',
|
34
|
-
:proc => lambda { Chef::Config[:knife][:cloudformation][:options][:disable_rollback] = true }
|
35
|
-
)
|
36
|
-
option(:capability,
|
37
|
-
:short => '-C CAPABILITY',
|
38
|
-
:long => '--capability CAPABILITY',
|
39
|
-
:description => 'Specify allowed capabilities. Can be used multiple times.',
|
40
|
-
:proc => lambda {|val|
|
41
|
-
Chef::Config[:knife][:cloudformation][:options][:capabilities] ||= []
|
42
|
-
Chef::Config[:knife][:cloudformation][:options][:capabilities].push(val).uniq!
|
43
|
-
}
|
44
|
-
)
|
45
|
-
option(:enable_processing,
|
46
|
-
:long => '--enable-processing',
|
47
|
-
:description => 'Call the unicorns.',
|
48
|
-
:proc => lambda { Chef::Config[:knife][:cloudformation][:options][:enable_processing] = true }
|
49
|
-
)
|
50
|
-
option(:disable_polling,
|
51
|
-
:long => '--disable-polling',
|
52
|
-
:description => 'Disable stack even polling.',
|
53
|
-
:proc => lambda { Chef::Config[:knife][:cloudformation][:options][:disable_polling] = true }
|
54
|
-
)
|
55
|
-
option(:notifications,
|
56
|
-
:long => '--notification ARN',
|
57
|
-
:description => 'Add notification ARN. Can be used multiple times.',
|
58
|
-
:proc => lambda {|val|
|
59
|
-
Chef::Config[:knife][:cloudformation][:options][:notification_ARNs] ||= []
|
60
|
-
Chef::Config[:knife][:cloudformation][:options][:notification_ARNs].push(val).uniq!
|
61
|
-
}
|
62
|
-
)
|
63
|
-
option(:file,
|
64
|
-
:short => '-F PATH',
|
65
|
-
:long => '--file PATH',
|
66
|
-
:description => 'Path to Cloud Formation to process',
|
67
|
-
:proc => lambda {|val|
|
68
|
-
Chef::Config[:knife][:cloudformation][:file] = val
|
69
|
-
}
|
70
|
-
)
|
71
|
-
option(:disable_interactive_parameters,
|
72
|
-
:long => '--no-parameter-prompts',
|
73
|
-
:description => 'Do not prompt for input on dynamic parameters'
|
74
|
-
)
|
91
|
+
include Options
|
75
92
|
|
76
93
|
def run
|
94
|
+
@action_type = self.class.name.split('::').last.sub('Cloudformation', '').upcase
|
77
95
|
unless(File.exists?(Chef::Config[:knife][:cloudformation][:file].to_s))
|
78
96
|
ui.fatal "Invalid formation file path provided: #{Chef::Config[:knife][:cloudformation][:file]}"
|
79
97
|
exit 1
|
@@ -82,26 +100,34 @@ class Chef
|
|
82
100
|
if(Chef::Config[:knife][:cloudformation][:enable_processing])
|
83
101
|
file = KnifeCloudformation::SparkleFormation.compile(Chef::Config[:knife][:cloudformation][:file])
|
84
102
|
else
|
85
|
-
file = File.read(Chef::Config[:knife][:cloudformation][:file])
|
103
|
+
file = _from_json(File.read(Chef::Config[:knife][:cloudformation][:file]))
|
86
104
|
end
|
87
|
-
ui.info "#{ui.color('Cloud Formation: ', :bold)} #{ui.color(
|
105
|
+
ui.info "#{ui.color('Cloud Formation: ', :bold)} #{ui.color(action_type, :green)}"
|
88
106
|
ui.info " -> #{ui.color('Name:', :bold)} #{name} #{ui.color('Path:', :bold)} #{Chef::Config[:knife][:cloudformation][:file]} #{ui.color('(not pre-processed)', :yellow) if Chef::Config[:knife][:cloudformation][:disable_processing]}"
|
89
107
|
stack = build_stack(file)
|
108
|
+
if(config[:print_only])
|
109
|
+
ui.warn 'Print only requested'
|
110
|
+
ui.info _format_json(stack['TemplateBody'])
|
111
|
+
exit 1
|
112
|
+
end
|
90
113
|
create_stack(name, stack)
|
91
114
|
unless(Chef::Config[:knife][:cloudformation][:disable_polling])
|
92
115
|
poll_stack(name)
|
93
116
|
else
|
94
117
|
ui.warn 'Stack state polling has been disabled.'
|
95
118
|
end
|
96
|
-
ui.info "Stack
|
119
|
+
ui.info "Stack #{action_type} complete: #{ui.color('SUCCESS', :green)}"
|
97
120
|
end
|
98
121
|
|
99
122
|
def build_stack(template)
|
100
123
|
stack = Mash.new
|
124
|
+
populate_parameters!(template)
|
101
125
|
Chef::Config[:knife][:cloudformation][:options].each do |key, value|
|
102
126
|
format_key = key.split('_').map(&:capitalize).join
|
127
|
+
stack[format_key] = value
|
128
|
+
=begin
|
103
129
|
case value
|
104
|
-
when Hash
|
130
|
+
when Hash && key.to_sym != :parameters
|
105
131
|
i = 1
|
106
132
|
value.each do |k, v|
|
107
133
|
stack["#{format_key}.member.#{i}.#{format_key[0, (format_key.length - 1)]}Key"] = k
|
@@ -112,14 +138,26 @@ class Chef
|
|
112
138
|
stack["#{format_key}.member.#{i+1}"] = v
|
113
139
|
end
|
114
140
|
else
|
115
|
-
|
141
|
+
|
116
142
|
end
|
143
|
+
=end
|
117
144
|
end
|
118
|
-
|
145
|
+
enable_capabilities!(stack, template)
|
119
146
|
stack['TemplateBody'] = Chef::JSONCompat.to_json(template)
|
120
147
|
stack
|
121
148
|
end
|
122
149
|
|
150
|
+
# Currently only checking for IAM resources since that's all
|
151
|
+
# that is supported for creation
|
152
|
+
def enable_capabilities!(stack, template)
|
153
|
+
found = Array(template['Resources']).detect do |resource_name, resource|
|
154
|
+
resource['Type'].start_with?('AWS::IAM')
|
155
|
+
end
|
156
|
+
if(found)
|
157
|
+
stack['Capabilities'] = ['CAPABILITY_IAM']
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
123
161
|
def populate_parameters!(stack)
|
124
162
|
unless(config[:disable_interactive_parameters])
|
125
163
|
if(stack['Parameters'])
|
@@ -149,8 +187,8 @@ class Chef
|
|
149
187
|
begin
|
150
188
|
res = aws_con.create_stack(name, stack)
|
151
189
|
rescue => e
|
152
|
-
ui.fatal "Failed to
|
153
|
-
_debug(e, "Generated template used:\n#{stack
|
190
|
+
ui.fatal "Failed to #{action_type} stack #{name}. Reason: #{e}"
|
191
|
+
_debug(e, "Generated template used:\n#{_format_json(stack['TemplateBody'])}")
|
154
192
|
exit 1
|
155
193
|
end
|
156
194
|
end
|
@@ -160,17 +198,17 @@ class Chef
|
|
160
198
|
knife_events.name_args.push(name)
|
161
199
|
Chef::Config[:knife][:cloudformation][:poll] = true
|
162
200
|
knife_events.run
|
163
|
-
unless(
|
164
|
-
ui.fatal "
|
201
|
+
unless(action_successful?(name))
|
202
|
+
ui.fatal "#{action_type} of new stack #{ui.color(name, :bold)}: #{ui.color('FAILED', :red, :bold)}"
|
165
203
|
exit 1
|
166
204
|
end
|
167
205
|
end
|
168
206
|
|
169
|
-
def
|
207
|
+
def action_in_progress?(name)
|
170
208
|
stack_status(name) == 'CREATE_IN_PROGRESS'
|
171
209
|
end
|
172
210
|
|
173
|
-
def
|
211
|
+
def action_successful?(name)
|
174
212
|
stack_status(name) == 'CREATE_COMPLETE'
|
175
213
|
end
|
176
214
|
end
|
@@ -63,7 +63,7 @@ class Chef
|
|
63
63
|
unless(output.empty?)
|
64
64
|
ui.info ui.list(output, :uneven_columns_across, allowed_attributes.size)
|
65
65
|
end
|
66
|
-
sleep(
|
66
|
+
sleep((ENV['CLOUDFORMATION_POLL'] || 15).to_i)
|
67
67
|
end
|
68
68
|
# One more to see completion
|
69
69
|
events = stack_events(name)
|
@@ -78,7 +78,7 @@ class Chef
|
|
78
78
|
end
|
79
79
|
|
80
80
|
def default_attributes
|
81
|
-
%w(Timestamp LogicalResourceId ResourceType ResourceStatus)
|
81
|
+
%w(Timestamp LogicalResourceId ResourceType ResourceStatus ResourceStatusReason)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'chef/knife/cloudformation_create'
|
2
|
+
|
3
|
+
class Chef
|
4
|
+
class Knife
|
5
|
+
class CloudformationUpdate < CloudformationCreate
|
6
|
+
banner 'knife cloudformation update NAME'
|
7
|
+
|
8
|
+
include CloudformationDefault
|
9
|
+
include CloudformationCreate::Options
|
10
|
+
|
11
|
+
def create_stack(name, stack)
|
12
|
+
begin
|
13
|
+
res = aws_con.update_stack(name, stack)
|
14
|
+
rescue => e
|
15
|
+
ui.fatal "Failed to update stack #{name}. Reason: #{e}"
|
16
|
+
_debug(e, "Generated template used:\n#{_format_json(stack['TemplateBody'])}")
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def action_in_progress?(name)
|
22
|
+
stack_status(name) == 'UPDATE_IN_PROGRESS'
|
23
|
+
end
|
24
|
+
|
25
|
+
def action_successful?(name)
|
26
|
+
stack_status(name) == 'UPDATE_COMPLETE'
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'attribute_struct'
|
2
|
+
|
3
|
+
module SparkleAttribute
|
4
|
+
|
5
|
+
# TODO: look at the docs for Fn stuff. We can probably just map
|
6
|
+
# simple ones with a bit of string manipulations
|
7
|
+
|
8
|
+
def _cf_join(*args)
|
9
|
+
options = args.detect{|i| i.is_a?(Hash) && i[:options]} || {:options => {}}
|
10
|
+
args.delete(options)
|
11
|
+
unless(args.size == 1)
|
12
|
+
args = [args]
|
13
|
+
end
|
14
|
+
{'Fn::Join' => [options[:options][:delimiter] || '', *args]}
|
15
|
+
end
|
16
|
+
|
17
|
+
def _cf_ref(thing)
|
18
|
+
thing = _process_key(thing, :force) if thing.is_a?(Symbol)
|
19
|
+
{'Ref' => thing}
|
20
|
+
end
|
21
|
+
|
22
|
+
def _cf_map(thing, key, *suffix)
|
23
|
+
suffix = suffix.map do |item|
|
24
|
+
if(item.is_a?(Symbol))
|
25
|
+
_process_key(item, :force)
|
26
|
+
else
|
27
|
+
item
|
28
|
+
end
|
29
|
+
end
|
30
|
+
thing = _process_key(thing, :force) if thing.is_a?(Symbol)
|
31
|
+
key = _process_key(key, :force) if key.is_a?(Symbol)
|
32
|
+
{'Fn::FindInMap' => [_process_key(thing), {'Ref' => _process_key(key)}, *suffix]}
|
33
|
+
end
|
34
|
+
|
35
|
+
def _cf_attr(*args)
|
36
|
+
args = args.map do |thing|
|
37
|
+
if(thing.is_a?(Symbol))
|
38
|
+
_process_key(thing, :force)
|
39
|
+
else
|
40
|
+
thing
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
{'Fn::GetAtt' => args}
|
45
|
+
end
|
46
|
+
|
47
|
+
def _cf_base64(arg)
|
48
|
+
{'Fn::Base64' => arg}
|
49
|
+
end
|
50
|
+
|
51
|
+
def rhel?
|
52
|
+
!!@platform[:rhel]
|
53
|
+
end
|
54
|
+
|
55
|
+
def debian?
|
56
|
+
!!@platform[:debian]
|
57
|
+
end
|
58
|
+
|
59
|
+
def _platform=(plat)
|
60
|
+
@platform || __hashish
|
61
|
+
@platform.clear
|
62
|
+
@platform[plat.to_sym] = true
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
AttributeStruct.send(:include, SparkleAttribute)
|
@@ -1,11 +1,15 @@
|
|
1
1
|
require 'chef/mash'
|
2
2
|
require 'attribute_struct'
|
3
|
+
require 'knife-cloudformation/sparkle_attribute'
|
3
4
|
|
4
5
|
AttributeStruct.camel_keys = true
|
5
6
|
|
6
7
|
module KnifeCloudformation
|
7
8
|
class SparkleFormation
|
8
9
|
class << self
|
10
|
+
|
11
|
+
attr_reader :dynamics
|
12
|
+
|
9
13
|
def compile(path)
|
10
14
|
formation = self.instance_eval(IO.read(path), path, 1)
|
11
15
|
formation.compile._dump
|
@@ -21,6 +25,31 @@ module KnifeCloudformation
|
|
21
25
|
self.instance_eval(IO.read(path), path, 1)
|
22
26
|
end
|
23
27
|
|
28
|
+
def load_dynamics!(directory)
|
29
|
+
@loaded_dynamics ||= []
|
30
|
+
Dir.glob(File.join(directory, '*.rb')).each do |dyn|
|
31
|
+
dyn = File.expand_path(dyn)
|
32
|
+
next if @loaded_dynamics.include?(dyn)
|
33
|
+
self.instance_eval(IO.read(dyn), dyn, 1)
|
34
|
+
@loaded_dynamics << dyn
|
35
|
+
end
|
36
|
+
@loaded_dynamics.uniq!
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def dynamic(name, &block)
|
41
|
+
@dynamics ||= Mash.new
|
42
|
+
@dynamics[name] = block
|
43
|
+
end
|
44
|
+
|
45
|
+
def insert(dynamic_name, struct, *args)
|
46
|
+
if(@dynamics && @dynamics[dynamic_name])
|
47
|
+
struct.instance_exec(*args, &@dynamics[dynamic_name])
|
48
|
+
struct
|
49
|
+
else
|
50
|
+
raise "Failed to locate requested dynamic block for insertion: #{dynamic_name} (valid: #{@dynamics.keys.sort.join(', ')})"
|
51
|
+
end
|
52
|
+
end
|
24
53
|
end
|
25
54
|
|
26
55
|
attr_reader :name
|
@@ -31,6 +60,8 @@ module KnifeCloudformation
|
|
31
60
|
def initialize(name, options={})
|
32
61
|
@name = name
|
33
62
|
@sparkle_path = options[:sparkle_path] || File.join(Dir.pwd, 'cloudformation/components')
|
63
|
+
@dynamics_directory = options[:dynamics_directory] || File.join(File.dirname(@sparkle_path), 'dynamics')
|
64
|
+
self.class.load_dynamics!(@dynamics_directory)
|
34
65
|
@components = Mash.new
|
35
66
|
@load_order = []
|
36
67
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: knife-cloudformation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-08-02 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: chef
|
@@ -71,11 +71,14 @@ files:
|
|
71
71
|
- lib/chef/knife/cloudformation_describe.rb
|
72
72
|
- lib/chef/knife/cloudformation_list.rb
|
73
73
|
- lib/chef/knife/cloudformation_create.rb
|
74
|
+
- lib/chef/knife/cloudformation_update.rb
|
74
75
|
- lib/knife-cloudformation.rb
|
76
|
+
- lib/knife-cloudformation/sparkle_attribute.rb
|
75
77
|
- lib/knife-cloudformation/version.rb
|
76
78
|
- lib/knife-cloudformation/sparkle_formation.rb
|
77
79
|
- README.md
|
78
80
|
- knife-cloudformation.gemspec
|
81
|
+
- knife-cloudformation-0.0.1.gem
|
79
82
|
- CHANGELOG.md
|
80
83
|
homepage: http://github.com/heavywater/knife-cloudformation
|
81
84
|
licenses: []
|