aws-eni 0.2.0 → 0.2.1
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/bin/aws-eni +36 -7
- data/lib/aws-eni.rb +80 -25
- data/lib/aws-eni/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe0e076295a17d9cc4c63a7227f83be289fcb4b3
|
4
|
+
data.tar.gz: 51dfdb49ec4bba211e5105f3eafed74fc210cdcc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aa9fd08058dfda15e1c473108105d37e6aaf1c64a322fe249a1c5f469b494399895395f2df2c18d12df7a1d5cbac8811393693e48d032d5824c0b70fc6880b72
|
7
|
+
data.tar.gz: 7da3b4bd53b7944f744e02c76bc9dc7a691cde2b76ecb708dba83006045e21a3dd30e4c8f35cc0f149762079e4d94f4a9c732e38c2bfb4e54a0fe7c886ccdfae
|
data/bin/aws-eni
CHANGED
@@ -24,6 +24,7 @@ desc 'Display all system commands and warnings'
|
|
24
24
|
switch [:V,:verbose], negatable: false
|
25
25
|
|
26
26
|
pre do |opt|
|
27
|
+
Aws::ENI.timeout 90
|
27
28
|
Aws::ENI::IFconfig.verbose = opt[:verbose]
|
28
29
|
true
|
29
30
|
end
|
@@ -236,13 +237,13 @@ arg 'security-groups', :optional
|
|
236
237
|
arg 'ip-address', :optional
|
237
238
|
command [:attach] do |c|
|
238
239
|
c.desc 'Do not configure or enable the device after attachment (implies block)'
|
239
|
-
c.switch [:n
|
240
|
+
c.switch [:n,:noconfig], negatable: false
|
240
241
|
|
241
242
|
c.desc 'Do not return until attachment is complete'
|
242
243
|
c.switch [:b,:block], negatable: false
|
243
244
|
|
244
245
|
c.action do |global,opts,args|
|
245
|
-
config = !opts[
|
246
|
+
config = !opts[:noconfig]
|
246
247
|
if args.first =~ /^eni-/
|
247
248
|
help_now! 'Too many arguments' if args.count > 1
|
248
249
|
id = args.first
|
@@ -275,6 +276,9 @@ command [:detach] do |c|
|
|
275
276
|
c.desc 'Delete (or preserve) the unused ENI resource after dataching (implies block)'
|
276
277
|
c.switch [:d,:delete], default_value: :not_provided # GLI behavior workaround
|
277
278
|
|
279
|
+
c.desc 'Release any associated public IP addresses'
|
280
|
+
c.switch [:r,:release], negatable: false
|
281
|
+
|
278
282
|
c.desc 'Do not return until detachment is complete'
|
279
283
|
c.switch [:b,:block], negatable: false
|
280
284
|
|
@@ -283,9 +287,18 @@ command [:detach] do |c|
|
|
283
287
|
params = parse_args args, :interface_id, :device_name
|
284
288
|
params[:block] = opts[:block]
|
285
289
|
params[:delete] = opts[:delete] unless opts[:delete] == :not_provided
|
290
|
+
params[:release] = opts[:release]
|
286
291
|
id = params[:device_name] || params[:interface_id]
|
287
292
|
|
288
293
|
device = Aws::ENI.detach_interface(id, params)
|
294
|
+
|
295
|
+
device[:public_ips].each do |address|
|
296
|
+
if device[:released]
|
297
|
+
puts "EIP #{address[:public_ip]} (#{address[:allocation_id]}) dissociated and released"
|
298
|
+
else
|
299
|
+
puts "EIP #{address[:public_ip]} (#{address[:allocation_id]}) dissociated"
|
300
|
+
end
|
301
|
+
end
|
289
302
|
if device[:deleted]
|
290
303
|
puts "interface #{device[:interface_id]} detached from #{device[:device_name]} and deleted"
|
291
304
|
else
|
@@ -310,10 +323,24 @@ command [:clean] do |c|
|
|
310
323
|
c.desc 'Force deletion of all unattached interfaces which meet our criteria'
|
311
324
|
c.switch [:f,:force], negatable: false
|
312
325
|
|
326
|
+
c.desc 'Release any associated public IP addresses'
|
327
|
+
c.switch [:r,:release], negatable: false
|
328
|
+
|
313
329
|
c.action do |global,opts,args|
|
314
330
|
help_now! "Too many arguments" if args.count > 1
|
315
|
-
deleted = Aws::ENI.clean_interfaces(args.first, safe_mode: !opts[:force])
|
316
|
-
|
331
|
+
deleted = Aws::ENI.clean_interfaces(args.first, safe_mode: !opts[:force], release: opts[:release])
|
332
|
+
|
333
|
+
deleted[:public_ips].each do |address|
|
334
|
+
if deleted[:released]
|
335
|
+
puts "EIP #{address[:public_ip]} (#{address[:allocation_id]}) dissociated and released"
|
336
|
+
else
|
337
|
+
puts "EIP #{address[:public_ip]} (#{address[:allocation_id]}) dissociated"
|
338
|
+
end
|
339
|
+
end
|
340
|
+
deleted[:interfaces].each do |interface_id|
|
341
|
+
puts "interface #{interface_id} deleted"
|
342
|
+
end
|
343
|
+
puts "#{deleted[:interfaces].count} interfaces deleted"
|
317
344
|
end
|
318
345
|
end
|
319
346
|
|
@@ -328,7 +355,7 @@ arg 'ip-address', :optional
|
|
328
355
|
arg 'interface-id OR device-name'
|
329
356
|
command [:assign] do |c|
|
330
357
|
c.desc 'Do not configure the interface after assignment'
|
331
|
-
c.switch [:n
|
358
|
+
c.switch [:n,:noconfig], negatable: false
|
332
359
|
|
333
360
|
c.desc 'Do not return until connection is verified'
|
334
361
|
c.switch [:b,:block], negatable: false
|
@@ -338,7 +365,7 @@ command [:assign] do |c|
|
|
338
365
|
device = params[:device_name] || params[:interface_id]
|
339
366
|
help_now! "Missing argument" if device.nil?
|
340
367
|
|
341
|
-
params.merge! configure: !opts[
|
368
|
+
params.merge! configure: !opts[:noconfig], block: opts[:block]
|
342
369
|
Aws::ENI.assert_ifconfig_access if params[:configure]
|
343
370
|
|
344
371
|
assignment = Aws::ENI.assign_secondary_ip(device, params)
|
@@ -395,10 +422,11 @@ command [:associate] do |c|
|
|
395
422
|
c.switch [:b,:block], negatable: false
|
396
423
|
|
397
424
|
c.action do |global,opts,args|
|
398
|
-
help_now! "Missing argument" if args.empty?
|
399
425
|
args.delete('new')
|
400
426
|
params = parse_args args, :private_ip, :public_ip, :allocation_id, :interface_id, :device_name
|
401
427
|
params[:block] = opts[:block]
|
428
|
+
help_now! "Missing argument" unless params[:private_ip]
|
429
|
+
|
402
430
|
assoc = Aws::ENI.associate_elastic_ip(params[:private_ip], params)
|
403
431
|
puts "EIP #{assoc[:public_ip]} (#{assoc[:allocation_id]}) associated with #{assoc[:private_ip]} on #{assoc[:device_name]} (#{assoc[:interface_id]})"
|
404
432
|
end
|
@@ -418,6 +446,7 @@ command [:dissociate] do |c|
|
|
418
446
|
|
419
447
|
c.action do |global,opts,args|
|
420
448
|
params = parse_args args, :private_ip, :public_ip, :allocation_id, :association_id, :interface_id, :device_name
|
449
|
+
params[:release] = opts[:release]
|
421
450
|
address = params[:private_ip] || params[:public_ip] || params[:association_id] || params[:allocation_id]
|
422
451
|
help_now! "Missing argument" unless address
|
423
452
|
dissoc = Aws::ENI.dissociate_elastic_ip(address, params)
|
data/lib/aws-eni.rb
CHANGED
@@ -123,6 +123,9 @@ module Aws
|
|
123
123
|
interface_id: options[:interface_id],
|
124
124
|
device_number: options[:device_number]
|
125
125
|
)
|
126
|
+
if device.name == 'eth0'
|
127
|
+
raise InvalidParameterError, "For safety, interface eth0 cannot be detached."
|
128
|
+
end
|
126
129
|
interface_id = device.interface_id
|
127
130
|
|
128
131
|
response = client.describe_network_interfaces(filters: [{
|
@@ -142,7 +145,19 @@ module Aws
|
|
142
145
|
force: true
|
143
146
|
)
|
144
147
|
created_by_us = interface.tag_set.any? { |tag| tag.key == 'created by' && tag.value == owner_tag }
|
145
|
-
do_delete = options[:delete]
|
148
|
+
do_delete = options[:delete] != false && created_by_us
|
149
|
+
do_release = !!options[:release]
|
150
|
+
|
151
|
+
public_ips = []
|
152
|
+
interface[:private_ip_addresses].each do |addr|
|
153
|
+
if assoc = addr[:association]
|
154
|
+
public_ips << {
|
155
|
+
public_ip: assoc[:public_ip],
|
156
|
+
allocation_id: assoc[:allocation_id]
|
157
|
+
}
|
158
|
+
dissociate_elastic_ip(assoc[:allocation_id], release: true) if do_release
|
159
|
+
end
|
160
|
+
end
|
146
161
|
|
147
162
|
if options[:block] || do_delete
|
148
163
|
wait_for 'the interface to detach', interval: 0.3 do
|
@@ -156,12 +171,16 @@ module Aws
|
|
156
171
|
device_number: device.device_number,
|
157
172
|
created_by_us: created_by_us,
|
158
173
|
deleted: do_delete,
|
174
|
+
released: do_release,
|
175
|
+
public_ips: public_ips,
|
159
176
|
api_response: interface
|
160
177
|
}
|
161
178
|
end
|
162
179
|
|
163
180
|
# delete unattached network interfaces
|
164
181
|
def clean_interfaces(filter = nil, options = {})
|
182
|
+
public_ips = []
|
183
|
+
do_release = !!options[:release]
|
165
184
|
safe_mode = true unless options[:safe_mode] == false
|
166
185
|
|
167
186
|
filters = [
|
@@ -186,20 +205,30 @@ module Aws
|
|
186
205
|
|
187
206
|
descriptions = client.describe_network_interfaces(filters: filters)
|
188
207
|
interfaces = descriptions[:network_interfaces].select do |interface|
|
189
|
-
|
208
|
+
created_recently = interface.tag_set.any? do |tag|
|
190
209
|
begin
|
191
210
|
tag.key == 'created on' && Time.now - Time.parse(tag.value) < 60
|
192
211
|
rescue ArgumentError
|
193
|
-
false
|
194
212
|
end
|
195
213
|
end
|
214
|
+
unless safe_mode && created_recently
|
215
|
+
interface[:private_ip_addresses].each do |addr|
|
216
|
+
if assoc = addr[:association]
|
217
|
+
public_ips << {
|
218
|
+
public_ip: assoc[:public_ip],
|
219
|
+
allocation_id: assoc[:allocation_id]
|
220
|
+
}
|
221
|
+
dissociate_elastic_ip(assoc[:allocation_id], release: true) if do_release
|
222
|
+
end
|
223
|
+
end
|
196
224
|
client.delete_network_interface(network_interface_id: interface[:network_interface_id])
|
197
225
|
true
|
198
226
|
end
|
199
227
|
end
|
200
228
|
{
|
201
|
-
|
202
|
-
|
229
|
+
interfaces: interfaces.map { |eni| eni[:network_interface_id] },
|
230
|
+
public_ips: public_ips,
|
231
|
+
released: do_release,
|
203
232
|
api_response: interfaces
|
204
233
|
}
|
205
234
|
end
|
@@ -216,7 +245,7 @@ module Aws
|
|
216
245
|
current_ips = interface_ips(interface_id)
|
217
246
|
new_ip = options[:private_ip]
|
218
247
|
|
219
|
-
if new_ip
|
248
|
+
if new_ip
|
220
249
|
if current_ips.include?(new_ip)
|
221
250
|
raise InvalidParameterError, "IP #{new_ip} already assigned to #{device.name}"
|
222
251
|
end
|
@@ -226,7 +255,8 @@ module Aws
|
|
226
255
|
allow_reassignment: false
|
227
256
|
)
|
228
257
|
wait_for 'private ip address to be assigned' do
|
229
|
-
interface_ips(interface_id).include?(new_ip)
|
258
|
+
interface_ips(interface_id).include?(new_ip) ||
|
259
|
+
device.local_ips.include?(new_ip)
|
230
260
|
end
|
231
261
|
else
|
232
262
|
client.assign_private_ip_addresses(
|
@@ -236,6 +266,7 @@ module Aws
|
|
236
266
|
)
|
237
267
|
wait_for 'new private ip address to be assigned' do
|
238
268
|
new_ips = interface_ips(interface_id) - current_ips
|
269
|
+
new_ips = device.local_ips - current_ips if new_ips.empty?
|
239
270
|
new_ip = new_ips.first if new_ips
|
240
271
|
end
|
241
272
|
end
|
@@ -279,7 +310,7 @@ module Aws
|
|
279
310
|
end
|
280
311
|
|
281
312
|
if assoc = addr_info[:association]
|
282
|
-
|
313
|
+
dissociate_elastic_ip(assoc[:allocation_id], release: do_release)
|
283
314
|
end
|
284
315
|
|
285
316
|
device.remove_alias(private_ip)
|
@@ -291,15 +322,17 @@ module Aws
|
|
291
322
|
private_ip: private_ip,
|
292
323
|
device_name: device.name,
|
293
324
|
interface_id: device.interface_id,
|
294
|
-
public_ip: assoc[:public_ip],
|
295
|
-
allocation_id: assoc[:allocation_id],
|
296
|
-
association_id: assoc[:association_id],
|
325
|
+
public_ip: assoc && assoc[:public_ip],
|
326
|
+
allocation_id: assoc && assoc[:allocation_id],
|
327
|
+
association_id: assoc && assoc[:association_id],
|
297
328
|
released: assoc && do_release
|
298
329
|
}
|
299
330
|
end
|
300
331
|
|
301
332
|
# associate a private ip with an elastic ip through the AWS api
|
302
333
|
def associate_elastic_ip(private_ip, options = {})
|
334
|
+
raise MissingParameterError, "You must specify a private ip address" unless private_ip
|
335
|
+
|
303
336
|
find = options[:device_name] || options[:device_number] || options[:interface_id] || private_ip
|
304
337
|
device = IFconfig[find].assert(
|
305
338
|
exists: true,
|
@@ -345,32 +378,54 @@ module Aws
|
|
345
378
|
|
346
379
|
# dissociate a public ip from a private ip through the AWS api and
|
347
380
|
# optionally release the public ip
|
348
|
-
def dissociate_elastic_ip(
|
381
|
+
def dissociate_elastic_ip(address, options = {})
|
349
382
|
do_release = !!options[:release]
|
350
|
-
eip = describe_address(ip)
|
351
383
|
|
352
|
-
|
384
|
+
# assert device attributes if we've specified a device
|
385
|
+
if find = options[:device_name] || options[:device_number]
|
353
386
|
device = IFconfig[find].assert(
|
354
387
|
device_name: options[:device_name],
|
355
388
|
device_number: options[:device_number],
|
356
|
-
interface_id: options[:interface_id]
|
389
|
+
interface_id: options[:interface_id],
|
390
|
+
private_ip: options[:private_ip],
|
391
|
+
public_ip: options[:public_ip]
|
357
392
|
)
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
393
|
+
end
|
394
|
+
|
395
|
+
# get our address info
|
396
|
+
eip = describe_address(address)
|
397
|
+
device ||= IFconfig.find { |dev| dev.interface_id == eip[:network_interface_id] }
|
398
|
+
|
399
|
+
# assert eip attributes if options provided
|
400
|
+
if options[:private_ip] && eip[:private_ip_address] != options[:private_ip]
|
401
|
+
raise InvalidParameterError, "#{address} is not associated with IP #{options[:private_ip]}"
|
402
|
+
end
|
403
|
+
if options[:public_ip] && eip[:public_ip] != options[:public_ip]
|
404
|
+
raise InvalidParameterError, "#{address} is not associated with public IP #{options[:public_ip]}"
|
405
|
+
end
|
406
|
+
if options[:allocation_id] && eip[:allocation_id] != options[:allocation_id]
|
407
|
+
raise InvalidParameterError, "#{address} is not associated with allocation ID #{options[:allocation_id]}"
|
408
|
+
end
|
409
|
+
if options[:association_id] && eip[:association_id] != options[:association_id]
|
410
|
+
raise InvalidParameterError, "#{address} is not associated with association ID #{options[:association_id]}"
|
411
|
+
end
|
412
|
+
if options[:interface_id] && eip[:network_interface_id] != options[:interface_id]
|
413
|
+
raise InvalidParameterError, "#{address} is not associated with interface ID #{options[:interface_id]}"
|
414
|
+
end
|
415
|
+
|
416
|
+
if device
|
417
|
+
if device.name == 'eth0' && device.local_ips.first == eip[:private_ip_address]
|
418
|
+
raise InvalidParameterError, "For safety, a public address cannot be dissociated from the primary IP on eth0"
|
366
419
|
end
|
420
|
+
elsif interface_status(eip[:network_interface_id]) != 'available'
|
421
|
+
raise InvalidParameterError, "#{address} is associated with an interface attached to another machine"
|
367
422
|
end
|
368
423
|
|
369
424
|
client.disassociate_address(association_id: eip[:association_id])
|
370
425
|
client.release_address(allocation_id: eip[:allocation_id]) if do_release
|
371
426
|
{
|
372
427
|
private_ip: eip[:private_ip_address],
|
373
|
-
device_name: device.name,
|
428
|
+
device_name: device && device.name,
|
374
429
|
interface_id: eip[:network_interface_id],
|
375
430
|
public_ip: eip[:public_ip],
|
376
431
|
allocation_id: eip[:allocation_id],
|
@@ -478,7 +533,7 @@ module Aws
|
|
478
533
|
when /^eipalloc-/
|
479
534
|
'allocation-id'
|
480
535
|
when /^eipassoc-/
|
481
|
-
'
|
536
|
+
'association-id'
|
482
537
|
else
|
483
538
|
if IPAddr.new(environment[:vpc_cidr]) === IPAddr.new(address)
|
484
539
|
'private-ip-address'
|
data/lib/aws-eni/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-eni
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mike Greiling
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-05-
|
11
|
+
date: 2015-05-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: gli
|