knife-cloudformation 0.2.24 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|