knife-ec2 0.12.0 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +41 -41
- data/.travis.yml +7 -1
- data/CHANGELOG.md +40 -4
- data/CONTRIBUTING.md +216 -71
- data/CONTRIBUTIONS.md +3 -6
- data/DOC_CHANGES.md +25 -50
- data/Gemfile +4 -1
- data/LICENSE +201 -201
- data/README.md +138 -83
- data/RELEASE_NOTES.md +20 -36
- data/Rakefile +56 -56
- data/knife-ec2.gemspec +4 -3
- data/lib/chef/knife/ec2_base.rb +45 -12
- data/lib/chef/knife/ec2_flavor_list.rb +53 -53
- data/lib/chef/knife/ec2_server_create.rb +251 -45
- data/lib/chef/knife/ec2_server_delete.rb +140 -140
- data/lib/chef/knife/ec2_server_list.rb +52 -83
- data/lib/chef/knife/s3_source.rb +49 -49
- data/lib/knife-ec2/version.rb +6 -6
- data/spec/spec_helper.rb +18 -18
- data/spec/unit/ec2_server_create_spec.rb +930 -19
- data/spec/unit/ec2_server_delete_spec.rb +141 -141
- data/spec/unit/ec2_server_list_spec.rb +131 -0
- data/spec/unit/s3_source_deps_spec.rb +24 -24
- data/spec/unit/s3_source_spec.rb +75 -75
- metadata +25 -15
@@ -1,140 +1,140 @@
|
|
1
|
-
#
|
2
|
-
# Author:: Adam Jacob (<adam@
|
3
|
-
# Author:: Seth Chisamore (<schisamo@
|
4
|
-
# Copyright:: Copyright (c) 2009-
|
5
|
-
# License:: Apache License, Version 2.0
|
6
|
-
#
|
7
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
-
# you may not use this file except in compliance with the License.
|
9
|
-
# You may obtain a copy of the License at
|
10
|
-
#
|
11
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
-
#
|
13
|
-
# Unless required by applicable law or agreed to in writing, software
|
14
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
-
# See the License for the specific language governing permissions and
|
17
|
-
# limitations under the License.
|
18
|
-
#
|
19
|
-
|
20
|
-
require 'chef/knife/ec2_base'
|
21
|
-
|
22
|
-
# These two are needed for the '--purge' deletion case
|
23
|
-
require 'chef/node'
|
24
|
-
require 'chef/api_client'
|
25
|
-
|
26
|
-
class Chef
|
27
|
-
class Knife
|
28
|
-
class Ec2ServerDelete < Knife
|
29
|
-
|
30
|
-
include Knife::Ec2Base
|
31
|
-
|
32
|
-
banner "knife ec2 server delete SERVER [SERVER] (options)"
|
33
|
-
|
34
|
-
attr_reader :server
|
35
|
-
|
36
|
-
option :purge,
|
37
|
-
:short => "-P",
|
38
|
-
:long => "--purge",
|
39
|
-
:boolean => true,
|
40
|
-
:default => false,
|
41
|
-
:description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the EC2 node itself. Assumes node and client have the same name as the server (if not, add the '--node-name' option)."
|
42
|
-
|
43
|
-
option :chef_node_name,
|
44
|
-
:short => "-N NAME",
|
45
|
-
:long => "--node-name NAME",
|
46
|
-
:description => "The name of the node and client to delete, if it differs from the server name. Only has meaning when used with the '--purge' option."
|
47
|
-
|
48
|
-
# Extracted from Chef::Knife.delete_object, because it has a
|
49
|
-
# confirmation step built in... By specifying the '--purge'
|
50
|
-
# flag (and also explicitly confirming the server destruction!)
|
51
|
-
# the user is already making their intent known. It is not
|
52
|
-
# necessary to make them confirm two more times.
|
53
|
-
def destroy_item(klass, name, type_name)
|
54
|
-
begin
|
55
|
-
object = klass.load(name)
|
56
|
-
object.destroy
|
57
|
-
ui.warn("Deleted #{type_name} #{name}")
|
58
|
-
rescue Net::HTTPServerException
|
59
|
-
ui.warn("Could not find a #{type_name} named #{name} to delete!")
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def run
|
64
|
-
|
65
|
-
validate!
|
66
|
-
if @name_args.empty? && config[:chef_node_name]
|
67
|
-
ui.info("no instance id is specific, trying to retrieve it from node name")
|
68
|
-
instance_id = fetch_instance_id(config[:chef_node_name])
|
69
|
-
@name_args << instance_id unless instance_id.nil?
|
70
|
-
end
|
71
|
-
|
72
|
-
@name_args.each do |instance_id|
|
73
|
-
|
74
|
-
begin
|
75
|
-
@server = connection.servers.get(instance_id)
|
76
|
-
|
77
|
-
msg_pair('Instance ID', @server.id)
|
78
|
-
msg_pair('Instance Name', @server.tags['Name'])
|
79
|
-
msg_pair('Flavor', @server.flavor_id)
|
80
|
-
msg_pair('Image', @server.image_id)
|
81
|
-
msg_pair('Region', connection.instance_variable_get(:@region))
|
82
|
-
msg_pair('Availability Zone', @server.availability_zone)
|
83
|
-
msg_pair('Security Groups', @server.groups.join(', '))
|
84
|
-
msg_pair('IAM Profile', iam_name_from_profile(@server.iam_instance_profile)) if @server.iam_instance_profile
|
85
|
-
msg_pair('SSH Key', @server.key_name)
|
86
|
-
msg_pair('Root Device Type', @server.root_device_type)
|
87
|
-
msg_pair('Public DNS Name', @server.dns_name)
|
88
|
-
msg_pair('Public IP Address', @server.public_ip_address)
|
89
|
-
msg_pair('Private DNS Name', @server.private_dns_name)
|
90
|
-
msg_pair('Private IP Address', @server.private_ip_address)
|
91
|
-
|
92
|
-
puts '\n'
|
93
|
-
confirm('Do you really want to delete this server')
|
94
|
-
|
95
|
-
@server.destroy
|
96
|
-
|
97
|
-
ui.warn("Deleted server #{@server.id}")
|
98
|
-
|
99
|
-
if config[:purge]
|
100
|
-
if config[:chef_node_name]
|
101
|
-
thing_to_delete = config[:chef_node_name]
|
102
|
-
else
|
103
|
-
thing_to_delete = fetch_node_name(instance_id)
|
104
|
-
end
|
105
|
-
destroy_item(Chef::Node, thing_to_delete, "node")
|
106
|
-
destroy_item(Chef::ApiClient, thing_to_delete, "client")
|
107
|
-
else
|
108
|
-
ui.warn("Corresponding node and client for the #{instance_id} server were not deleted and remain registered with the Chef Server")
|
109
|
-
end
|
110
|
-
rescue NoMethodError
|
111
|
-
ui.error("Could not locate server '#{instance_id}'. Please verify it was provisioned in the '#{locate_config_value(:region)}' region.")
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def fetch_node_name(instance_id)
|
117
|
-
result = query.search(:node,"ec2_instance_id:#{instance_id}")
|
118
|
-
unless result.first.empty?
|
119
|
-
result.first.first.name
|
120
|
-
else
|
121
|
-
instance_id
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
def fetch_instance_id(name)
|
126
|
-
result = query.search(:node,"name:#{name}")
|
127
|
-
unless result.first.empty?
|
128
|
-
node = result.first.first
|
129
|
-
if node.attribute?('ec2')
|
130
|
-
node['ec2']['instance_id']
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
def query
|
136
|
-
@query ||= Chef::Search::Query.new
|
137
|
-
end
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
1
|
+
#
|
2
|
+
# Author:: Adam Jacob (<adam@chef.io>)
|
3
|
+
# Author:: Seth Chisamore (<schisamo@chef.io>)
|
4
|
+
# Copyright:: Copyright (c) 2009-2015 Chef Software, Inc.
|
5
|
+
# License:: Apache License, Version 2.0
|
6
|
+
#
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
8
|
+
# you may not use this file except in compliance with the License.
|
9
|
+
# You may obtain a copy of the License at
|
10
|
+
#
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
12
|
+
#
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
16
|
+
# See the License for the specific language governing permissions and
|
17
|
+
# limitations under the License.
|
18
|
+
#
|
19
|
+
|
20
|
+
require 'chef/knife/ec2_base'
|
21
|
+
|
22
|
+
# These two are needed for the '--purge' deletion case
|
23
|
+
require 'chef/node'
|
24
|
+
require 'chef/api_client'
|
25
|
+
|
26
|
+
class Chef
|
27
|
+
class Knife
|
28
|
+
class Ec2ServerDelete < Knife
|
29
|
+
|
30
|
+
include Knife::Ec2Base
|
31
|
+
|
32
|
+
banner "knife ec2 server delete SERVER [SERVER] (options)"
|
33
|
+
|
34
|
+
attr_reader :server
|
35
|
+
|
36
|
+
option :purge,
|
37
|
+
:short => "-P",
|
38
|
+
:long => "--purge",
|
39
|
+
:boolean => true,
|
40
|
+
:default => false,
|
41
|
+
:description => "Destroy corresponding node and client on the Chef Server, in addition to destroying the EC2 node itself. Assumes node and client have the same name as the server (if not, add the '--node-name' option)."
|
42
|
+
|
43
|
+
option :chef_node_name,
|
44
|
+
:short => "-N NAME",
|
45
|
+
:long => "--node-name NAME",
|
46
|
+
:description => "The name of the node and client to delete, if it differs from the server name. Only has meaning when used with the '--purge' option."
|
47
|
+
|
48
|
+
# Extracted from Chef::Knife.delete_object, because it has a
|
49
|
+
# confirmation step built in... By specifying the '--purge'
|
50
|
+
# flag (and also explicitly confirming the server destruction!)
|
51
|
+
# the user is already making their intent known. It is not
|
52
|
+
# necessary to make them confirm two more times.
|
53
|
+
def destroy_item(klass, name, type_name)
|
54
|
+
begin
|
55
|
+
object = klass.load(name)
|
56
|
+
object.destroy
|
57
|
+
ui.warn("Deleted #{type_name} #{name}")
|
58
|
+
rescue Net::HTTPServerException
|
59
|
+
ui.warn("Could not find a #{type_name} named #{name} to delete!")
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def run
|
64
|
+
|
65
|
+
validate!
|
66
|
+
if @name_args.empty? && config[:chef_node_name]
|
67
|
+
ui.info("no instance id is specific, trying to retrieve it from node name")
|
68
|
+
instance_id = fetch_instance_id(config[:chef_node_name])
|
69
|
+
@name_args << instance_id unless instance_id.nil?
|
70
|
+
end
|
71
|
+
|
72
|
+
@name_args.each do |instance_id|
|
73
|
+
|
74
|
+
begin
|
75
|
+
@server = connection.servers.get(instance_id)
|
76
|
+
|
77
|
+
msg_pair('Instance ID', @server.id)
|
78
|
+
msg_pair('Instance Name', @server.tags['Name'])
|
79
|
+
msg_pair('Flavor', @server.flavor_id)
|
80
|
+
msg_pair('Image', @server.image_id)
|
81
|
+
msg_pair('Region', connection.instance_variable_get(:@region))
|
82
|
+
msg_pair('Availability Zone', @server.availability_zone)
|
83
|
+
msg_pair('Security Groups', @server.groups.join(', '))
|
84
|
+
msg_pair('IAM Profile', iam_name_from_profile(@server.iam_instance_profile)) if @server.iam_instance_profile
|
85
|
+
msg_pair('SSH Key', @server.key_name)
|
86
|
+
msg_pair('Root Device Type', @server.root_device_type)
|
87
|
+
msg_pair('Public DNS Name', @server.dns_name)
|
88
|
+
msg_pair('Public IP Address', @server.public_ip_address)
|
89
|
+
msg_pair('Private DNS Name', @server.private_dns_name)
|
90
|
+
msg_pair('Private IP Address', @server.private_ip_address)
|
91
|
+
|
92
|
+
puts '\n'
|
93
|
+
confirm('Do you really want to delete this server')
|
94
|
+
|
95
|
+
@server.destroy
|
96
|
+
|
97
|
+
ui.warn("Deleted server #{@server.id}")
|
98
|
+
|
99
|
+
if config[:purge]
|
100
|
+
if config[:chef_node_name]
|
101
|
+
thing_to_delete = config[:chef_node_name]
|
102
|
+
else
|
103
|
+
thing_to_delete = fetch_node_name(instance_id)
|
104
|
+
end
|
105
|
+
destroy_item(Chef::Node, thing_to_delete, "node")
|
106
|
+
destroy_item(Chef::ApiClient, thing_to_delete, "client")
|
107
|
+
else
|
108
|
+
ui.warn("Corresponding node and client for the #{instance_id} server were not deleted and remain registered with the Chef Server")
|
109
|
+
end
|
110
|
+
rescue NoMethodError
|
111
|
+
ui.error("Could not locate server '#{instance_id}'. Please verify it was provisioned in the '#{locate_config_value(:region)}' region.")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def fetch_node_name(instance_id)
|
117
|
+
result = query.search(:node,"ec2_instance_id:#{instance_id}")
|
118
|
+
unless result.first.empty?
|
119
|
+
result.first.first.name
|
120
|
+
else
|
121
|
+
instance_id
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def fetch_instance_id(name)
|
126
|
+
result = query.search(:node,"name:#{name}")
|
127
|
+
unless result.first.empty?
|
128
|
+
node = result.first.first
|
129
|
+
if node.attribute?('ec2')
|
130
|
+
node['ec2']['instance_id']
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def query
|
136
|
+
@query ||= Chef::Search::Query.new
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
#
|
2
|
-
# Author:: Adam Jacob (<adam@
|
3
|
-
# Author:: Seth Chisamore (<schisamo@
|
4
|
-
# Copyright:: Copyright (c) 2010-
|
2
|
+
# Author:: Adam Jacob (<adam@chef.io>)
|
3
|
+
# Author:: Seth Chisamore (<schisamo@chef.io>)
|
4
|
+
# Copyright:: Copyright (c) 2010-2015 Chef Software, Inc.
|
5
5
|
# License:: Apache License, Version 2.0
|
6
6
|
#
|
7
7
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
@@ -46,21 +46,6 @@ class Chef
|
|
46
46
|
:long => "--tags TAG1,TAG2",
|
47
47
|
:description => "List of tags to output"
|
48
48
|
|
49
|
-
def fcolor(flavor)
|
50
|
-
case flavor
|
51
|
-
when "t1.micro"
|
52
|
-
fcolor = :blue
|
53
|
-
when "m1.small"
|
54
|
-
fcolor = :magenta
|
55
|
-
when "m1.medium"
|
56
|
-
fcolor = :cyan
|
57
|
-
when "m1.large"
|
58
|
-
fcolor = :green
|
59
|
-
when "m1.xlarge"
|
60
|
-
fcolor = :red
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
49
|
def azcolor(az)
|
65
50
|
case az
|
66
51
|
when /a$/
|
@@ -76,22 +61,6 @@ class Chef
|
|
76
61
|
end
|
77
62
|
end
|
78
63
|
|
79
|
-
def groups_with_ids(groups)
|
80
|
-
groups.map{|g|
|
81
|
-
"#{g} (#{@group_id_hash[g]})"
|
82
|
-
}
|
83
|
-
end
|
84
|
-
|
85
|
-
def vpc_with_name(vpc_id)
|
86
|
-
this_vpc = @vpcs.select{|v| v.id == vpc_id }.first
|
87
|
-
if this_vpc.tags["Name"]
|
88
|
-
vpc_name = this_vpc.tags["Name"]
|
89
|
-
"#{vpc_name} (#{vpc_id})"
|
90
|
-
else
|
91
|
-
vpc_id
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
64
|
def run
|
96
65
|
$stdout.sync = true
|
97
66
|
|
@@ -99,7 +68,7 @@ class Chef
|
|
99
68
|
|
100
69
|
server_list = [
|
101
70
|
ui.color('Instance ID', :bold),
|
102
|
-
|
71
|
+
|
103
72
|
if config[:name]
|
104
73
|
ui.color("Name", :bold)
|
105
74
|
end,
|
@@ -115,72 +84,72 @@ class Chef
|
|
115
84
|
ui.color('Image', :bold),
|
116
85
|
ui.color('SSH Key', :bold),
|
117
86
|
ui.color('Security Groups', :bold),
|
118
|
-
|
87
|
+
|
119
88
|
if config[:tags]
|
120
89
|
config[:tags].split(",").collect do |tag_name|
|
121
90
|
ui.color("Tag:#{tag_name}", :bold)
|
122
91
|
end
|
123
92
|
end,
|
124
|
-
|
93
|
+
|
125
94
|
ui.color('IAM Profile', :bold),
|
126
95
|
ui.color('State', :bold)
|
127
96
|
].flatten.compact
|
128
|
-
|
97
|
+
|
129
98
|
output_column_count = server_list.length
|
130
|
-
|
131
|
-
if !config[:region]
|
99
|
+
|
100
|
+
if !config[:region] && Chef::Config[:knife][:region].nil?
|
132
101
|
ui.warn "No region was specified in knife.rb or as an argument. The default region, us-east-1, will be used:"
|
133
102
|
end
|
134
|
-
|
135
|
-
connection.servers
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
103
|
+
|
104
|
+
servers = connection.servers
|
105
|
+
if (config[:format] == 'summary')
|
106
|
+
servers.each do |server|
|
107
|
+
server_list << server.id.to_s
|
108
|
+
|
109
|
+
if config[:name]
|
110
|
+
server_list << server.tags["Name"].to_s
|
111
|
+
end
|
112
|
+
|
113
|
+
server_list << server.public_ip_address.to_s
|
114
|
+
server_list << server.private_ip_address.to_s
|
115
|
+
server_list << server.flavor_id.to_s
|
116
|
+
|
117
|
+
if config[:az]
|
118
|
+
server_list << ui.color(
|
119
|
+
server.availability_zone.to_s,
|
120
|
+
azcolor(server.availability_zone.to_s)
|
148
121
|
)
|
122
|
+
end
|
149
123
|
|
150
|
-
|
151
|
-
server_list <<
|
152
|
-
|
153
|
-
azcolor(server.availability_zone.to_s)
|
154
|
-
)
|
155
|
-
end
|
124
|
+
server_list << server.image_id.to_s
|
125
|
+
server_list << server.key_name.to_s
|
126
|
+
server_list << server.groups.join(", ")
|
156
127
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
if config[:tags]
|
162
|
-
config[:tags].split(",").each do |tag_name|
|
163
|
-
server_list << server.tags[tag_name].to_s
|
128
|
+
if config[:tags]
|
129
|
+
config[:tags].split(",").each do |tag_name|
|
130
|
+
server_list << server.tags[tag_name].to_s
|
131
|
+
end
|
164
132
|
end
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
133
|
+
|
134
|
+
server_list << iam_name_from_profile(server.iam_instance_profile)
|
135
|
+
|
136
|
+
server_list << begin
|
137
|
+
state = server.state.to_s.downcase
|
138
|
+
case state
|
139
|
+
when 'shutting-down','terminated','stopping','stopped'
|
140
|
+
ui.color(state, :red)
|
141
|
+
when 'pending'
|
142
|
+
ui.color(state, :yellow)
|
143
|
+
else
|
144
|
+
ui.color(state, :green)
|
145
|
+
end
|
178
146
|
end
|
179
147
|
end
|
180
|
-
end
|
181
|
-
|
182
|
-
puts ui.list(server_list, :uneven_columns_across, output_column_count)
|
183
148
|
|
149
|
+
puts ui.list(server_list, :uneven_columns_across, output_column_count)
|
150
|
+
else
|
151
|
+
output(format_for_display(servers))
|
152
|
+
end
|
184
153
|
end
|
185
154
|
end
|
186
155
|
end
|