awsutils 1.4.3
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 +7 -0
- data/.gitignore +18 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +58 -0
- data/Rakefile +11 -0
- data/awsutils.gemspec +33 -0
- data/bin/ec2addsg +14 -0
- data/bin/ec2delsg +14 -0
- data/bin/ec2info +13 -0
- data/bin/ec2latestimage +12 -0
- data/bin/ec2listmachines +13 -0
- data/bin/ec2lsgrp +25 -0
- data/bin/elbls +13 -0
- data/bin/r53ls +14 -0
- data/lib/awsutils.rb +1 -0
- data/lib/awsutils/ec2addsg.rb +200 -0
- data/lib/awsutils/ec2delsg.rb +96 -0
- data/lib/awsutils/ec2info.rb +701 -0
- data/lib/awsutils/ec2latestimage.rb +84 -0
- data/lib/awsutils/ec2listmachines.rb +406 -0
- data/lib/awsutils/ec2lsgrp.rb +91 -0
- data/lib/awsutils/ec2sg.rb +77 -0
- data/lib/awsutils/elbls.rb +51 -0
- data/lib/awsutils/r53addrr.rb +28 -0
- data/lib/awsutils/r53ls.rb +92 -0
- data/lib/awsutils/version.rb +3 -0
- data/spec/lib/awsutils/ec2addsg_spec.rb +11 -0
- data/spec/lib/awsutils/ec2lsgrp_spec.rb +178 -0
- data/spec/spec_helper.rb +10 -0
- metadata +238 -0
@@ -0,0 +1,91 @@
|
|
1
|
+
require 'awsutils/ec2sg'
|
2
|
+
require 'trollop'
|
3
|
+
|
4
|
+
gem 'fog-aws', '>= 0.7.6'
|
5
|
+
|
6
|
+
module AwsUtils
|
7
|
+
class GroupDoesNotExist < StandardError; end
|
8
|
+
|
9
|
+
class Ec2LsGrp < Ec2SecurityGroup
|
10
|
+
attr_reader :search, :opts, :owner_id
|
11
|
+
|
12
|
+
def msg_pair(key, value)
|
13
|
+
puts("#{key} #{value}")
|
14
|
+
end
|
15
|
+
|
16
|
+
def perms_out(direction, perms)
|
17
|
+
puts "#{direction.upcase} RULES"
|
18
|
+
perms.to_enum.with_index(1) do |perm, index|
|
19
|
+
print " #{index} "
|
20
|
+
print "groups: #{group_perm_string(perm['groups'])}; " if perm['groups'].count > 0
|
21
|
+
print "ip_ranges: #{perm['ipRanges'].join(', ')}; " if perm['ipRanges'].count > 0
|
22
|
+
print "ipProtocol: #{perm['ipProtocol']}; "
|
23
|
+
print "fromPort: #{perm['fromPort']}; " if perm['fromPort']
|
24
|
+
print "toPort: #{perm['toPort']}" if perm['toPort']
|
25
|
+
print "\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def group_details(g)
|
30
|
+
@owner_id = g.owner_id
|
31
|
+
|
32
|
+
msg_pair('ID', g.group_id)
|
33
|
+
msg_pair('NAME', g.name)
|
34
|
+
msg_pair('OWNER_ID', owner_id)
|
35
|
+
msg_pair('DESCRIPTION', g.description)
|
36
|
+
msg_pair('VPC_ID', g.vpc_id) if g.vpc_id
|
37
|
+
|
38
|
+
perms_out('incoming', g.ip_permissions)
|
39
|
+
perms_out('egress', g.ip_permissions_egress) if g.vpc_id
|
40
|
+
end
|
41
|
+
|
42
|
+
def run
|
43
|
+
fail ArgumentError, 'Please specify a security group' unless search
|
44
|
+
unless group_o = group(search) # rubocop:disable Lint/AssignmentInCondition
|
45
|
+
fail GroupDoesNotExist
|
46
|
+
end
|
47
|
+
return group_details(group_o) unless opts[:list_refs]
|
48
|
+
refs = references(group_o.group_id)
|
49
|
+
if refs.empty?
|
50
|
+
puts 'No references'
|
51
|
+
else
|
52
|
+
puts "References: #{refs.keys.join(', ')}"
|
53
|
+
puts refs.to_yaml if opts[:verbose]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def initialize
|
58
|
+
@opts = parse_opts
|
59
|
+
@search = ARGV.last
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def group_perm_string(group_perm)
|
65
|
+
group_perm.map do |g|
|
66
|
+
if g['userId'] == owner_id
|
67
|
+
"#{g['groupId']} (#{group(g['groupId']).name})"
|
68
|
+
else
|
69
|
+
"#{g['groupId']} (#{g['groupName']}, owner: #{g['userId']})"
|
70
|
+
end
|
71
|
+
end.join(', ')
|
72
|
+
end
|
73
|
+
|
74
|
+
def parse_opts
|
75
|
+
Trollop.options do
|
76
|
+
opt :list_refs,
|
77
|
+
'List groups referencing this group',
|
78
|
+
short: 'r',
|
79
|
+
default: false
|
80
|
+
opt :verbose,
|
81
|
+
'Verbose output (currently only used with -r output)',
|
82
|
+
short: 'v',
|
83
|
+
default: false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def group(search)
|
88
|
+
groups.find { |g| (search =~ /^sg-/ && g.group_id == search) || g.name == search }
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fog/aws'
|
3
|
+
|
4
|
+
module AwsUtils
|
5
|
+
class Ec2SecurityGroup
|
6
|
+
def connection
|
7
|
+
@connection ||= begin
|
8
|
+
options = {}
|
9
|
+
|
10
|
+
if ENV['AWS_ACCESS_KEY']
|
11
|
+
options = {
|
12
|
+
aws_access_key_id: ENV['AWS_ACCESS_KEY'],
|
13
|
+
aws_secret_access_key: ENV['AWS_SECRET_KEY']
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
Fog::Compute::AWS.new options
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def references(search)
|
22
|
+
if search =~ /^sg-/
|
23
|
+
search_id = search
|
24
|
+
else
|
25
|
+
search_id = groups.find { |g| g.name == search }.group_id
|
26
|
+
end
|
27
|
+
|
28
|
+
groups.each_with_object({}) do |grp, m|
|
29
|
+
assoc_p = grp.ip_permissions.select do |ip_perm|
|
30
|
+
!ip_perm['groups'].select { |src_grp|
|
31
|
+
src_grp['groupName'] == search ||
|
32
|
+
src_grp['groupId'] == search_id
|
33
|
+
}.empty?
|
34
|
+
end
|
35
|
+
if assoc_p.empty?
|
36
|
+
next
|
37
|
+
else
|
38
|
+
m[grp.name] = {
|
39
|
+
'groupId' => grp.group_id,
|
40
|
+
'ipPermissions' => assoc_p.map do |ap|
|
41
|
+
ap.delete('ipRanges')
|
42
|
+
ap
|
43
|
+
end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def groups
|
50
|
+
@groups ||= connection.security_groups
|
51
|
+
end
|
52
|
+
|
53
|
+
def assigned?
|
54
|
+
servers_using_group = connection.servers.map do |server|
|
55
|
+
next unless server.state != 'terminated' &&
|
56
|
+
server.groups.include?(@opts[:security_group])
|
57
|
+
server.tags['Name'] ? server.tags['Name'] : server.id
|
58
|
+
end.compact
|
59
|
+
|
60
|
+
return false unless servers_using_group.length > 0
|
61
|
+
print 'The following servers are still using this group: '
|
62
|
+
puts servers_using_group.join(',')
|
63
|
+
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
def exist?
|
68
|
+
current_groups.include?(@opts[:security_group])
|
69
|
+
end
|
70
|
+
|
71
|
+
def current_groups
|
72
|
+
@current_groups ||= begin
|
73
|
+
connection.security_groups.map { |g| [g.name, g.group_id] }.flatten.uniq
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'fog/aws/elb'
|
2
|
+
require 'fog/core/parser'
|
3
|
+
require 'facets/string/titlecase'
|
4
|
+
require 'rainbow'
|
5
|
+
|
6
|
+
module AwsUtils
|
7
|
+
class ElbLs
|
8
|
+
attr_reader :args
|
9
|
+
|
10
|
+
def run(args)
|
11
|
+
@args = args
|
12
|
+
|
13
|
+
if args.empty?
|
14
|
+
puts connection.load_balancers.map(&:id).sort
|
15
|
+
else
|
16
|
+
args.each do |lb|
|
17
|
+
puts colorize_yaml(attributes(lb).to_yaml)
|
18
|
+
puts '---' if args.count > 1
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def colorize_yaml(yaml_string)
|
26
|
+
yaml_string.split("\n").map do |line|
|
27
|
+
if line =~ /:/
|
28
|
+
key, val = line.split(':', 2)
|
29
|
+
[Rainbow(key).bright, val].join(':')
|
30
|
+
else
|
31
|
+
line
|
32
|
+
end
|
33
|
+
end.join("\n")
|
34
|
+
end
|
35
|
+
|
36
|
+
def attributes(lb)
|
37
|
+
Hash[connection.load_balancers.get(lb).attributes.map do |key, val|
|
38
|
+
case key
|
39
|
+
when Symbol
|
40
|
+
[key.to_s.titlecase, val]
|
41
|
+
when String
|
42
|
+
[key.split(/(?=[A-Z])/).join(' '), val]
|
43
|
+
end
|
44
|
+
end]
|
45
|
+
end
|
46
|
+
|
47
|
+
def connection
|
48
|
+
@connection ||= Fog::AWS::ELB.new
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fog'
|
3
|
+
require 'trollop'
|
4
|
+
|
5
|
+
module AwsUtils
|
6
|
+
|
7
|
+
class Route53AddResourceRecord
|
8
|
+
|
9
|
+
def connection
|
10
|
+
@connection ||= Fog::DNS::AWS.new
|
11
|
+
end # def connection
|
12
|
+
|
13
|
+
def parse_opts
|
14
|
+
opts = Trollop::options do
|
15
|
+
opt :name, "The name", :short => 'n', :type => String, :required => true
|
16
|
+
opt :type, "Record type (e.g. CNAME or A)", :short => 'T', :type => String, :required => true
|
17
|
+
opt :ttl, "Time-to-live", :short => 't', :type => String, :default => "300"
|
18
|
+
opt :value, "Record Value", :short => 'v', :type => String, :required => true
|
19
|
+
end # opts = Trollop::options
|
20
|
+
end # def parse_opts
|
21
|
+
|
22
|
+
def initialize
|
23
|
+
@opts = parse_opts
|
24
|
+
end # def initialize
|
25
|
+
|
26
|
+
end # class Route53AddResourceRecord
|
27
|
+
|
28
|
+
end # module AwsUtils
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'fog'
|
3
|
+
require 'trollop'
|
4
|
+
require 'json'
|
5
|
+
|
6
|
+
module AwsUtils
|
7
|
+
class Route53ListResourceRecord
|
8
|
+
def connection
|
9
|
+
@connection ||= Fog::DNS::AWS.new
|
10
|
+
end # def connection
|
11
|
+
|
12
|
+
def parse_opts
|
13
|
+
opts = Trollop.options do
|
14
|
+
opt :format, 'Output format', default: 'table'
|
15
|
+
end
|
16
|
+
opts[:name] = ARGV.last
|
17
|
+
opts
|
18
|
+
end # def parse_opts( args )
|
19
|
+
|
20
|
+
def zone
|
21
|
+
@zone ||= connection.zones.all('domain' => zone_name).first
|
22
|
+
end
|
23
|
+
|
24
|
+
def zone_name
|
25
|
+
@zone_name ||= @opts[:name].split('.')[-2..-1].join('.') + '.'
|
26
|
+
end
|
27
|
+
|
28
|
+
def apex?
|
29
|
+
@opts[:name].split('.')[-3].nil? ? true : false
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@opts = parse_opts
|
34
|
+
end # def initialize( args )
|
35
|
+
|
36
|
+
def display_record(record)
|
37
|
+
if @opts[:format] == 'json'
|
38
|
+
puts JSON.pretty_generate(zone_to_json([record]).first)
|
39
|
+
else
|
40
|
+
puts 'Name: ' + record.name
|
41
|
+
puts 'Type: ' + record.type
|
42
|
+
puts 'TTL: ' + record.ttl
|
43
|
+
puts record.value.count < 2 ? 'Value:' : 'Values:'
|
44
|
+
record.value.each { |rr| puts " #{rr}" }
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def record_by_name
|
49
|
+
name = @opts[:name].split('.').join('.') + '.'
|
50
|
+
zone.records.find { |r| r.name == name }
|
51
|
+
end
|
52
|
+
|
53
|
+
def zone_to_json(zone_records)
|
54
|
+
zone_records.map do |r|
|
55
|
+
{
|
56
|
+
'name' => r.name,
|
57
|
+
'type' => r.type,
|
58
|
+
'ttl' => r.ttl,
|
59
|
+
'value' => r.value
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def print_table
|
65
|
+
zone.records.each do |r|
|
66
|
+
printf(
|
67
|
+
"%-40s%-8s%-8s%-40s\n",
|
68
|
+
r.name,
|
69
|
+
r.type,
|
70
|
+
r.ttl,
|
71
|
+
r.value.join(' ')
|
72
|
+
)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def list_all
|
77
|
+
if @opts[:format] == 'json'
|
78
|
+
puts JSON.pretty_generate(zone_to_json(zone.records))
|
79
|
+
else
|
80
|
+
print_table
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def run
|
85
|
+
if apex?
|
86
|
+
list_all
|
87
|
+
else
|
88
|
+
display_record(record_by_name)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end # class Route53AddResourceRecord
|
92
|
+
end # module AwsUtils
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
require 'awsutils/ec2addsg'
|
3
|
+
|
4
|
+
describe AwsUtils::Ec2AddSecurityGroup do
|
5
|
+
it "takes security_group name" do
|
6
|
+
group_name = 'rspec_test_group'
|
7
|
+
ARGV = ['-N', group_name, '-d', 'rspec test group description']
|
8
|
+
sg = AwsUtils::Ec2AddSecurityGroup.new
|
9
|
+
expect(sg.name).to eq(group_name)
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'awsutils/ec2lsgrp'
|
3
|
+
require 'byebug'
|
4
|
+
|
5
|
+
describe AwsUtils::Ec2LsGrp do
|
6
|
+
let(:ec2lsgrp) { AwsUtils::Ec2LsGrp.new }
|
7
|
+
let(:fog) { Fog::Compute::AWS.new }
|
8
|
+
let(:local_group_name) { 'test_group' }
|
9
|
+
|
10
|
+
before(:each) do
|
11
|
+
Fog.mock!
|
12
|
+
Fog::Mock.reset
|
13
|
+
allow(ec2lsgrp).to receive(:puts)
|
14
|
+
end
|
15
|
+
|
16
|
+
describe '#group' do
|
17
|
+
let(:group_set) do
|
18
|
+
[
|
19
|
+
object_double(
|
20
|
+
'security_groups',
|
21
|
+
name: 'test_group',
|
22
|
+
group_id: 'sg-a1b2c3d4'
|
23
|
+
)
|
24
|
+
]
|
25
|
+
end
|
26
|
+
|
27
|
+
before { allow(ec2lsgrp).to receive(:groups).and_return group_set }
|
28
|
+
|
29
|
+
context 'search by valid name' do
|
30
|
+
it 'return the group object' do
|
31
|
+
expect(ec2lsgrp.send('group', 'test_group')).to eq group_set.first
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'search by valid ID' do
|
36
|
+
it 'return the group object' do
|
37
|
+
expect(ec2lsgrp.send('group', 'sg-a1b2c3d4')).to eq group_set.first
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'search by invalid name' do
|
42
|
+
it 'return nil' do
|
43
|
+
expect(ec2lsgrp.send('group', 'invalid_group')).to eq nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context 'search by invalid ID' do
|
48
|
+
it 'return nil' do
|
49
|
+
expect(ec2lsgrp.send('group', 'sg-00000000')).to eq nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'specify no arguments' do
|
55
|
+
before do
|
56
|
+
allow(ec2lsgrp).to receive(:search).and_return nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'raise ArgumentError' do
|
60
|
+
expect { ec2lsgrp.run }.to raise_error(
|
61
|
+
ArgumentError,
|
62
|
+
'Please specify a security group'
|
63
|
+
)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'search for a group' do
|
68
|
+
context 'by a name that does not exist' do
|
69
|
+
before do
|
70
|
+
allow(ec2lsgrp).to receive(:search).and_return 'bad-group-name'
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should raise GroupDoesNotExist exception' do
|
74
|
+
expect { ec2lsgrp.run }.to raise_error AwsUtils::GroupDoesNotExist
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'by an id that does not exist' do
|
79
|
+
before do
|
80
|
+
allow(ec2lsgrp).to receive(:search).and_return 'sg-a1b2c3d4'
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'should raise GroupDoesNotExist exception' do
|
84
|
+
expect { ec2lsgrp.run }.to raise_error AwsUtils::GroupDoesNotExist
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
context 'with no permissions' do
|
89
|
+
let(:local_group_obj) do
|
90
|
+
group_obj = fog.security_groups.create(
|
91
|
+
'description' => '',
|
92
|
+
'name' => local_group_name)
|
93
|
+
fog.security_groups.get_by_id(group_obj.group_id)
|
94
|
+
end
|
95
|
+
|
96
|
+
before do
|
97
|
+
allow(ec2lsgrp).to receive(:search).and_return local_group_name
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'searches for the group by id' do
|
101
|
+
expect(ec2lsgrp).to receive(:group).with(local_group_name)
|
102
|
+
.and_return(local_group_obj)
|
103
|
+
ec2lsgrp.run
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'with source group belonging to same userid' do
|
108
|
+
let(:dummy_group_name) { 'dummy_group' }
|
109
|
+
|
110
|
+
let(:dummy_group_obj) do
|
111
|
+
group_obj = fog.security_groups.create(
|
112
|
+
'description' => 'Dummy Group',
|
113
|
+
'name' => dummy_group_name
|
114
|
+
)
|
115
|
+
fog.security_groups.get_by_id(group_obj.group_id)
|
116
|
+
end
|
117
|
+
|
118
|
+
let(:local_group_obj) do
|
119
|
+
group_obj = fog.security_groups.create(
|
120
|
+
'description' => '',
|
121
|
+
'name' => local_group_name
|
122
|
+
)
|
123
|
+
group_obj.authorize_port_range(
|
124
|
+
8080..8080,
|
125
|
+
group: { dummy_group_obj.owner_id => dummy_group_obj.group_id }
|
126
|
+
)
|
127
|
+
fog.security_groups.get_by_id(group_obj.group_id)
|
128
|
+
end
|
129
|
+
|
130
|
+
before do
|
131
|
+
allow(ec2lsgrp).to receive(:search).and_return local_group_name
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'prints a source group list containing only groupName' do
|
135
|
+
allow(ec2lsgrp).to receive(:owner_id).and_return local_group_obj.owner_id
|
136
|
+
expect do
|
137
|
+
ec2lsgrp.perms_out('incoming', local_group_obj.ip_permissions)
|
138
|
+
end.to output(/ \d+ groups: #{dummy_group_obj.group_id} \(#{dummy_group_name}\); /).to_stdout
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'with source group belonging to another userid' do
|
143
|
+
let(:dummy_group_obj) do
|
144
|
+
group_obj = fog.security_groups.create(
|
145
|
+
'description' => 'Dummy Group',
|
146
|
+
'name' => 'dummy_group'
|
147
|
+
)
|
148
|
+
fog.security_groups.get_by_id(group_obj.group_id)
|
149
|
+
end
|
150
|
+
|
151
|
+
let(:dummy_group_name) do
|
152
|
+
fog.security_groups.get_by_id(dummy_group_obj.group_id).name
|
153
|
+
end
|
154
|
+
|
155
|
+
let(:local_group_obj) do
|
156
|
+
group_obj = fog.security_groups.create(
|
157
|
+
'description' => '',
|
158
|
+
'name' => local_group_name
|
159
|
+
)
|
160
|
+
group_obj.authorize_port_range(
|
161
|
+
8080..8080,
|
162
|
+
group: { 'amazon-elb' => dummy_group_obj.group_id }
|
163
|
+
)
|
164
|
+
fog.security_groups.get_by_id(group_obj.group_id)
|
165
|
+
end
|
166
|
+
|
167
|
+
before do
|
168
|
+
allow(ec2lsgrp).to receive(:search).and_return local_group_name
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'prints a source group list containing userId and groupName' do
|
172
|
+
expect do
|
173
|
+
ec2lsgrp.perms_out('incoming', local_group_obj.ip_permissions)
|
174
|
+
end.to output(/ \d+ groups: #{dummy_group_obj.group_id} \(#{dummy_group_name}, owner: amazon-elb\); /).to_stdout
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|