ec2ex 0.1.0 → 0.2.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/README.md +55 -7
- data/ec2ex.gemspec +4 -2
- data/lib/ec2ex/cli.rb +240 -85
- data/lib/ec2ex/core.rb +198 -36
- data/lib/ec2ex/version.rb +1 -1
- metadata +39 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5755c9dc27c67e067cb6813e6e130a830ab2b320
|
4
|
+
data.tar.gz: a3eb2fe48d2cbec37f45dbf310222f6e22891e34
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 689bd524c9c9a9f77d77cb3c3e85d1e588d49cc9e89422e6497a7b0b1881d764995589cd778d9065146a8cf22d36a2ba2369f788f980c3eddbc0b57acc99cd74
|
7
|
+
data.tar.gz: 432de3ba88dc99d2dbae99d36e7371257eb85f6cd1454c41d50629b907d7cf4e04424c919710d04c970d1a1e17441b7da192aac1870f89dae49a51f7c8118ecf
|
data/README.md
CHANGED
@@ -1,19 +1,67 @@
|
|
1
1
|
# ec2ex [](http://travis-ci.org/toyama0919/ec2ex)
|
2
2
|
|
3
|
-
|
3
|
+
## Examples
|
4
4
|
|
5
|
-
|
5
|
+
### Search Instance
|
6
6
|
|
7
|
-
|
7
|
+
```
|
8
|
+
$ ec2ex -s 'stgweb01'
|
9
|
+
```
|
10
|
+
|
11
|
+
### Copy Instance
|
12
|
+
|
13
|
+
```
|
14
|
+
$ ec2ex copy -n "stgembulk01" -t Name:stgembulk02 --public_ip_address auto --instance_count 3
|
15
|
+
```
|
16
|
+
|
17
|
+
### Copy Spot Instance
|
18
|
+
|
19
|
+
```
|
20
|
+
$ ec2ex spot -n "web01" --price 0.5 --private_ip_address 10.0.0.100 -t Name:web02
|
21
|
+
```
|
22
|
+
|
23
|
+
### Deployment Instance
|
24
|
+
|
25
|
+
```
|
26
|
+
$ ec2ex run_spot -n "stgembulk01" --price 0.5
|
27
|
+
```
|
28
|
+
|
29
|
+
### Connect ELB Instance
|
30
|
+
|
31
|
+
```
|
32
|
+
$ ec2ex connect_elb -n "web01" -l elbname
|
33
|
+
```
|
34
|
+
|
35
|
+
### Disconnect ELB Instance
|
36
|
+
|
37
|
+
```
|
38
|
+
$ ec2ex disconnect_elb -n "web02" -l elbname
|
39
|
+
```
|
40
|
+
|
41
|
+
### Terminate Instance
|
42
|
+
|
43
|
+
```
|
44
|
+
$ ec2ex terminate -n web01
|
45
|
+
```
|
46
|
+
|
47
|
+
### Renew Instance
|
48
|
+
|
49
|
+
```
|
50
|
+
$ ec2ex renew -n "presto01" --private-ip-address 10.0.81.201 -p '{iam_instance_profile: { name: "iap-role"} }'
|
51
|
+
```
|
52
|
+
|
53
|
+
### Create AMI with tag
|
54
|
+
|
55
|
+
```
|
56
|
+
$ ec2 create_image -n "presto01"
|
57
|
+
```
|
8
58
|
|
9
|
-
$ ec2ex sample
|
10
|
-
#=> hoge
|
11
59
|
|
12
60
|
## Installation
|
13
61
|
|
14
62
|
Add this line to your application's Gemfile:
|
15
63
|
|
16
|
-
gem 'ec2ex'
|
64
|
+
gem 'ec2ex', github: 'ipros-team/ec2ex'
|
17
65
|
|
18
66
|
And then execute:
|
19
67
|
|
@@ -21,7 +69,7 @@ And then execute:
|
|
21
69
|
|
22
70
|
Or install it yourself as:
|
23
71
|
|
24
|
-
$ gem
|
72
|
+
$ gem specific_install -l https://github.com/ipros-team/ec2ex
|
25
73
|
|
26
74
|
## Contributing
|
27
75
|
|
data/ec2ex.gemspec
CHANGED
@@ -20,10 +20,12 @@ Gem::Specification.new do |gem|
|
|
20
20
|
gem.add_dependency 'thor'
|
21
21
|
gem.add_dependency 'hashie'
|
22
22
|
gem.add_dependency 'ipaddress'
|
23
|
-
gem.add_dependency 'aws-sdk'
|
23
|
+
gem.add_dependency 'aws-sdk'
|
24
24
|
gem.add_dependency 'activesupport'
|
25
|
+
gem.add_dependency 'parallel'
|
26
|
+
gem.add_dependency 'net-ping'
|
25
27
|
|
26
|
-
gem.add_development_dependency 'bundler'
|
28
|
+
gem.add_development_dependency 'bundler'
|
27
29
|
gem.add_development_dependency 'pry', '~> 0.10.1'
|
28
30
|
gem.add_development_dependency 'rake', '~> 10.3.2'
|
29
31
|
gem.add_development_dependency 'rspec', '~> 2.4'
|
data/lib/ec2ex/cli.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'json'
|
3
3
|
require 'pp'
|
4
|
-
require '
|
5
|
-
require 'aws-sdk'
|
4
|
+
require 'parallel'
|
6
5
|
require 'active_support/core_ext/hash'
|
7
6
|
|
8
7
|
module Ec2ex
|
@@ -19,15 +18,16 @@ module Ec2ex
|
|
19
18
|
super(args, options, config)
|
20
19
|
@global_options = config[:shell].base.options
|
21
20
|
@core = Core.new
|
22
|
-
@ec2 =
|
23
|
-
@elb =
|
21
|
+
@ec2 = @core.client
|
22
|
+
@elb = @core.elb_client
|
23
|
+
@logger = @core.logger
|
24
24
|
end
|
25
25
|
|
26
26
|
desc 'search', 'search instance'
|
27
27
|
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
28
28
|
option :running_only, aliases: '--ro', type: :boolean, default: true, desc: 'grouping key'
|
29
|
-
def search(name = options[
|
30
|
-
results = @core.instances_hash({ Name: name }, options[
|
29
|
+
def search(name = options[:name])
|
30
|
+
results = @core.instances_hash({ Name: name }, options[:running_only])
|
31
31
|
puts_json results
|
32
32
|
end
|
33
33
|
|
@@ -35,7 +35,7 @@ module Ec2ex
|
|
35
35
|
option :condition, aliases: '-c', type: :hash, default: {}, desc: 'grouping key'
|
36
36
|
option :running_only, aliases: '--ro', type: :boolean, default: true, desc: 'grouping key'
|
37
37
|
def search_by_tags
|
38
|
-
puts_json @core.instances_hash(options[
|
38
|
+
puts_json @core.instances_hash(options[:condition], options[:running_only])
|
39
39
|
end
|
40
40
|
|
41
41
|
desc 'reserved', 'reserved instance'
|
@@ -50,7 +50,7 @@ module Ec2ex
|
|
50
50
|
list = @core.instances_hash({}, true).select { |instance| instance[:instance_lifecycle].nil? }
|
51
51
|
list = list.map{ |_instance|
|
52
52
|
['instance_type', 'placement.availability_zone'].map do |key|
|
53
|
-
eval("
|
53
|
+
eval("_instance.#{key} ")
|
54
54
|
end.join('_')
|
55
55
|
}
|
56
56
|
result = {}
|
@@ -66,22 +66,64 @@ module Ec2ex
|
|
66
66
|
end
|
67
67
|
|
68
68
|
desc 'create_image', 'create image'
|
69
|
-
option :name, aliases: '-n', type: :string,
|
69
|
+
option :name, aliases: '-n', type: :string, required: true, desc: 'name tag'
|
70
|
+
option :proc, type: :numeric, default: Parallel.processor_count, desc: 'Number of parallel'
|
71
|
+
option :region, aliases: '-r', type: :string, required: false, default: nil, desc: 'region'
|
70
72
|
def create_image
|
71
|
-
results = @core.instances_hash({ Name: options[
|
72
|
-
results
|
73
|
-
|
73
|
+
results = @core.instances_hash({ Name: options[:name] }, false)
|
74
|
+
Parallel.map(results, in_threads: options[:proc]) do |instance|
|
75
|
+
begin
|
76
|
+
@core.create_image_with_instance(instance, options[:region])
|
77
|
+
rescue => e
|
78
|
+
@logger.info "\n#{e.message}\n#{e.backtrace.join("\n")}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
desc 'deregister_image', 'deregister image'
|
84
|
+
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
85
|
+
option :older_than, aliases: '--older_than', type: :numeric, default: 30, desc: 'older than count.'
|
86
|
+
def deregister_image
|
87
|
+
@core.get_old_images(options[:name], options[:older_than]).each do |image|
|
88
|
+
image_id = image[:image_id]
|
89
|
+
@logger.info "delete AMI #{image_id} [#{image[:name]}]"
|
90
|
+
@ec2.deregister_image({image_id: image_id})
|
91
|
+
snapshot_ids = image[:block_device_mappings]
|
92
|
+
.select{ |block_device_mapping| block_device_mapping[:ebs] != nil }
|
93
|
+
.map{ |block_device_mapping| block_device_mapping[:ebs][:snapshot_id] }
|
94
|
+
|
95
|
+
snapshot_ids.each do |snapshot_id|
|
96
|
+
@logger.info "delete snapshot #{snapshot_id}"
|
97
|
+
@ec2.delete_snapshot({snapshot_id: snapshot_id})
|
98
|
+
end
|
74
99
|
end
|
75
100
|
end
|
76
101
|
|
102
|
+
desc 'deregister_image', 'deregister image'
|
103
|
+
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
104
|
+
option :older_than, aliases: '--older_than', type: :numeric, default: 30, desc: 'older than count.'
|
105
|
+
def old_images
|
106
|
+
puts_json(@core.get_old_images(options[:name], options[:older_than]))
|
107
|
+
end
|
108
|
+
|
109
|
+
desc 'deregister_snapshot_no_related', 'AMI not related snapshot basis delete all'
|
110
|
+
option :owner_id, type: :string, required: true, desc: 'owner_id'
|
111
|
+
def deregister_snapshot_no_related
|
112
|
+
@core.deregister_snapshot_no_related(options[:owner_id])
|
113
|
+
end
|
114
|
+
|
77
115
|
desc 'copy', 'copy instance'
|
78
116
|
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
79
117
|
option :params, aliases: '-p', type: :string, default: '{}', desc: 'params'
|
80
118
|
option :tag, aliases: '-t', type: :hash, default: {}, desc: 'name tag'
|
119
|
+
option :private_ip_address, type: :string, default: nil, desc: 'private_ip_address'
|
120
|
+
option :public_ip_address, type: :string, default: nil, desc: 'public_ip_address'
|
121
|
+
option :instance_count, type: :numeric, default: 1, desc: 'instance_count'
|
81
122
|
def copy
|
82
|
-
|
83
|
-
|
84
|
-
|
123
|
+
instance = @core.instances_hash_first_result({ Name: options[:name] }, true)
|
124
|
+
image_id = @core.create_image_with_instance(instance)
|
125
|
+
instance_count = options[:instance_count]
|
126
|
+
Parallel.map(instance_count.times.to_a, in_threads: Parallel.processor_count) do |server_index|
|
85
127
|
security_group_ids = instance.security_groups.map { |security_group| security_group.group_id }
|
86
128
|
request = {
|
87
129
|
image_id: image_id,
|
@@ -89,43 +131,61 @@ module Ec2ex
|
|
89
131
|
max_count: 1,
|
90
132
|
security_group_ids: security_group_ids,
|
91
133
|
instance_type: instance.instance_type,
|
92
|
-
placement: instance.placement.to_hash
|
93
|
-
subnet_id: instance.subnet_id,
|
94
|
-
private_ip_address: instance.private_ip_address
|
134
|
+
placement: instance.placement.to_hash
|
95
135
|
}
|
96
|
-
|
136
|
+
request[:private_ip_address] = options[:private_ip_address] if options[:private_ip_address]
|
137
|
+
if instance.iam_instance_profile
|
97
138
|
request[:iam_instance_profile] = { name: instance.iam_instance_profile.arn.split('/').last }
|
98
139
|
end
|
99
|
-
|
100
|
-
|
140
|
+
if instance.key_name
|
141
|
+
request[:key_name] = instance.key_name
|
142
|
+
end
|
143
|
+
|
144
|
+
request.merge!(eval(options[:params]))
|
145
|
+
request[:subnet_id] = if request[:private_ip_address]
|
146
|
+
@core.get_subnet(request[:private_ip_address]).subnet_id
|
147
|
+
else
|
148
|
+
instance.subnet_id
|
149
|
+
end
|
101
150
|
|
102
151
|
response = @ec2.run_instances(request)
|
103
152
|
instance_id = response.instances.first.instance_id
|
104
153
|
@ec2.wait_until(:instance_running, instance_ids: [instance_id])
|
105
154
|
@ec2.create_tags(resources: [instance_id], tags: instance.tags)
|
106
|
-
|
107
|
-
|
155
|
+
@ec2.create_tags(resources: [instance_id], tags: [{ key: 'InstanceIndex', value: "#{server_index}" }])
|
156
|
+
@ec2.create_tags(resources: [instance_id], tags: [{ key: 'InstanceCount', value: "#{instance_count}" }])
|
157
|
+
unless options[:tag].nil?
|
158
|
+
@ec2.create_tags(
|
159
|
+
resources: [instance_id],
|
160
|
+
tags: @core.format_tag(
|
161
|
+
options[:tag],
|
162
|
+
@core.get_tag_hash_from_id(instance_id)
|
163
|
+
)
|
164
|
+
)
|
108
165
|
end
|
166
|
+
public_ip_address = get_public_ip_address(options[:public_ip_address], instance.public_ip_address, false)
|
167
|
+
@core.associate_address(instance_id, public_ip_address)
|
168
|
+
@logger.info("created instance => #{instance_id}")
|
109
169
|
end
|
110
170
|
end
|
111
171
|
|
112
172
|
desc 'renew', 'renew instance'
|
113
173
|
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
114
174
|
option :stop, type: :boolean, default: true, desc: 'stop'
|
115
|
-
option :params, aliases: '-p', type: :string, default:
|
175
|
+
option :params, aliases: '-p', type: :string, default: '{}', desc: 'params'
|
116
176
|
def renew
|
117
|
-
params = eval(options[
|
118
|
-
results = @core.instances_hash({ Name: options[
|
177
|
+
params = eval(options[:params])
|
178
|
+
results = @core.instances_hash({ Name: options[:name] }, false)
|
119
179
|
results.each do |instance|
|
120
180
|
tags = instance.tags
|
121
181
|
tag_hash = @core.get_tag_hash(tags)
|
122
|
-
if options[
|
182
|
+
if options[:stop]
|
123
183
|
@core.stop_instance(instance.instance_id)
|
124
184
|
end
|
125
185
|
|
126
186
|
image_id = @core.create_image_with_instance(instance)
|
127
187
|
|
128
|
-
@core.terminate_instance(instance
|
188
|
+
@core.terminate_instance(instance)
|
129
189
|
security_group_ids = instance.security_groups.map { |security_group| security_group.group_id }
|
130
190
|
request = {
|
131
191
|
image_id: image_id,
|
@@ -136,9 +196,13 @@ module Ec2ex
|
|
136
196
|
placement: instance.placement.to_hash,
|
137
197
|
private_ip_address: instance.private_ip_address
|
138
198
|
}
|
139
|
-
|
199
|
+
if instance.iam_instance_profile
|
140
200
|
request[:iam_instance_profile] = { name: instance.iam_instance_profile.arn.split('/').last }
|
141
201
|
end
|
202
|
+
|
203
|
+
if instance.key_name
|
204
|
+
request[:key_name] = instance.key_name
|
205
|
+
end
|
142
206
|
request.merge!(params)
|
143
207
|
request[:subnet_id] = @core.get_subnet(request[:private_ip_address]).subnet_id
|
144
208
|
|
@@ -157,18 +221,26 @@ module Ec2ex
|
|
157
221
|
option :price, type: :string, required: true, desc: 'price'
|
158
222
|
option :private_ip_address, type: :string, default: nil, desc: 'private_ip_address'
|
159
223
|
option :public_ip_address, type: :string, default: nil, desc: 'public_ip_address'
|
224
|
+
option :block_duration_minutes, type: :numeric, default: nil, desc: 'block_duration_minutes'
|
160
225
|
option :params, aliases: '-p', type: :string, default: '{}', desc: 'params'
|
161
226
|
option :tag, aliases: '-t', type: :hash, default: {}, desc: 'name tag'
|
162
227
|
option :renew, aliases: '-r', type: :boolean, default: false, desc: 'renew instance'
|
163
228
|
option :persistent, type: :boolean, default: false, desc: 'persistent request'
|
229
|
+
option :stop, type: :boolean, default: false, desc: 'stop'
|
230
|
+
option :instance_count, type: :numeric, default: 1, desc: 'instance_count'
|
164
231
|
def spot
|
165
|
-
|
166
|
-
|
167
|
-
|
232
|
+
instance = @core.instances_hash_first_result({ Name: options[:name] }, true)
|
233
|
+
if options[:stop]
|
234
|
+
@core.stop_instance(instance.instance_id)
|
235
|
+
end
|
236
|
+
image_id = @core.create_image_with_instance(instance)
|
237
|
+
|
238
|
+
instance_count = options[:instance_count]
|
239
|
+
Parallel.map(instance_count.times.to_a, in_threads: Parallel.processor_count) do |server_index|
|
168
240
|
security_group_ids = instance.security_groups.map { |security_group| security_group.group_id }
|
169
241
|
option = {
|
170
242
|
instance_count: 1,
|
171
|
-
spot_price: options[
|
243
|
+
spot_price: options[:price],
|
172
244
|
launch_specification: {
|
173
245
|
image_id: image_id,
|
174
246
|
instance_type: instance.instance_type,
|
@@ -176,52 +248,61 @@ module Ec2ex
|
|
176
248
|
subnet_id: instance.subnet_id
|
177
249
|
},
|
178
250
|
}
|
179
|
-
option[:type] = 'persistent' if options[
|
251
|
+
option[:type] = 'persistent' if options[:persistent]
|
252
|
+
option[:block_duration_minutes] = options[:block_duration_minutes] if options[:block_duration_minutes]
|
180
253
|
|
181
|
-
|
254
|
+
if instance.iam_instance_profile
|
182
255
|
option[:launch_specification][:iam_instance_profile] = { name: instance.iam_instance_profile.arn.split('/').last }
|
183
256
|
end
|
184
257
|
|
185
|
-
|
258
|
+
if instance.key_name
|
259
|
+
option[:launch_specification][:key_name] = instance.key_name
|
260
|
+
end
|
261
|
+
|
262
|
+
option[:launch_specification].merge!(eval(options[:params]))
|
186
263
|
|
187
264
|
private_ip_address = nil
|
188
|
-
if options[
|
189
|
-
private_ip_address = instance.private_ip_address if options[
|
265
|
+
if options[:private_ip_address].nil?
|
266
|
+
private_ip_address = instance.private_ip_address if options[:renew]
|
190
267
|
else
|
191
|
-
private_ip_address = options[
|
268
|
+
private_ip_address = options[:private_ip_address]
|
192
269
|
end
|
193
270
|
|
194
|
-
|
271
|
+
if private_ip_address
|
195
272
|
network_interface = {
|
196
273
|
device_index: 0,
|
197
274
|
subnet_id: @core.get_subnet(private_ip_address).subnet_id,
|
198
|
-
groups: security_group_ids,
|
275
|
+
groups: option[:launch_specification][:security_group_ids],
|
199
276
|
private_ip_addresses: [{ private_ip_address: private_ip_address, primary: true }]
|
200
277
|
}
|
201
278
|
option[:launch_specification][:network_interfaces] = [network_interface]
|
202
279
|
option[:launch_specification].delete(:security_group_ids)
|
203
280
|
option[:launch_specification].delete(:subnet_id)
|
204
281
|
end
|
205
|
-
@core.terminate_instance(instance
|
282
|
+
@core.terminate_instance(instance) if options[:renew]
|
206
283
|
|
207
284
|
response = @ec2.request_spot_instances(option)
|
208
285
|
spot_instance_request_id = response.spot_instance_requests.first.spot_instance_request_id
|
209
286
|
sleep 5
|
210
287
|
instance_id = @core.wait_spot_running(spot_instance_request_id)
|
288
|
+
@core.set_delete_on_termination(@core.instances_hash_with_id(instance_id))
|
211
289
|
|
212
290
|
@ec2.create_tags(resources: [instance_id], tags: instance.tags)
|
213
291
|
@ec2.create_tags(resources: [instance_id], tags: [{ key: 'Spot', value: 'true' }])
|
214
|
-
|
215
|
-
|
216
|
-
|
292
|
+
@ec2.create_tags(resources: [instance_id], tags: [{ key: 'InstanceIndex', value: "#{server_index}" }])
|
293
|
+
@ec2.create_tags(resources: [instance_id], tags: [{ key: 'InstanceCount', value: "#{instance_count}" }])
|
294
|
+
|
295
|
+
unless options[:tag].empty?
|
296
|
+
@ec2.create_tags(
|
297
|
+
resources: [instance_id],
|
298
|
+
tags: @core.format_tag(
|
299
|
+
options[:tag],
|
300
|
+
@core.get_tag_hash_from_id(instance_id)
|
301
|
+
)
|
302
|
+
)
|
217
303
|
end
|
218
304
|
|
219
|
-
public_ip_address =
|
220
|
-
if options['public_ip_address'].nil?
|
221
|
-
public_ip_address = instance.public_ip_address if options['renew']
|
222
|
-
else
|
223
|
-
public_ip_address = options['public_ip_address']
|
224
|
-
end
|
305
|
+
public_ip_address = get_public_ip_address(options[:public_ip_address], instance.public_ip_address, options[:renew])
|
225
306
|
@core.associate_address(instance_id, public_ip_address)
|
226
307
|
end
|
227
308
|
end
|
@@ -229,34 +310,49 @@ module Ec2ex
|
|
229
310
|
desc 'run_spot', 'run_spot latest image'
|
230
311
|
option :name, aliases: '-n', type: :string, required: true, desc: 'name tag'
|
231
312
|
option :price, type: :string, required: true, desc: 'price'
|
313
|
+
option :private_ip_address, type: :string, default: nil, desc: 'private_ip_address'
|
314
|
+
option :params, aliases: '-p', type: :string, default: '{}', desc: 'params'
|
315
|
+
option :block_duration_minutes, type: :numeric, default: nil, desc: 'block_duration_minutes'
|
232
316
|
def run_spot
|
233
|
-
image = @core.latest_image_with_name(options[
|
317
|
+
image = @core.latest_image_with_name(options[:name])
|
318
|
+
|
234
319
|
tag_hash = @core.get_tag_hash(image[:tags])
|
320
|
+
private_ip_address = options[:private_ip_address] || tag_hash.private_ip_address
|
321
|
+
exit 0 if @core.ping?(private_ip_address)
|
322
|
+
|
235
323
|
option = {
|
236
324
|
instance_count: 1,
|
237
|
-
spot_price: options[
|
325
|
+
spot_price: options[:price],
|
238
326
|
launch_specification: {
|
239
327
|
image_id: image[:image_id],
|
240
328
|
instance_type: tag_hash.instance_type
|
241
329
|
},
|
242
330
|
}
|
243
331
|
|
332
|
+
option[:block_duration_minutes] = options[:block_duration_minutes] if options[:block_duration_minutes]
|
333
|
+
|
244
334
|
if tag_hash.iam_instance_profile
|
245
335
|
option[:launch_specification][:iam_instance_profile] = { name: tag_hash.iam_instance_profile }
|
246
336
|
end
|
247
337
|
|
338
|
+
if tag_hash.key_name
|
339
|
+
option[:launch_specification][:key_name] = tag_hash.key_name
|
340
|
+
end
|
341
|
+
|
248
342
|
network_interface = {
|
249
343
|
device_index: 0,
|
250
|
-
subnet_id: @core.get_subnet(
|
344
|
+
subnet_id: @core.get_subnet(private_ip_address).subnet_id,
|
251
345
|
groups: JSON.parse(tag_hash.security_groups),
|
252
|
-
private_ip_addresses: [{ private_ip_address:
|
346
|
+
private_ip_addresses: [{ private_ip_address: private_ip_address, primary: true }]
|
253
347
|
}
|
254
348
|
option[:launch_specification][:network_interfaces] = [network_interface]
|
349
|
+
option[:launch_specification].merge!(eval(options[:params]))
|
255
350
|
|
256
351
|
response = @ec2.request_spot_instances(option)
|
257
352
|
spot_instance_request_id = response.spot_instance_requests.first.spot_instance_request_id
|
258
353
|
sleep 5
|
259
354
|
instance_id = @core.wait_spot_running(spot_instance_request_id)
|
355
|
+
@core.set_delete_on_termination(@core.instances_hash_with_id(instance_id))
|
260
356
|
@ec2.create_tags(resources: [instance_id], tags: JSON.parse(tag_hash[:tags]))
|
261
357
|
|
262
358
|
if tag_hash.public_ip_address
|
@@ -268,7 +364,7 @@ module Ec2ex
|
|
268
364
|
option :acl_id, type: :string, default: '', required: true, desc: 'name tag'
|
269
365
|
option :ip_address, type: :string, default: '', required: true, desc: 'name tag'
|
270
366
|
def regist_deny_acl
|
271
|
-
acls = @ec2.describe_network_acls(network_acl_ids: [options[
|
367
|
+
acls = @ec2.describe_network_acls(network_acl_ids: [options[:acl_id]])
|
272
368
|
|
273
369
|
allow_any_rule_number = acls.network_acls.first.entries.select {|r|
|
274
370
|
!r.egress && r.cidr_block == '0.0.0.0/0' && r.rule_action == 'allow'
|
@@ -280,13 +376,13 @@ module Ec2ex
|
|
280
376
|
|
281
377
|
next_rule_number = deny_rules.empty? ? 1 : deny_rules.last.rule_number + 1
|
282
378
|
|
283
|
-
unless deny_rules.any? { |r| r.cidr_block == "#{options[
|
379
|
+
unless deny_rules.any? { |r| r.cidr_block == "#{options[:ip_address]}/32" }
|
284
380
|
option = {
|
285
|
-
network_acl_id: options[
|
381
|
+
network_acl_id: options[:acl_id],
|
286
382
|
rule_number: next_rule_number,
|
287
383
|
rule_action: 'deny',
|
288
384
|
protocol: '-1',
|
289
|
-
cidr_block: "#{options[
|
385
|
+
cidr_block: "#{options[:ip_address]}/32",
|
290
386
|
egress: false
|
291
387
|
}
|
292
388
|
@ec2.create_network_acl_entry(option)
|
@@ -296,7 +392,7 @@ module Ec2ex
|
|
296
392
|
desc 'delete_deny_acl_all', 'delete deny acl'
|
297
393
|
option :acl_id, type: :string, required: true, desc: 'name tag'
|
298
394
|
def delete_deny_acl_all
|
299
|
-
acls = @ec2.describe_network_acls(network_acl_ids: [options[
|
395
|
+
acls = @ec2.describe_network_acls(network_acl_ids: [options[:acl_id]])
|
300
396
|
|
301
397
|
allow_any_rule_number = acls.network_acl_set.first.entries.select {|r|
|
302
398
|
!r.egress && r.cidr_block == '0.0.0.0/0' && r.rule_action == 'allow'
|
@@ -308,7 +404,7 @@ module Ec2ex
|
|
308
404
|
|
309
405
|
deny_rules.each do |deny_rule|
|
310
406
|
option = {
|
311
|
-
network_acl_id: options[
|
407
|
+
network_acl_id: options[:acl_id],
|
312
408
|
rule_number: deny_rule.rule_number,
|
313
409
|
egress: false
|
314
410
|
}
|
@@ -334,25 +430,34 @@ module Ec2ex
|
|
334
430
|
desc 'copy_tag', 'request spot instances'
|
335
431
|
option :source, aliases: '--src', type: :string, default: nil, required: true, desc: 'name tag'
|
336
432
|
option :dest, aliases: '--dest', type: :string, default: nil, required: true, desc: 'name tag'
|
337
|
-
def copy_tag(_name = options[
|
338
|
-
source = @core.instances_hash({ Name: options[
|
339
|
-
dest = @core.instances_hash({ Name: options[
|
433
|
+
def copy_tag(_name = options[:name])
|
434
|
+
source = @core.instances_hash({ Name: options[:source] }, true)
|
435
|
+
dest = @core.instances_hash({ Name: options[:dest] }, true)
|
340
436
|
@ec2.create_tags(resources: dest.map { |instance| instance.instance_id }, tags: source.first.tags)
|
341
|
-
@ec2.create_tags(resources: dest.map { |instance| instance.instance_id }, tags: [{ key: 'Name', value: options[
|
437
|
+
@ec2.create_tags(resources: dest.map { |instance| instance.instance_id }, tags: [{ key: 'Name', value: options[:dest] }])
|
342
438
|
end
|
343
439
|
|
344
440
|
desc 'set_tag', 'set tag'
|
345
441
|
option :name, aliases: '-n', type: :string, required: true, desc: 'name tag'
|
346
442
|
option :tag, aliases: '-t', type: :hash, required: true, desc: 'name tag'
|
347
443
|
def set_tag
|
348
|
-
instances = @core.instances_hash({ Name: options[
|
349
|
-
tags = @core.format_tag(options[
|
444
|
+
instances = @core.instances_hash({ Name: options[:name] }, true)
|
445
|
+
tags = @core.format_tag(options[:tag])
|
350
446
|
@ec2.create_tags(resources: instances.map { |instance| instance.instance_id }, tags: tags)
|
351
447
|
end
|
352
448
|
|
449
|
+
desc 'set_delete_on_termination', 'set delete on termination instance'
|
450
|
+
option :name, aliases: '-n', type: :string, required: true, desc: 'name tag'
|
451
|
+
def set_delete_on_termination
|
452
|
+
@core.instances_hash({ Name: options[:name] }, true).each do |instance|
|
453
|
+
@core.set_delete_on_termination(instance)
|
454
|
+
@logger.info "set delete on termination => #{instance.instance_id}"
|
455
|
+
end
|
456
|
+
end
|
457
|
+
|
353
458
|
desc 'search_images', 'search images'
|
354
459
|
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
355
|
-
def search_images(name = options[
|
460
|
+
def search_images(name = options[:name])
|
356
461
|
puts_json @core.images(name)
|
357
462
|
end
|
358
463
|
|
@@ -361,8 +466,8 @@ module Ec2ex
|
|
361
466
|
option :key, aliases: '-k', type: :array, required: true, desc: 'grouping key'
|
362
467
|
option :running_only, aliases: '--ro', type: :boolean, default: true, desc: 'grouping key'
|
363
468
|
def aggregate
|
364
|
-
list = @core.instances_hash(options[
|
365
|
-
options[
|
469
|
+
list = @core.instances_hash(options[:condition], options[:running_only]).map do |instance|
|
470
|
+
options[:key].map do |key|
|
366
471
|
eval("instance.#{key} ")
|
367
472
|
end.join('_')
|
368
473
|
end
|
@@ -372,7 +477,7 @@ module Ec2ex
|
|
372
477
|
desc 'reboot', 'reboot instance'
|
373
478
|
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
374
479
|
def reboot
|
375
|
-
@core.instances_hash({ Name: options[
|
480
|
+
@core.instances_hash({ Name: options[:name] }, true).each do |instance|
|
376
481
|
@ec2.reboot_instances(instance_ids: [instance.instance_id])
|
377
482
|
sleep 5
|
378
483
|
@ec2.wait_until(:instance_running, instance_ids: [instance.instance_id])
|
@@ -382,13 +487,13 @@ module Ec2ex
|
|
382
487
|
desc 'stop_start', 'stop after start instance'
|
383
488
|
option :names, aliases: '-n', type: :array, default: [], required: true, desc: 'name tag'
|
384
489
|
def stop_start
|
385
|
-
options[
|
490
|
+
options[:names].each do |name|
|
386
491
|
@core.instances_hash({ Name: name }, true).each do |instance|
|
387
492
|
instance.stop
|
388
493
|
@ec2.wait_until(:instance_stopped, instance_ids: [instance.instance_id])
|
389
494
|
instance.start
|
390
495
|
@ec2.wait_until(:instance_running, instance_ids: [instance.instance_id])
|
391
|
-
|
496
|
+
@logger.info "#{instance.tags['Name']} restart complete!"
|
392
497
|
end
|
393
498
|
end
|
394
499
|
end
|
@@ -396,25 +501,34 @@ module Ec2ex
|
|
396
501
|
desc 'terminate', 'terminate instance'
|
397
502
|
option :name, aliases: '-n', type: :string, required: true, desc: 'name tag'
|
398
503
|
def terminate
|
399
|
-
@core.instances_hash({ Name: options[
|
400
|
-
|
504
|
+
instances = @core.instances_hash({ Name: options[:name] }, false)
|
505
|
+
Parallel.map(instances, in_threads: Parallel.processor_count) do |instance|
|
506
|
+
@core.terminate_instance(instance)
|
401
507
|
end
|
402
508
|
end
|
403
509
|
|
404
|
-
desc '
|
510
|
+
desc 'start', 'start instance'
|
405
511
|
option :name, aliases: '-n', type: :string, required: true, desc: 'name tag'
|
406
512
|
def start
|
407
|
-
@core.instances_hash({ Name: options[
|
513
|
+
@core.instances_hash({ Name: options[:name] }, false).each do |instance|
|
408
514
|
@core.start_instance(instance.instance_id)
|
409
515
|
end
|
410
516
|
end
|
411
517
|
|
518
|
+
desc 'stop', 'stop instance'
|
519
|
+
option :name, aliases: '-n', type: :string, required: true, desc: 'name tag'
|
520
|
+
def stop
|
521
|
+
@core.instances_hash({ Name: options[:name] }, false).each do |instance|
|
522
|
+
@core.stop_instance(instance.instance_id)
|
523
|
+
end
|
524
|
+
end
|
525
|
+
|
412
526
|
desc 'connect elb', 'connect elb'
|
413
527
|
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
414
528
|
option :load_balancer_name, aliases: '-l', type: :string, default: '', required: true, desc: 'name tag'
|
415
|
-
def connect_elb(_name = options[
|
416
|
-
@core.instances_hash({ Name: options[
|
417
|
-
option = { load_balancer_name: options[
|
529
|
+
def connect_elb(_name = options[:name])
|
530
|
+
@core.instances_hash({ Name: options[:name] }, true).each do |instance|
|
531
|
+
option = { load_balancer_name: options[:load_balancer_name], instances: [instance_id: instance.instance_id] }
|
418
532
|
@elb.deregister_instances_from_load_balancer(option)
|
419
533
|
@elb.register_instances_with_load_balancer(option)
|
420
534
|
print 'connecting ELB...'
|
@@ -426,6 +540,16 @@ module Ec2ex
|
|
426
540
|
end
|
427
541
|
end
|
428
542
|
|
543
|
+
desc 'disconnect elb', 'disconnect elb'
|
544
|
+
option :name, aliases: '-n', type: :string, default: '', required: true, desc: 'name tag'
|
545
|
+
option :load_balancer_name, aliases: '-l', type: :string, default: '', required: true, desc: 'name tag'
|
546
|
+
def disconnect_elb
|
547
|
+
@core.instances_hash({ Name: options[:name] }, true).each do |instance|
|
548
|
+
option = { load_balancer_name: options[:load_balancer_name], instances: [instance_id: instance.instance_id] }
|
549
|
+
@elb.deregister_instances_from_load_balancer(option)
|
550
|
+
end
|
551
|
+
end
|
552
|
+
|
429
553
|
desc 'elbs', 'show elbs'
|
430
554
|
def elbs
|
431
555
|
puts_json @elb.describe_load_balancers.data.to_h[:load_balancer_descriptions]
|
@@ -452,25 +576,56 @@ module Ec2ex
|
|
452
576
|
desc 'latest_image', 'show elbs'
|
453
577
|
option :name, aliases: '-n', type: :string, required: true, desc: 'name tag'
|
454
578
|
def latest_image
|
455
|
-
puts_json @core.latest_image_with_name(options[
|
579
|
+
puts_json @core.latest_image_with_name(options[:name])
|
456
580
|
end
|
457
581
|
|
458
582
|
desc 'allocate_address', 'allocate address'
|
459
|
-
def
|
460
|
-
response = @
|
583
|
+
def allocate_address_vpc
|
584
|
+
response = @core.allocate_address_vpc
|
585
|
+
puts response.data
|
586
|
+
end
|
587
|
+
|
588
|
+
desc 'instance_metadata', 'instance metadata'
|
589
|
+
option :path, type: :string, required: true, desc: 'path'
|
590
|
+
def instance_metadata
|
591
|
+
response = @core.get_metadata(options[:path])
|
461
592
|
puts response
|
462
593
|
end
|
463
594
|
|
595
|
+
desc 'own_tag', 'own tag'
|
596
|
+
option :key, type: :string, desc: 'key'
|
597
|
+
def own_tag
|
598
|
+
response = @core.own_tag
|
599
|
+
if options[:key]
|
600
|
+
puts response[options[:key]]
|
601
|
+
else
|
602
|
+
puts_json response
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
464
606
|
private
|
465
607
|
def instances(name, _running_only = true)
|
466
608
|
@ec2.instances.with_tag('Name', "#{name}")
|
467
609
|
end
|
468
610
|
|
469
611
|
def puts_json(data)
|
470
|
-
unless @global_options[
|
471
|
-
data = @core.extract_fields(data, @global_options[
|
612
|
+
unless @global_options[:fields].nil?
|
613
|
+
data = @core.extract_fields(data, @global_options[:fields])
|
472
614
|
end
|
473
615
|
puts JSON.pretty_generate(data)
|
474
616
|
end
|
617
|
+
|
618
|
+
def get_public_ip_address(define_public_ip_address, instance_public_ip_address, renew)
|
619
|
+
public_ip_address = nil
|
620
|
+
if define_public_ip_address == 'auto'
|
621
|
+
allocate_address_result = @core.allocate_address_vpc
|
622
|
+
public_ip_address = allocate_address_result.public_ip
|
623
|
+
elsif define_public_ip_address.nil?
|
624
|
+
public_ip_address = instance_public_ip_address if renew
|
625
|
+
else
|
626
|
+
public_ip_address = define_public_ip_address
|
627
|
+
end
|
628
|
+
public_ip_address
|
629
|
+
end
|
475
630
|
end
|
476
631
|
end
|
data/lib/ec2ex/core.rb
CHANGED
@@ -1,10 +1,47 @@
|
|
1
1
|
require 'aws-sdk'
|
2
2
|
require 'ipaddress'
|
3
|
+
require 'open-uri'
|
4
|
+
require "logger"
|
5
|
+
require 'hashie'
|
6
|
+
require 'net/ping'
|
3
7
|
|
8
|
+
TIME_OUT = 3
|
4
9
|
module Ec2ex
|
5
10
|
class Core
|
6
11
|
def initialize
|
12
|
+
ENV['AWS_REGION'] = ENV['AWS_REGION'] || get_document['region']
|
7
13
|
@ec2 = Aws::EC2::Client.new
|
14
|
+
@elb = Aws::ElasticLoadBalancing::Client.new
|
15
|
+
@logger = Logger.new(STDOUT);
|
16
|
+
end
|
17
|
+
|
18
|
+
def client
|
19
|
+
@ec2
|
20
|
+
end
|
21
|
+
|
22
|
+
def logger
|
23
|
+
@logger
|
24
|
+
end
|
25
|
+
|
26
|
+
def get_document
|
27
|
+
JSON.parse(get_metadata('/latest/dynamic/instance-identity/document/'))
|
28
|
+
end
|
29
|
+
|
30
|
+
def get_metadata(path)
|
31
|
+
begin
|
32
|
+
result = {}
|
33
|
+
::Timeout.timeout(TIME_OUT) {
|
34
|
+
body = open('http://169.254.169.254' + path).read
|
35
|
+
return body
|
36
|
+
}
|
37
|
+
return result
|
38
|
+
rescue TimeoutError => e
|
39
|
+
raise "not EC2 instance"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def elb_client
|
44
|
+
@elb
|
8
45
|
end
|
9
46
|
|
10
47
|
def extract_fields(data, fields)
|
@@ -24,10 +61,11 @@ module Ec2ex
|
|
24
61
|
Hash[list.group_by { |e| e }.map { |k, v| [k, v.length] }]
|
25
62
|
end
|
26
63
|
|
27
|
-
def format_tag(tag)
|
64
|
+
def format_tag(tag, preset_tag_hash = {})
|
28
65
|
tags = []
|
29
66
|
tag.each do |k, v|
|
30
|
-
|
67
|
+
value = v ? ERB.new(v.gsub(/\$\{([^}]+)\}/, "<%=preset_tag_hash['" + '\1' + "'] %>")).result(binding) : ''
|
68
|
+
tags << { key: k, value: value }
|
31
69
|
end
|
32
70
|
tags
|
33
71
|
end
|
@@ -40,6 +78,14 @@ module Ec2ex
|
|
40
78
|
Hashie::Mash.new(result)
|
41
79
|
end
|
42
80
|
|
81
|
+
def get_tag_hash_from_id(instance_id)
|
82
|
+
preset_tag = {}
|
83
|
+
@ec2.describe_tags(filters: [{ name: 'resource-id', values: [instance_id] }]).tags.each do |tag|
|
84
|
+
preset_tag[tag.key] = tag.value
|
85
|
+
end
|
86
|
+
preset_tag
|
87
|
+
end
|
88
|
+
|
43
89
|
def instances_hash(condition, running_only = true)
|
44
90
|
filter = []
|
45
91
|
condition.each do |key, value|
|
@@ -55,66 +101,113 @@ module Ec2ex
|
|
55
101
|
).data.to_h[:reservations].map { |instance| Hashie::Mash.new(instance[:instances].first) }
|
56
102
|
end
|
57
103
|
|
58
|
-
def
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
104
|
+
def instances_hash_first_result(condition, running_only = true)
|
105
|
+
results = instances_hash(condition, running_only)
|
106
|
+
instance = results.first
|
107
|
+
unless instance
|
108
|
+
@logger.warn("not match instance => #{condition}")
|
109
|
+
exit 1
|
110
|
+
end
|
111
|
+
instance
|
64
112
|
end
|
65
113
|
|
66
|
-
def
|
67
|
-
|
68
|
-
|
69
|
-
|
114
|
+
def instances_hash_with_id(instance_id)
|
115
|
+
@ec2.describe_instances(
|
116
|
+
instance_ids: [instance_id]
|
117
|
+
).data.to_h[:reservations].map { |instance| Hashie::Mash.new(instance[:instances].first) }.first
|
118
|
+
end
|
119
|
+
|
120
|
+
def own_tag
|
121
|
+
get_tag_hash(instances_hash_with_id(get_metadata('/latest/meta-data/instance-id')).tags)
|
122
|
+
end
|
123
|
+
|
124
|
+
def get_ami_tag_hash(instance, tags)
|
125
|
+
ami_tag_hash = {
|
70
126
|
'created' => Time.now.strftime('%Y%m%d%H%M%S'),
|
71
127
|
'tags' => instance.tags.map(&:to_hash).to_json,
|
72
128
|
'Name' => tags['Name']
|
73
129
|
}
|
74
|
-
|
75
|
-
|
130
|
+
ami_tag_hash['security_groups'] = instance.security_groups.map(&:group_id).to_json
|
131
|
+
ami_tag_hash['private_ip_address'] = instance.private_ip_address
|
76
132
|
unless instance.public_ip_address.nil?
|
77
|
-
|
133
|
+
ami_tag_hash['public_ip_address'] = instance.public_ip_address
|
78
134
|
end
|
79
|
-
|
80
|
-
|
135
|
+
ami_tag_hash['instance_type'] = instance.instance_type
|
136
|
+
ami_tag_hash['placement'] = instance.placement.to_hash.to_json
|
81
137
|
unless instance.iam_instance_profile.nil?
|
82
|
-
|
138
|
+
ami_tag_hash['iam_instance_profile'] = instance.iam_instance_profile.arn.split('/').last
|
83
139
|
end
|
140
|
+
unless instance.key_name.nil?
|
141
|
+
ami_tag_hash['key_name'] = instance.key_name
|
142
|
+
end
|
143
|
+
ami_tag_hash
|
144
|
+
end
|
84
145
|
|
146
|
+
def create_image_with_instance(instance, region = nil)
|
147
|
+
tags = get_tag_hash(instance.tags)
|
148
|
+
@logger.info "#{tags['Name']} image creating..."
|
149
|
+
|
150
|
+
image_name = tags['Name'] + ".#{Time.now.strftime('%Y%m%d%H%M%S')}"
|
85
151
|
image_response = @ec2.create_image(
|
86
152
|
instance_id: instance.instance_id,
|
87
|
-
name:
|
153
|
+
name: image_name,
|
88
154
|
no_reboot: true
|
89
155
|
)
|
90
156
|
sleep 10
|
91
157
|
@ec2.wait_until(:image_available, image_ids: [image_response.image_id]) do |w|
|
92
158
|
w.interval = 15
|
93
|
-
w.max_attempts =
|
159
|
+
w.max_attempts = 1440
|
94
160
|
end
|
95
|
-
|
161
|
+
@logger.info "image create complete #{tags['Name']}! image_id => [#{image_response.image_id}]"
|
96
162
|
|
97
|
-
ami_tag = format_tag(
|
163
|
+
ami_tag = format_tag(get_ami_tag_hash(instance, tags))
|
98
164
|
@ec2.create_tags(resources: [image_response.image_id], tags: ami_tag)
|
165
|
+
|
166
|
+
if region
|
167
|
+
@logger.info "copying another region... [#{ENV['AWS_REGION']}] => [#{region}]"
|
168
|
+
dest_ec2 = Aws::EC2::Client.new(region: region)
|
169
|
+
copy_image_response = dest_ec2.copy_image(
|
170
|
+
source_region: ENV['AWS_REGION'],
|
171
|
+
source_image_id: image_response.image_id,
|
172
|
+
name: image_name
|
173
|
+
)
|
174
|
+
dest_ec2.create_tags(resources: [copy_image_response.image_id], tags: ami_tag)
|
175
|
+
end
|
176
|
+
|
99
177
|
image_response.image_id
|
100
178
|
end
|
101
179
|
|
102
180
|
def wait_spot_running(spot_instance_request_id)
|
103
|
-
|
181
|
+
@logger.info 'spot instance creating...'
|
104
182
|
instance_id = nil
|
105
183
|
while true
|
106
184
|
spot_instance_request = @ec2.describe_spot_instance_requests(spot_instance_request_ids: [spot_instance_request_id]).spot_instance_requests.first
|
107
185
|
if spot_instance_request.state == 'active'
|
108
186
|
instance_id = spot_instance_request.instance_id
|
109
187
|
break
|
188
|
+
elsif spot_instance_request.state == 'failed'
|
189
|
+
@logger.info spot_instance_request.fault.code
|
190
|
+
@ec2.cancel_spot_instance_requests({ spot_instance_request_ids: [spot_instance_request_id] })
|
191
|
+
raise spot_instance_request.fault.message
|
110
192
|
end
|
111
193
|
sleep 10
|
112
194
|
end
|
113
195
|
@ec2.wait_until(:instance_running, instance_ids: [instance_id])
|
114
|
-
|
196
|
+
@logger.info "spot instance create complete! instance_id => [#{instance_id}]"
|
115
197
|
instance_id
|
116
198
|
end
|
117
199
|
|
200
|
+
def set_delete_on_termination(instance)
|
201
|
+
block_device_mappings = instance.block_device_mappings.map{ |block_device_mapping|
|
202
|
+
ebs = block_device_mapping.ebs
|
203
|
+
{
|
204
|
+
device_name: block_device_mapping.device_name,
|
205
|
+
ebs: { volume_id: block_device_mapping.ebs.volume_id, delete_on_termination: true }
|
206
|
+
}
|
207
|
+
}
|
208
|
+
@ec2.modify_instance_attribute({instance_id: instance.instance_id, block_device_mappings: block_device_mappings})
|
209
|
+
end
|
210
|
+
|
118
211
|
def get_allocation(public_ip_address)
|
119
212
|
@ec2.describe_addresses(public_ips: [public_ip_address]).addresses.first
|
120
213
|
end
|
@@ -128,29 +221,30 @@ module Ec2ex
|
|
128
221
|
end
|
129
222
|
|
130
223
|
def stop_instance(instance_id)
|
131
|
-
|
224
|
+
@logger.info 'stopping...'
|
132
225
|
@ec2.stop_instances(
|
133
226
|
instance_ids: [instance_id],
|
134
227
|
force: true
|
135
228
|
)
|
136
229
|
@ec2.wait_until(:instance_stopped, instance_ids: [instance_id])
|
137
|
-
|
230
|
+
@logger.info "stop instance complete! instance_id => [#{instance_id}]"
|
138
231
|
end
|
139
232
|
|
140
233
|
def start_instance(instance_id)
|
141
|
-
|
234
|
+
@logger.info 'starting...'
|
142
235
|
@ec2.start_instances(
|
143
236
|
instance_ids: [instance_id]
|
144
237
|
)
|
145
238
|
@ec2.wait_until(:instance_running, instance_ids: [instance_id])
|
146
|
-
|
239
|
+
@logger.info "start instance complete! instance_id => [#{instance_id}]"
|
147
240
|
end
|
148
241
|
|
149
|
-
def terminate_instance(
|
150
|
-
|
242
|
+
def terminate_instance(instance)
|
243
|
+
instance_id = instance.instance_id
|
244
|
+
@logger.info 'terminating...'
|
151
245
|
@ec2.terminate_instances(instance_ids: [instance_id])
|
152
246
|
@ec2.wait_until(:instance_terminated, instance_ids: [instance_id])
|
153
|
-
|
247
|
+
@logger.info "terminate instance complete! instance_id => [#{instance_id}]"
|
154
248
|
end
|
155
249
|
|
156
250
|
def associate_address(instance_id, public_ip_address)
|
@@ -161,16 +255,84 @@ module Ec2ex
|
|
161
255
|
end
|
162
256
|
|
163
257
|
def latest_image_with_name(name)
|
164
|
-
|
165
|
-
filter << { name: 'tag:Name', values: [name] }
|
166
|
-
result = @ec2.describe_images(
|
167
|
-
filters: filter
|
168
|
-
).data.to_h[:images]
|
258
|
+
result = search_image_with_name(name)
|
169
259
|
result = result.sort_by{ |image|
|
170
260
|
tag_hash = get_tag_hash(image[:tags])
|
171
261
|
tag_hash['created'].nil? ? '' : tag_hash['created']
|
172
262
|
}
|
173
263
|
result.empty? ? {} : result.last
|
174
264
|
end
|
265
|
+
|
266
|
+
def get_old_images(name, num = 10)
|
267
|
+
result = search_image_with_name(name)
|
268
|
+
return [] if result.empty?
|
269
|
+
map = Hash.new{|h,k| h[k] = []}
|
270
|
+
result = result.each{ |image|
|
271
|
+
tag_hash = get_tag_hash(image[:tags])
|
272
|
+
next if tag_hash['Name'].nil? || tag_hash['created'].nil?
|
273
|
+
map[tag_hash['Name']] << image
|
274
|
+
}
|
275
|
+
old_images = []
|
276
|
+
map.each do |name, images|
|
277
|
+
sorted_images = images.sort_by{ |image|
|
278
|
+
tag_hash = get_tag_hash(image[:tags])
|
279
|
+
Time.parse(tag_hash['created'])
|
280
|
+
}
|
281
|
+
newly_images = sorted_images.last(num)
|
282
|
+
old_images = old_images + (sorted_images - newly_images)
|
283
|
+
end
|
284
|
+
old_images
|
285
|
+
end
|
286
|
+
|
287
|
+
def images(name)
|
288
|
+
filter = [{ name: 'is-public', values: ['false'] }]
|
289
|
+
filter << { name: 'name', values: [name] }
|
290
|
+
@ec2.describe_images(
|
291
|
+
filters: filter
|
292
|
+
).data.to_h[:images]
|
293
|
+
end
|
294
|
+
|
295
|
+
def search_image_with_name(name)
|
296
|
+
filter = [{ name: 'is-public', values: ['false'] }]
|
297
|
+
filter << { name: 'tag:Name', values: [name] }
|
298
|
+
@ec2.describe_images(
|
299
|
+
filters: filter
|
300
|
+
).data.to_h[:images]
|
301
|
+
end
|
302
|
+
|
303
|
+
def deregister_snapshot_no_related(owner_id)
|
304
|
+
enable_snapshot_ids = []
|
305
|
+
images('*').each do |image|
|
306
|
+
image_id = image[:image_id]
|
307
|
+
snapshot_ids = image[:block_device_mappings]
|
308
|
+
.select{ |block_device_mapping| block_device_mapping[:ebs] != nil }
|
309
|
+
.map{ |block_device_mapping| block_device_mapping[:ebs][:snapshot_id] }
|
310
|
+
enable_snapshot_ids.concat(snapshot_ids)
|
311
|
+
end
|
312
|
+
filter = [{ name: 'owner-id', values: [owner_id] }]
|
313
|
+
all_snapshot_ids = @ec2.describe_snapshots(
|
314
|
+
filters: filter
|
315
|
+
).data.to_h[:snapshots].map{ |snapshot| snapshot[:snapshot_id] }
|
316
|
+
disable_snapshot_ids = (all_snapshot_ids - enable_snapshot_ids)
|
317
|
+
disable_snapshot_ids.each do |disable_snapshot_id|
|
318
|
+
@ec2.delete_snapshot({snapshot_id: disable_snapshot_id})
|
319
|
+
@logger.info "delete snapshot #{disable_snapshot_id}"
|
320
|
+
end
|
321
|
+
end
|
322
|
+
|
323
|
+
def ping?(private_ip_address)
|
324
|
+
if private_ip_address
|
325
|
+
pinger = Net::Ping::External.new(private_ip_address)
|
326
|
+
if pinger.ping?
|
327
|
+
@logger.info "already exists private_ip_address => #{private_ip_address}"
|
328
|
+
return true
|
329
|
+
end
|
330
|
+
end
|
331
|
+
return false
|
332
|
+
end
|
333
|
+
|
334
|
+
def allocate_address_vpc
|
335
|
+
@ec2.allocate_address(domain: 'vpc').data
|
336
|
+
end
|
175
337
|
end
|
176
338
|
end
|
data/lib/ec2ex/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ec2ex
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hiroshi Toyama
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-12-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -56,16 +56,16 @@ dependencies:
|
|
56
56
|
name: aws-sdk
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
61
|
+
version: '0'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
68
|
+
version: '0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: activesupport
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -80,20 +80,48 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: parallel
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: net-ping
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
- !ruby/object:Gem::Dependency
|
84
112
|
name: bundler
|
85
113
|
requirement: !ruby/object:Gem::Requirement
|
86
114
|
requirements:
|
87
|
-
- - "
|
115
|
+
- - ">="
|
88
116
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
117
|
+
version: '0'
|
90
118
|
type: :development
|
91
119
|
prerelease: false
|
92
120
|
version_requirements: !ruby/object:Gem::Requirement
|
93
121
|
requirements:
|
94
|
-
- - "
|
122
|
+
- - ">="
|
95
123
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
124
|
+
version: '0'
|
97
125
|
- !ruby/object:Gem::Dependency
|
98
126
|
name: pry
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -225,7 +253,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
253
|
version: '0'
|
226
254
|
requirements: []
|
227
255
|
rubyforge_project:
|
228
|
-
rubygems_version: 2.
|
256
|
+
rubygems_version: 2.5.1
|
229
257
|
signing_key:
|
230
258
|
specification_version: 4
|
231
259
|
summary: ec2 expand command line
|