knife-ec2 0.19.16 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/chef/knife/ec2_ami_list.rb +48 -37
- data/lib/chef/knife/ec2_base.rb +108 -36
- data/lib/chef/knife/ec2_eip_list.rb +88 -0
- data/lib/chef/knife/ec2_flavor_list.rb +3 -34
- data/lib/chef/knife/ec2_securitygroup_list.rb +68 -0
- data/lib/chef/knife/ec2_server_create.rb +429 -554
- data/lib/chef/knife/ec2_server_delete.rb +99 -48
- data/lib/chef/knife/ec2_server_list.rb +83 -44
- data/lib/chef/knife/ec2_subnet_list.rb +79 -0
- data/lib/chef/knife/ec2_vpc_list.rb +75 -0
- data/lib/chef/knife/s3_source.rb +27 -9
- data/lib/knife-ec2/version.rb +1 -1
- metadata +29 -20
@@ -35,6 +35,13 @@ class Chef
|
|
35
35
|
|
36
36
|
attr_reader :server
|
37
37
|
|
38
|
+
option :dry_run,
|
39
|
+
long: "--dry-run",
|
40
|
+
short: "-n",
|
41
|
+
boolean: true,
|
42
|
+
default: false,
|
43
|
+
description: "Don't take action, only print what would happen."
|
44
|
+
|
38
45
|
option :purge,
|
39
46
|
short: "-P",
|
40
47
|
long: "--purge",
|
@@ -54,61 +61,48 @@ class Chef
|
|
54
61
|
# necessary to make them confirm two more times.
|
55
62
|
def destroy_item(klass, name, type_name)
|
56
63
|
object = klass.load(name)
|
57
|
-
object.destroy
|
64
|
+
object.destroy unless config[:dry_run]
|
58
65
|
ui.warn("Deleted #{type_name} #{name}")
|
59
66
|
rescue Net::HTTPServerException
|
60
67
|
ui.warn("Could not find a #{type_name} named #{name} to delete!")
|
61
68
|
end
|
62
69
|
|
63
70
|
def run
|
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
|
-
ui.warn("
|
97
|
-
|
98
|
-
if config[:purge]
|
99
|
-
if config[:chef_node_name]
|
100
|
-
thing_to_delete = config[:chef_node_name]
|
101
|
-
else
|
102
|
-
thing_to_delete = fetch_node_name(instance_id)
|
103
|
-
end
|
104
|
-
destroy_item(Chef::Node, thing_to_delete, "node")
|
105
|
-
destroy_item(Chef::ApiClient, thing_to_delete, "client")
|
106
|
-
else
|
107
|
-
ui.warn("Corresponding node and client for the #{instance_id} server were not deleted and remain registered with the Chef Server")
|
108
|
-
end
|
109
|
-
rescue NoMethodError
|
110
|
-
ui.error("Could not locate server '#{instance_id}'. Please verify it was provisioned in the '#{locate_config_value(:region)}' region.")
|
71
|
+
validate_aws_config!
|
72
|
+
validate_instances!
|
73
|
+
|
74
|
+
server_hashes.each do |h|
|
75
|
+
instance_id = h["instance_id"]
|
76
|
+
msg_pair("Instance ID", instance_id)
|
77
|
+
msg_pair("Instance Name", h["name"])
|
78
|
+
msg_pair("Flavor", h["instance_type"])
|
79
|
+
msg_pair("Image", h["image_id"])
|
80
|
+
msg_pair("Region", fetch_region)
|
81
|
+
msg_pair("Availability Zone", h["az"])
|
82
|
+
msg_pair("Security Groups", h["security_groups"])
|
83
|
+
msg_pair("IAM Profile", h["iam_instance_profile"])
|
84
|
+
msg_pair("SSH Key", h["key_name"])
|
85
|
+
msg_pair("Root Device Type", h["root_device_type"])
|
86
|
+
msg_pair("Public DNS Name", h["public_dns_name"])
|
87
|
+
msg_pair("Public IP Address", h["public_ip_address"])
|
88
|
+
msg_pair("Private DNS Name", h["private_dns_name"])
|
89
|
+
msg_pair("Private IP Address", h["private_ip_address"])
|
90
|
+
|
91
|
+
puts "\n"
|
92
|
+
confirm("Do you really want to delete this server")
|
93
|
+
|
94
|
+
delete_instance(instance_id) unless config[:dry_run]
|
95
|
+
|
96
|
+
ui.warn("Deleted server #{instance_id}")
|
97
|
+
|
98
|
+
if config[:purge]
|
99
|
+
node_name = config[:chef_node_name] || fetch_node_name(instance_id)
|
100
|
+
destroy_item(Chef::Node, node_name, "node")
|
101
|
+
destroy_item(Chef::ApiClient, node_name, "client")
|
102
|
+
else
|
103
|
+
ui.warn("Corresponding node and client for the #{instance_id} server were not deleted and remain registered with the Chef Server")
|
111
104
|
end
|
105
|
+
puts "\n"
|
112
106
|
end
|
113
107
|
end
|
114
108
|
|
@@ -137,6 +131,63 @@ class Chef
|
|
137
131
|
def query
|
138
132
|
@query ||= Chef::Search::Query.new
|
139
133
|
end
|
134
|
+
|
135
|
+
private
|
136
|
+
|
137
|
+
# @return [Array<Hash>]
|
138
|
+
def server_hashes
|
139
|
+
all_data = []
|
140
|
+
|
141
|
+
servers_list = ec2_connection.describe_instances({
|
142
|
+
instance_ids: @name_args,
|
143
|
+
})
|
144
|
+
|
145
|
+
servers_list.reservations.each do |i|
|
146
|
+
server_data = {}
|
147
|
+
%w{image_id instance_id instance_type key_name root_device_type public_ip_address private_ip_address private_dns_name public_dns_name}.each do |id|
|
148
|
+
server_data[id] = i.instances[0].send(id)
|
149
|
+
end
|
150
|
+
|
151
|
+
server_data["name"] = i.instances[0].tags[0].value
|
152
|
+
server_data["az"] = i.instances[0].placement.availability_zone
|
153
|
+
server_data["iam_instance_profile"] = ( i.instances[0].iam_instance_profile.nil? ? nil : i.instances[0].iam_instance_profile.arn[/instance-profile\/(.*)/] )
|
154
|
+
server_data["security_groups"] = i.instances[0].security_groups.map { |x| x.group_name }.join(", ")
|
155
|
+
|
156
|
+
all_data << server_data
|
157
|
+
end
|
158
|
+
all_data
|
159
|
+
end
|
160
|
+
|
161
|
+
# Delete the server instance
|
162
|
+
def delete_instance(instance_id)
|
163
|
+
return nil unless instance_id || instance_id.is_a?(String)
|
164
|
+
ec2_connection.terminate_instances({
|
165
|
+
instance_ids: [
|
166
|
+
instance_id,
|
167
|
+
],
|
168
|
+
})
|
169
|
+
end
|
170
|
+
|
171
|
+
# If SERVER instance id not provided then check chef_name_tag and fetch the node
|
172
|
+
# And if the node contains instance id then add it to the name args
|
173
|
+
def validate_instances!
|
174
|
+
if @name_args.empty?
|
175
|
+
if config[:chef_node_name]
|
176
|
+
ui.info("No instance id is specified, trying to retrieve it from node name")
|
177
|
+
instance_id = fetch_instance_id(config[:chef_node_name])
|
178
|
+
|
179
|
+
if instance_id.nil?
|
180
|
+
ui.info("No instance id found.")
|
181
|
+
exit 1
|
182
|
+
else
|
183
|
+
@name_args << instance_id
|
184
|
+
end
|
185
|
+
else
|
186
|
+
ui.info("No instance id is specified.")
|
187
|
+
exit 1
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
140
191
|
end
|
141
192
|
end
|
142
193
|
end
|
@@ -34,8 +34,15 @@ class Chef
|
|
34
34
|
default: true,
|
35
35
|
description: "Do not display name tag in output"
|
36
36
|
|
37
|
+
option :iamprofile,
|
38
|
+
short: "-i",
|
39
|
+
long: "--iam-profile",
|
40
|
+
boolean: true,
|
41
|
+
default: false,
|
42
|
+
description: "Show the iam profile"
|
43
|
+
|
37
44
|
option :az,
|
38
|
-
short: "-
|
45
|
+
short: "-a",
|
39
46
|
long: "--availability-zone",
|
40
47
|
boolean: true,
|
41
48
|
default: false,
|
@@ -64,12 +71,24 @@ class Chef
|
|
64
71
|
end
|
65
72
|
end
|
66
73
|
|
74
|
+
# @return [Symbol]
|
75
|
+
def state_color(state)
|
76
|
+
case state
|
77
|
+
when "shutting-down", "terminated", "stopping", "stopped"
|
78
|
+
:red
|
79
|
+
when "pending"
|
80
|
+
:yellow
|
81
|
+
else
|
82
|
+
:green
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
67
86
|
def run
|
68
87
|
$stdout.sync = true
|
69
88
|
|
70
|
-
|
89
|
+
validate_aws_config!
|
71
90
|
|
72
|
-
|
91
|
+
servers_list = [
|
73
92
|
ui.color("Instance ID", :bold),
|
74
93
|
|
75
94
|
if config[:name]
|
@@ -94,65 +113,85 @@ class Chef
|
|
94
113
|
end
|
95
114
|
end,
|
96
115
|
|
97
|
-
|
116
|
+
if config[:iamprofile]
|
117
|
+
ui.color("IAM Profile", :bold)
|
118
|
+
end,
|
119
|
+
|
98
120
|
ui.color("State", :bold)
|
99
121
|
].flatten.compact
|
100
122
|
|
101
|
-
output_column_count =
|
123
|
+
output_column_count = servers_list.length
|
102
124
|
|
103
125
|
if !config[:region] && Chef::Config[:knife][:region].nil?
|
104
126
|
ui.warn "No region was specified in knife.rb/config.rb or as an argument. The default region, us-east-1, will be used:"
|
105
127
|
end
|
106
128
|
|
107
|
-
servers = connection.servers
|
108
129
|
if config[:format] == "summary"
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
130
|
+
server_hashes.each do |v|
|
131
|
+
servers_list << v["instance_id"]
|
132
|
+
servers_list << v["name"] if config[:name]
|
133
|
+
servers_list << v["public_ip_address"]
|
134
|
+
servers_list << v["private_ip_address"]
|
135
|
+
servers_list << v["instance_type"]
|
136
|
+
servers_list << v["az"] if config[:az]
|
137
|
+
servers_list << v["image_id"]
|
138
|
+
servers_list << v["key_name"]
|
139
|
+
servers_list << v["security_groups"].join(",")
|
140
|
+
if config[:tags]
|
141
|
+
config[:tags].split(",").collect do |tag_name|
|
142
|
+
servers_list << v["tags"].find { |tag| tag == tag_name }
|
143
|
+
end
|
114
144
|
end
|
145
|
+
servers_list << v["iam_instance_profile"].to_s if config[:iamprofile] # may be nil
|
146
|
+
servers_list << v["state"]
|
147
|
+
end
|
148
|
+
puts ui.list(servers_list, :uneven_columns_across, output_column_count)
|
149
|
+
else
|
150
|
+
output(format_for_display(server_hashes))
|
151
|
+
end
|
152
|
+
end
|
115
153
|
|
116
|
-
|
117
|
-
server_list << server.private_ip_address.to_s
|
118
|
-
server_list << server.flavor_id.to_s
|
154
|
+
private
|
119
155
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
156
|
+
# @return [Array<Hash>]
|
157
|
+
def server_hashes
|
158
|
+
all_data = []
|
159
|
+
ec2_connection.describe_instances.reservations.each do |i|
|
160
|
+
server_data = {}
|
161
|
+
%w{image_id instance_id instance_type key_name public_ip_address private_ip_address}.each do |id|
|
162
|
+
server_data[id] = i.instances[0].send(id)
|
163
|
+
end
|
126
164
|
|
127
|
-
|
128
|
-
|
129
|
-
server_list << server.groups.join(", ")
|
165
|
+
# dig into tags struct
|
166
|
+
tags = extract_tags(i.instances[0].tags)
|
130
167
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
end
|
135
|
-
end
|
168
|
+
if config[:name]
|
169
|
+
server_data["name"] = tags[0]
|
170
|
+
end
|
136
171
|
|
137
|
-
|
138
|
-
|
139
|
-
server_list << begin
|
140
|
-
state = server.state.to_s.downcase
|
141
|
-
case state
|
142
|
-
when "shutting-down", "terminated", "stopping", "stopped"
|
143
|
-
ui.color(state, :red)
|
144
|
-
when "pending"
|
145
|
-
ui.color(state, :yellow)
|
146
|
-
else
|
147
|
-
ui.color(state, :green)
|
148
|
-
end
|
149
|
-
end
|
172
|
+
if config[:az]
|
173
|
+
server_data["az"] = ui.color(i.instances[0].placement.availability_zone, azcolor(i.instances[0].placement.availability_zone))
|
150
174
|
end
|
151
175
|
|
152
|
-
|
153
|
-
|
154
|
-
|
176
|
+
server_data["iam_instance_profile"] = ( i.instances[0].iam_instance_profile.nil? ? nil : i.instances[0].iam_instance_profile.arn[/instance-profile\/(.*)/] )
|
177
|
+
|
178
|
+
server_data["state"] = ui.color(i.instances[0].state.name, state_color(i.instances[0].state.name))
|
179
|
+
|
180
|
+
if config[:tags]
|
181
|
+
server_data["tags"] = tags
|
182
|
+
end
|
183
|
+
|
184
|
+
# dig into security_groups struct
|
185
|
+
server_data["security_groups"] = i.instances[0].security_groups.map { |x| x.group_name }
|
186
|
+
|
187
|
+
all_data << server_data
|
155
188
|
end
|
189
|
+
all_data
|
190
|
+
end
|
191
|
+
|
192
|
+
# @return [Array<String>]
|
193
|
+
def extract_tags(tags_struct)
|
194
|
+
tags_struct.map { |x| x.value }
|
156
195
|
end
|
157
196
|
end
|
158
197
|
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Tim Smith (<tsmith@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) 2018 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require "chef/knife/ec2_base"
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
class Knife
|
23
|
+
class Ec2SubnetList < Knife
|
24
|
+
|
25
|
+
include Knife::Ec2Base
|
26
|
+
|
27
|
+
banner "knife ec2 subnet list (options)"
|
28
|
+
|
29
|
+
def run
|
30
|
+
validate_aws_config!
|
31
|
+
custom_warnings!
|
32
|
+
|
33
|
+
subnet_list = [
|
34
|
+
ui.color("ID", :bold),
|
35
|
+
ui.color("State", :bold),
|
36
|
+
ui.color("CIDR Block", :bold),
|
37
|
+
ui.color("AZ", :bold),
|
38
|
+
ui.color("Available IPs", :bold),
|
39
|
+
ui.color("AZ Default?", :bold),
|
40
|
+
ui.color("Maps Public IP?", :bold),
|
41
|
+
ui.color("VPC ID", :bold)
|
42
|
+
].flatten.compact
|
43
|
+
|
44
|
+
output_column_count = subnet_list.length
|
45
|
+
|
46
|
+
if config[:format] == "summary"
|
47
|
+
subnet_hash.each_pair do |_k, v|
|
48
|
+
subnet_list << v["subnet_id"]
|
49
|
+
subnet_list << v["state"]
|
50
|
+
subnet_list << v["cidr_block"]
|
51
|
+
subnet_list << v["availability_zone"]
|
52
|
+
subnet_list << v["available_ip_address_count"].to_s
|
53
|
+
subnet_list << (v["default_for_az"] ? "Yes" : "No")
|
54
|
+
subnet_list << (v["map_public_ip_on_launch"] ? "Yes" : "No")
|
55
|
+
subnet_list << v["vpc_id"]
|
56
|
+
end
|
57
|
+
puts ui.list(subnet_list, :uneven_columns_across, output_column_count)
|
58
|
+
else
|
59
|
+
output(format_for_display(subnet_hash))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# @return [Hash<Hash>]
|
66
|
+
def subnet_hash
|
67
|
+
all_data = {}
|
68
|
+
ec2_connection.describe_subnets.first.subnets.each do |s|
|
69
|
+
s_data = {}
|
70
|
+
%w{subnet_id availability_zone available_ip_address_count cidr_block default_for_az map_public_ip_on_launch state vpc_id}.each do |id|
|
71
|
+
s_data[id] = s.send(id)
|
72
|
+
end
|
73
|
+
all_data[s_data["subnet_id"]] = s_data
|
74
|
+
end
|
75
|
+
all_data
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
#
|
2
|
+
# Author:: Tim Smith (<tsmith@chef.io>)
|
3
|
+
# Copyright:: Copyright (c) 2018 Chef Software, Inc.
|
4
|
+
# License:: Apache License, Version 2.0
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
require "chef/knife/ec2_base"
|
20
|
+
|
21
|
+
class Chef
|
22
|
+
class Knife
|
23
|
+
class Ec2VpcList < Knife
|
24
|
+
|
25
|
+
include Knife::Ec2Base
|
26
|
+
|
27
|
+
banner "knife ec2 vpc list (options)"
|
28
|
+
|
29
|
+
def run
|
30
|
+
validate_aws_config!
|
31
|
+
custom_warnings!
|
32
|
+
|
33
|
+
vpcs_list = [
|
34
|
+
ui.color("ID", :bold),
|
35
|
+
ui.color("State", :bold),
|
36
|
+
ui.color("CIDR Block", :bold),
|
37
|
+
ui.color("Instance Tenancy", :bold),
|
38
|
+
ui.color("DHCP Options ID", :bold),
|
39
|
+
ui.color("Default VPC?", :bold)
|
40
|
+
].flatten.compact
|
41
|
+
|
42
|
+
output_column_count = vpcs_list.length
|
43
|
+
|
44
|
+
if config[:format] == "summary"
|
45
|
+
vpc_hash.each_pair do |_k, v|
|
46
|
+
vpcs_list << v["vpc_id"]
|
47
|
+
vpcs_list << v["state"]
|
48
|
+
vpcs_list << v["cidr_block"]
|
49
|
+
vpcs_list << v["instance_tenancy"]
|
50
|
+
vpcs_list << v["dhcp_options_id"]
|
51
|
+
vpcs_list << (v["is_default"] ? "Yes" : "No")
|
52
|
+
end
|
53
|
+
puts ui.list(vpcs_list, :uneven_columns_across, output_column_count)
|
54
|
+
else
|
55
|
+
output(format_for_display(vpc_hash))
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# @return [Hash<Hash>]
|
62
|
+
def vpc_hash
|
63
|
+
all_data = {}
|
64
|
+
ec2_connection.describe_vpcs.first.vpcs.each do |v|
|
65
|
+
v_data = {}
|
66
|
+
%w{vpc_id cidr_block dhcp_options_id instance_tenancy is_default state}.each do |id|
|
67
|
+
v_data[id] = v.send(id)
|
68
|
+
end
|
69
|
+
all_data[v_data["vpc_id"]] = v_data
|
70
|
+
end
|
71
|
+
all_data
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|