knife-cloudformation 0.2.24 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/README.md +16 -0
- data/knife-cloudformation.gemspec +14 -4
- data/lib/knife-cloudformation.rb +0 -28
- data/lib/knife-cloudformation/version.rb +1 -1
- metadata +18 -80
- data/lib/chef/knife/cloudformation_create.rb +0 -147
- data/lib/chef/knife/cloudformation_describe.rb +0 -99
- data/lib/chef/knife/cloudformation_destroy.rb +0 -84
- data/lib/chef/knife/cloudformation_events.rb +0 -117
- data/lib/chef/knife/cloudformation_export.rb +0 -162
- data/lib/chef/knife/cloudformation_import.rb +0 -141
- data/lib/chef/knife/cloudformation_inspect.rb +0 -206
- data/lib/chef/knife/cloudformation_list.rb +0 -72
- data/lib/chef/knife/cloudformation_promote.rb +0 -40
- data/lib/chef/knife/cloudformation_update.rb +0 -137
- data/lib/chef/knife/cloudformation_validate.rb +0 -36
- data/lib/knife-cloudformation/cache.rb +0 -385
- data/lib/knife-cloudformation/knife.rb +0 -9
- data/lib/knife-cloudformation/knife/base.rb +0 -195
- data/lib/knife-cloudformation/knife/stack.rb +0 -197
- data/lib/knife-cloudformation/knife/template.rb +0 -213
- data/lib/knife-cloudformation/monkey_patch.rb +0 -8
- data/lib/knife-cloudformation/monkey_patch/stack.rb +0 -195
- data/lib/knife-cloudformation/provider.rb +0 -225
- data/lib/knife-cloudformation/utils.rb +0 -24
- data/lib/knife-cloudformation/utils/animal_strings.rb +0 -28
- data/lib/knife-cloudformation/utils/debug.rb +0 -31
- data/lib/knife-cloudformation/utils/json.rb +0 -64
- data/lib/knife-cloudformation/utils/object_storage.rb +0 -28
- data/lib/knife-cloudformation/utils/output.rb +0 -79
- data/lib/knife-cloudformation/utils/path_selector.rb +0 -99
- data/lib/knife-cloudformation/utils/ssher.rb +0 -29
- data/lib/knife-cloudformation/utils/stack_exporter.rb +0 -271
- data/lib/knife-cloudformation/utils/stack_parameter_scrubber.rb +0 -37
- data/lib/knife-cloudformation/utils/stack_parameter_validator.rb +0 -124
@@ -1,206 +0,0 @@
|
|
1
|
-
require 'knife-cloudformation'
|
2
|
-
|
3
|
-
class Chef
|
4
|
-
class Knife
|
5
|
-
# Cloudformation inspect command
|
6
|
-
class CloudformationInspect < Knife
|
7
|
-
|
8
|
-
include KnifeCloudformation::Knife::Base
|
9
|
-
include KnifeCloudformation::Utils::Ssher
|
10
|
-
|
11
|
-
banner 'knife cloudformation inspect NAME'
|
12
|
-
|
13
|
-
option(:attribute,
|
14
|
-
:short => '-a ATTR',
|
15
|
-
:long => '--attribute ATTR',
|
16
|
-
:description => 'Dot delimited attribute to view'
|
17
|
-
)
|
18
|
-
|
19
|
-
option(:nodes,
|
20
|
-
:short => '-N',
|
21
|
-
:long => '--[no-]nodes',
|
22
|
-
:boolean => true,
|
23
|
-
:description => 'Locate all instances'
|
24
|
-
)
|
25
|
-
|
26
|
-
option(:instance_failure,
|
27
|
-
:short => '-I [LOG_FILE_PATH]',
|
28
|
-
:long => '--instance-failure [LOG_FILE_PATH]',
|
29
|
-
:descrption => 'Display chef log file (defaults /var/log/chef/client.log)',
|
30
|
-
:proc => lambda{|val|
|
31
|
-
Chef::Config[:knife][:cloudformation][:failure_log_path] = val
|
32
|
-
}
|
33
|
-
)
|
34
|
-
|
35
|
-
option(:identity_file,
|
36
|
-
:short => '-i IDENTITY_FILE',
|
37
|
-
:long => '--identity-file IDENTITY_FILE',
|
38
|
-
:description => 'SSH identity file for authentication',
|
39
|
-
:proc => lambda{|val|
|
40
|
-
Chef::Config[:knife][:cloudformation][:identity_file] = val
|
41
|
-
}
|
42
|
-
)
|
43
|
-
|
44
|
-
option(:ssh_user,
|
45
|
-
:short => '-x SSH_USER',
|
46
|
-
:long => '--ssh-user SSH_USER',
|
47
|
-
:description => 'SSH username for inspection connect',
|
48
|
-
:proc => lambda{|val|
|
49
|
-
Chef::Config[:knife][:cloudformation][:ssh_user] = val
|
50
|
-
}
|
51
|
-
)
|
52
|
-
|
53
|
-
# Run the stack inspection action
|
54
|
-
def _run
|
55
|
-
stack_name = name_args.last
|
56
|
-
stack = provider.connection.stacks.get(stack_name)
|
57
|
-
ui.info "Stack inspection #{ui.color(stack_name, :bold)}:"
|
58
|
-
outputs = [:attribute, :nodes, :instance_failure].map do |key|
|
59
|
-
if(config.has_key?(key))
|
60
|
-
send("display_#{key}", stack)
|
61
|
-
key
|
62
|
-
end
|
63
|
-
end.compact
|
64
|
-
if(outputs.empty?)
|
65
|
-
ui.info ' Stack dump:'
|
66
|
-
ui.info MultiJson.dump(
|
67
|
-
MultiJson.load(
|
68
|
-
stack.reload.to_json
|
69
|
-
),
|
70
|
-
:pretty => true
|
71
|
-
)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def display_instance_failure(stack)
|
76
|
-
instances = stack.resources.all.find_all do |resource|
|
77
|
-
resource.state.to_s.end_with?('failed')
|
78
|
-
end.map do |resource|
|
79
|
-
# If compute instance, simply expand
|
80
|
-
if(resource.within?(:compute, :servers))
|
81
|
-
resource.instance
|
82
|
-
# If a waitcondition, check for instance ID
|
83
|
-
elsif(resource.type.to_s.downcase.end_with?('waitcondition'))
|
84
|
-
if(resource.status_reason.to_s.include?('uniqueId'))
|
85
|
-
srv_id = resource.status_reason.split(' ').last.strip
|
86
|
-
provider.connection.api_for(:compute).servers.get(srv_id)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end.compact
|
90
|
-
if(instances.empty?)
|
91
|
-
ui.error 'Failed to locate any failed instances'
|
92
|
-
else
|
93
|
-
log_path = Chef::Config[:knife][:cloudformation][:failure_log_path]
|
94
|
-
if(log_path.to_s.empty?)
|
95
|
-
log_path = '/var/log/chef/client.log'
|
96
|
-
end
|
97
|
-
opts = ssh_key ? {:keys => [ssh_key]} : {}
|
98
|
-
instances.each do |instance|
|
99
|
-
ui.info " -> Log inspect for #{instance.id}:"
|
100
|
-
address = instance.addresses_public.map do |address|
|
101
|
-
if(address.version == 4)
|
102
|
-
address.address
|
103
|
-
end
|
104
|
-
end
|
105
|
-
if(address)
|
106
|
-
ssh_attempt_users.each do |user|
|
107
|
-
begin
|
108
|
-
ui.info remote_file_contents(address.first, user, log_path, opts)
|
109
|
-
break
|
110
|
-
rescue Net::SSH::AuthenticationFailed
|
111
|
-
ui.warn "Authentication failed for user #{user} on instance #{address}"
|
112
|
-
rescue => e
|
113
|
-
ui.error "Failed to retrieve log: #{e}"
|
114
|
-
_debug e
|
115
|
-
break
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
# Users to attempt SSH connection
|
124
|
-
#
|
125
|
-
# @return [Array<String>] usernames for ssh connect attempt
|
126
|
-
def ssh_attempt_users
|
127
|
-
base_user = Chef::Config[:knife][:cloudformation][:ssh_user] ||
|
128
|
-
Chef::Config[:knife][:ssh_user] ||
|
129
|
-
ENV['USER']
|
130
|
-
[base_user, Chef::Config[:knife][:cloudformation][:ssh_attempt_users]].flatten.compact
|
131
|
-
end
|
132
|
-
|
133
|
-
def ssh_key
|
134
|
-
Chef::Config[:knife][:cloudformation][:identity_file] ||
|
135
|
-
Chef::Config[:knife][:identity_file]
|
136
|
-
end
|
137
|
-
|
138
|
-
def display_attribute(stack)
|
139
|
-
attr = config[:attribute].split('.').inject(stack) do |memo, key|
|
140
|
-
args = key.scan(/\(([^)]*)\)/).flatten.first.to_s
|
141
|
-
if(args)
|
142
|
-
args = args.split(',').map{|a| a.to_i.to_s == a ? a.to_i : a}
|
143
|
-
key = key.split('(').first
|
144
|
-
end
|
145
|
-
if(memo.public_methods.include?(key.to_sym))
|
146
|
-
if(args.size == 1 && args.first.to_s.start_with?('&'))
|
147
|
-
memo.send(key, &args.first.slice(2, args.first.size).to_sym)
|
148
|
-
else
|
149
|
-
memo.send(*[key, args].flatten.compact)
|
150
|
-
end
|
151
|
-
else
|
152
|
-
raise NoMethodError.new "Invalid attribute requested! (#{memo.class}##{key})"
|
153
|
-
end
|
154
|
-
end
|
155
|
-
ui.info " Attribute Lookup -> #{config[:attribute]}:"
|
156
|
-
ui.info MultiJson.dump(
|
157
|
-
MultiJson.load(
|
158
|
-
MultiJson.dump(attr)
|
159
|
-
),
|
160
|
-
:pretty => true
|
161
|
-
)
|
162
|
-
end
|
163
|
-
|
164
|
-
def display_nodes(stack)
|
165
|
-
asg_nodes = Smash[
|
166
|
-
stack.resources.all.find_all do |resource|
|
167
|
-
resource.within?(:auto_scale, :groups)
|
168
|
-
end.map do |group_resource|
|
169
|
-
asg = group_resource.expand
|
170
|
-
[
|
171
|
-
asg.name,
|
172
|
-
Smash[
|
173
|
-
asg.servers.map(&:expand).map{|s|
|
174
|
-
[s.id, Smash.new(
|
175
|
-
:name => s.name,
|
176
|
-
:addresses => s.addresses.map(&:address)
|
177
|
-
)]
|
178
|
-
}
|
179
|
-
]
|
180
|
-
]
|
181
|
-
end
|
182
|
-
]
|
183
|
-
compute_nodes = Smash[
|
184
|
-
stack.resources.all.find_all do |resource|
|
185
|
-
resource.within?(:compute, :servers)
|
186
|
-
end.map do |srv|
|
187
|
-
srv = srv.instance
|
188
|
-
[srv.id, Smash.new(
|
189
|
-
:name => srv.name,
|
190
|
-
:addresses => srv.addresses.map(&:address)
|
191
|
-
)]
|
192
|
-
end
|
193
|
-
]
|
194
|
-
unless(asg_nodes.empty?)
|
195
|
-
ui.info ' AutoScale Group Instances:'
|
196
|
-
ui.info MultiJson.dump(asg_nodes, :pretty => true)
|
197
|
-
end
|
198
|
-
unless(compute_nodes.empty?)
|
199
|
-
ui.info ' Compute Instances:'
|
200
|
-
ui.info MultiJson.dump(compute_nodes, :pretty => true)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
end
|
205
|
-
end
|
206
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
require 'knife-cloudformation'
|
2
|
-
|
3
|
-
class Chef
|
4
|
-
class Knife
|
5
|
-
# Cloudformation list command
|
6
|
-
class CloudformationList < Knife
|
7
|
-
|
8
|
-
include KnifeCloudformation::Knife::Base
|
9
|
-
|
10
|
-
banner 'knife cloudformation list NAME'
|
11
|
-
|
12
|
-
option(:attribute,
|
13
|
-
:short => '-a ATTR',
|
14
|
-
:long => '--attribute ATTR',
|
15
|
-
:description => 'Attribute to print. Can be used multiple times.',
|
16
|
-
:proc => lambda {|val|
|
17
|
-
Chef::Config[:knife][:cloudformation][:attributes] ||= []
|
18
|
-
Chef::Config[:knife][:cloudformation][:attributes].push(val).uniq!
|
19
|
-
}
|
20
|
-
)
|
21
|
-
|
22
|
-
option(:all,
|
23
|
-
:long => '--all-attributes',
|
24
|
-
:description => 'Print all attributes'
|
25
|
-
)
|
26
|
-
|
27
|
-
option(:status,
|
28
|
-
:short => '-S STATUS',
|
29
|
-
:long => '--status STATUS',
|
30
|
-
:description => 'Match given status. Use "none" to disable. Can be used multiple times.',
|
31
|
-
:proc => lambda {|val|
|
32
|
-
Chef::Config[:knife][:cloudformation][:status] ||= []
|
33
|
-
Chef::Config[:knife][:cloudformation][:status].push(val).uniq!
|
34
|
-
}
|
35
|
-
)
|
36
|
-
|
37
|
-
# Run the list command
|
38
|
-
def _run
|
39
|
-
things_output(nil, get_list, nil)
|
40
|
-
end
|
41
|
-
|
42
|
-
# Get the list of stacks to display
|
43
|
-
#
|
44
|
-
# @return [Array<Hash>]
|
45
|
-
def get_list
|
46
|
-
get_things do
|
47
|
-
provider.stacks.all.map do |stack|
|
48
|
-
Mash.new(stack.attributes)
|
49
|
-
end.sort do |x, y|
|
50
|
-
if(y[:created].to_s.empty?)
|
51
|
-
-1
|
52
|
-
elsif(x[:created].to_s.empty?)
|
53
|
-
1
|
54
|
-
else
|
55
|
-
Time.parse(y['created'].to_s) <=> Time.parse(x['created'].to_s)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
# @return [Array<String>] default attributes to display
|
62
|
-
def default_attributes
|
63
|
-
if(provider.connection.provider == :aws)
|
64
|
-
%w(name created status template_description)
|
65
|
-
else
|
66
|
-
%w(name created status description)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
require 'knife-cloudformation'
|
2
|
-
|
3
|
-
class Chef
|
4
|
-
class Knife
|
5
|
-
class CloudformationPromote < Knife
|
6
|
-
|
7
|
-
include KnifeCloudformation::Knife::Base
|
8
|
-
|
9
|
-
banner 'knife cloudformation promote NEW_STACK_NAME DESTINATION'
|
10
|
-
|
11
|
-
option(:accounts,
|
12
|
-
:long => '--accounts-file PATH',
|
13
|
-
:short => '-A PATH',
|
14
|
-
:description => 'JSON account file',
|
15
|
-
:proc => lambda{|v|
|
16
|
-
Chef::Config[:knife][:cloudformation][:promote_accounts] = JSON.load(File.read(v))
|
17
|
-
}
|
18
|
-
)
|
19
|
-
|
20
|
-
option(:storage_bucket,
|
21
|
-
:long => '--exports-bucket NAME',
|
22
|
-
:description => 'Bucket name containing the exports',
|
23
|
-
:proc => lambda{|v| Chef::Config[:knife][:cloudformation][:promote_exports_bucket] = v }
|
24
|
-
)
|
25
|
-
|
26
|
-
option(:storage_prefix,
|
27
|
-
:long => '--exports-prefix PREFIX',
|
28
|
-
:description => 'Prefix of stack key',
|
29
|
-
:proc => lambda{|v| Chef::Config[:knife][:cloudformation][:promote_exports_prefix] = v }
|
30
|
-
)
|
31
|
-
|
32
|
-
|
33
|
-
def _run
|
34
|
-
stack_name, destination = name_args
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,137 +0,0 @@
|
|
1
|
-
require 'knife-cloudformation'
|
2
|
-
|
3
|
-
class Chef
|
4
|
-
class Knife
|
5
|
-
class CloudformationUpdate < Knife
|
6
|
-
|
7
|
-
include KnifeCloudformation::Knife::Base
|
8
|
-
include KnifeCloudformation::Knife::Template
|
9
|
-
include KnifeCloudformation::Knife::Stack
|
10
|
-
|
11
|
-
option(:file_path_prompt,
|
12
|
-
:long => '--[no-]file-path-prompt',
|
13
|
-
:description => 'Interactive prompt for template path discovery',
|
14
|
-
:boolean => true,
|
15
|
-
:default => false,
|
16
|
-
:proc => lambda {|val|
|
17
|
-
Chef::Config[:knife][:cloudformation][:file_path_prompt] = val
|
18
|
-
}
|
19
|
-
)
|
20
|
-
option(:apply_stacks,
|
21
|
-
:long => '--apply-stack NAME_OR_ID',
|
22
|
-
:description => 'Autofill parameters using existing stack outputs. Can be used multiple times',
|
23
|
-
:proc => lambda {|val|
|
24
|
-
Chef::Config[:knife][:cloudformation][:update] ||= Mash.new
|
25
|
-
Chef::Config[:knife][:cloudformation][:update][:apply_stacks] ||= []
|
26
|
-
Chef::Config[:knife][:cloudformation][:update][:apply_stacks].push(val).uniq!
|
27
|
-
}
|
28
|
-
)
|
29
|
-
|
30
|
-
banner 'knife cloudformation update NAME'
|
31
|
-
|
32
|
-
# Run the stack creation command
|
33
|
-
def _run
|
34
|
-
name = name_args.first
|
35
|
-
unless(name)
|
36
|
-
ui.fatal "Formation name must be specified!"
|
37
|
-
exit 1
|
38
|
-
end
|
39
|
-
|
40
|
-
stack_info = "#{ui.color('Name:', :bold)} #{name}"
|
41
|
-
|
42
|
-
if(Chef::Config[:knife][:cloudformation][:file])
|
43
|
-
file = load_template_file
|
44
|
-
stack_info << " #{ui.color('Path:', :bold)} #{Chef::Config[:knife][:cloudformation][:file]}"
|
45
|
-
nested_stacks = file.delete('sfn_nested_stack')
|
46
|
-
end
|
47
|
-
|
48
|
-
if(nested_stacks)
|
49
|
-
|
50
|
-
unpack_nesting(name, file, :update)
|
51
|
-
|
52
|
-
else
|
53
|
-
stack = provider.connection.stacks.get(name)
|
54
|
-
|
55
|
-
if(stack)
|
56
|
-
ui.info "#{ui.color('Cloud Formation:', :bold)} #{ui.color('update', :green)}"
|
57
|
-
|
58
|
-
unless(file)
|
59
|
-
if(Chef::Config[:knife][:cloudformation][:template])
|
60
|
-
file = Chef::Config[:knife][:cloudformation][:template]
|
61
|
-
stack_info << " #{ui.color('(template provided)', :green)}"
|
62
|
-
else
|
63
|
-
stack_info << " #{ui.color('(no template update)', :yellow)}"
|
64
|
-
end
|
65
|
-
end
|
66
|
-
ui.info " -> #{stack_info}"
|
67
|
-
|
68
|
-
apply_stacks!(stack)
|
69
|
-
|
70
|
-
if(file)
|
71
|
-
populate_parameters!(file, stack.parameters)
|
72
|
-
stack.template = translate_template(file)
|
73
|
-
stack.parameters = Chef::Config[:knife][:cloudformation][:options][:parameters]
|
74
|
-
stack.template = KnifeCloudformation::Utils::StackParameterScrubber.scrub!(stack.template)
|
75
|
-
else
|
76
|
-
populate_parameters!(stack.template, stack.parameters)
|
77
|
-
stack.parameters = Chef::Config[:knife][:cloudformation][:options][:parameters]
|
78
|
-
end
|
79
|
-
|
80
|
-
begin
|
81
|
-
stack.save
|
82
|
-
rescue Miasma::Error::ApiError::RequestError => e
|
83
|
-
if(e.message.downcase.include?('no updates')) # :'(
|
84
|
-
ui.warn "No updates detected for stack (#{stack.name})"
|
85
|
-
else
|
86
|
-
raise
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
if(Chef::Config[:knife][:cloudformation][:poll])
|
91
|
-
poll_stack(stack.name)
|
92
|
-
if(stack.success?)
|
93
|
-
ui.info "Stack update complete: #{ui.color('SUCCESS', :green)}"
|
94
|
-
knife_output = Chef::Knife::CloudformationDescribe.new
|
95
|
-
knife_output.name_args.push(name)
|
96
|
-
knife_output.config[:outputs] = true
|
97
|
-
knife_output.run
|
98
|
-
else
|
99
|
-
ui.fatal "Update of stack #{ui.color(name, :bold)}: #{ui.color('FAILED', :red, :bold)}"
|
100
|
-
ui.info ""
|
101
|
-
knife_inspect = Chef::Knife::CloudformationInspect.new
|
102
|
-
knife_inspect.name_args.push(name)
|
103
|
-
knife_inspect.config[:instance_failure] = true
|
104
|
-
knife_inspect.run
|
105
|
-
exit 1
|
106
|
-
end
|
107
|
-
else
|
108
|
-
ui.warn 'Stack state polling has been disabled.'
|
109
|
-
ui.info "Stack update initialized for #{ui.color(name, :green)}"
|
110
|
-
end
|
111
|
-
else
|
112
|
-
ui.fatal "Failed to locate requested stack: #{ui.color(name, :red, :bold)}"
|
113
|
-
exit -1
|
114
|
-
end
|
115
|
-
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# Update default values for parameters in template with
|
120
|
-
# currently used parameters on the existing stack
|
121
|
-
#
|
122
|
-
# @param template [Hash] stack template
|
123
|
-
# @param stack [Fog::Orchestration::Stack]
|
124
|
-
# @return [Hash]
|
125
|
-
# @todo to be scrubbed
|
126
|
-
def redefault_stack_parameters(template, stack)
|
127
|
-
stack.parameters.each do |key, value|
|
128
|
-
if(template['Parameters'][key])
|
129
|
-
template['Parameters'][key]['Default'] = value
|
130
|
-
end
|
131
|
-
end
|
132
|
-
template
|
133
|
-
end
|
134
|
-
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|