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.
@@ -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,3 @@
1
+ module AwsUtils
2
+ VERSION = '1.4.3'
3
+ end
@@ -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