cloudutil 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 1409a2b9cdb13ae5236b4d4f70fb4eec0b16f47d
4
+ data.tar.gz: 6ae2a2a2554cc5af1f2ea34e394a89deea8112f3
5
+ SHA512:
6
+ metadata.gz: f087f0aa8a8ff7202e2bbf8016d6f653e21b617210b72abdfeb8bc2fdbc3f10346f4a2393136c1ee9a091317904e0f1236c8bbab117cc570f0e1b29c245262ad
7
+ data.tar.gz: 5f83cf1c8de01886765863a7ca87693ccd644d0c4ed9962a03093a85f066fc149386795994ba156a4cb8d7bd8b27bf96c7edcf94b1e0775e39b2ff893dfb974a
data/.gitignore ADDED
@@ -0,0 +1,41 @@
1
+ *.gem
2
+ *.rbc
3
+ /.config
4
+ /coverage/
5
+ /InstalledFiles
6
+ /pkg/
7
+ /spec/reports/
8
+ /test/tmp/
9
+ /test/version_tmp/
10
+ /tmp/
11
+
12
+ ## Specific to RubyMotion:
13
+ .dat*
14
+ .repl_history
15
+ build/
16
+
17
+ ## Documentation cache and generated files:
18
+ /.yardoc/
19
+ /_yardoc/
20
+ /doc/
21
+ /rdoc/
22
+
23
+ ## Environment normalisation:
24
+ /.bundle/
25
+ /lib/bundler/man/
26
+
27
+ # for a library or gem, you might want to ignore these files since the code is
28
+ # intended to run in multiple environments; otherwise, check them in:
29
+ # Gemfile.lock
30
+ # .ruby-version
31
+ # .ruby-gemset
32
+
33
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
34
+ .rvmrc
35
+
36
+ Gemfile.lock
37
+ *.bundle
38
+ *.so
39
+ *.o
40
+ *.a
41
+ mkmf.log
data/.rubocop.yml ADDED
@@ -0,0 +1,24 @@
1
+ Encoding:
2
+ Enabled: false
3
+
4
+ NumericLiterals:
5
+ Enabled: false
6
+
7
+ ClassLength:
8
+ Max: 200
9
+
10
+ MethodLength:
11
+ Max: 25
12
+
13
+ LineLength:
14
+ Max: 128
15
+
16
+ HashSyntax:
17
+ Exclude:
18
+ - Rakefile
19
+
20
+ CyclomaticComplexity:
21
+ Max: 10
22
+
23
+ PerceivedComplexity:
24
+ Max: 10
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cloudutil.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Mike Morris
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,38 @@
1
+ # Cloudutil
2
+
3
+ A utility library for performing helpful tasks with various cloud platform providers
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'cloudutil'
10
+
11
+ And then execute:
12
+
13
+ $ bundle install
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install cloudutil
18
+
19
+ ## Usage
20
+
21
+ For AWS helpers:
22
+
23
+ require 'cloudutil/aws'
24
+
25
+ aws = Cloudutil::AWS(config: existing_AWS::Config_object) -or-
26
+ aws = Cloudutil::AWS(access_key: your_AWS_access_key, secret_key: your_AWS_secret_key)
27
+
28
+ subnet_id = aws.resolve_subnet_id('my_subnet_name_or_tag')
29
+ sec_grp_id = aws.resolve_subnet_id('my_security_group_name_or_tag')
30
+ ami_id = aws.resolve_subnet_id('my_ami_name_or_tag')
31
+
32
+ ## Contributing
33
+
34
+ 1. Fork it ( https://github.com/mmmorris1975/cloudutil/fork )
35
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
36
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
37
+ 4. Push to the branch (`git push origin my-new-feature`)
38
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,29 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ gem_dir = ::File.dirname(__FILE__)
5
+
6
+ desc 'Rubocop'
7
+ task :rc => [:rubocop]
8
+ task :rubocop do
9
+ sh "bundle exec rubocop -D #{gem_dir}"
10
+ end
11
+
12
+ task default: [:rc] do
13
+ Rake::Task[:spec].invoke('progress', %w(~slow ~account_specific))
14
+ end
15
+
16
+ desc 'Run rspec'
17
+ RSpec::Core::RakeTask.new(:spec, [:format, :tags]) do |t, args|
18
+ format = args[:format] || 'documentation'
19
+ tags = args[:tags] || []
20
+ t.verbose = false
21
+ t.fail_on_error = true
22
+ t.rspec_opts = "--format=#{format}"
23
+
24
+ tags.flatten.compact.each do |tag|
25
+ t.rspec_opts += " --tag #{tag}"
26
+ end
27
+
28
+ t.ruby_opts = '-W0'
29
+ end
data/cloudutil.gemspec ADDED
@@ -0,0 +1,27 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cloudutil/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cloudutil'
8
+ spec.version = Cloudutil::VERSION
9
+ spec.authors = ['Mike Morris']
10
+ spec.email = ['michael.m.morris@pearson.com']
11
+ spec.summary = 'A utility library for performing helpful tasks with various cloud platform providers'
12
+ spec.description = IO.read(File.join(File.dirname(__FILE__), 'README.md'))
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(/^(test|spec|features)\//)
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.6'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'rspec'
24
+ spec.add_development_dependency 'rubocop'
25
+
26
+ spec.add_dependency 'aws-sdk', '~> 1.44'
27
+ end
@@ -0,0 +1,92 @@
1
+ require 'aws-sdk'
2
+
3
+ module Cloudutil
4
+ module AWS
5
+ # Class containing common methods and attributes for interfacing with AWS
6
+ class Core
7
+ DEFAULT_REGION = 'us-east-1'
8
+
9
+ attr_writer :region
10
+ attr_writer :access_key
11
+ attr_writer :secret_key
12
+
13
+ # Initialize an instance of this class. Will accept options as a hash, or an array,
14
+ # with hash form being preferred. There are no required parameters for this method.
15
+ #
16
+ # Array args must be in the order of: AWS region, AWS access key, AWS secret key.
17
+ #
18
+ # Supported hash option keys are:
19
+ # - config (an pre-built AWS::config object to use for API calls)
20
+ # - region (the AWS region to make API calls to)
21
+ # - access_key (the AWS access key to use for API authentication)
22
+ # - secret_key (the AWS secret key to use for API authentication)
23
+ #
24
+ # If no AWS::config object was passed, this class's config method will automatically
25
+ # be called to create one
26
+ #
27
+ def initialize(*args)
28
+ if args.respond_to? :to_h
29
+ _process_hash_init(args.to_h)
30
+ elsif args[0].respond_to? :to_h
31
+ _process_hash_init(args[0].to_h)
32
+ else
33
+ _process_array_init(args.flatten)
34
+ end
35
+
36
+ config(true) if @config.nil?
37
+ end
38
+
39
+ # Getter for the 'region' attribute, uses DEFAULT_REGION
40
+ # if not explicitly set
41
+ def region
42
+ @region = DEFAULT_REGION if !@region || @region.length < 1
43
+ @region
44
+ end
45
+
46
+ # Getter for the 'access_key' attribute, will use values of the
47
+ # AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY env vars, if not explicitly set
48
+ def access_key
49
+ if !@access_key || @access_key.length < 1
50
+ @access_key = ENV['AWS_ACCESS_KEY_ID'] || ENV['AWS_ACCESS_KEY'] || nil
51
+ end
52
+
53
+ @access_key
54
+ end
55
+
56
+ # Getter for the 'secret_key' attribute, will use values of the
57
+ # AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY env vars, if not explicitly set
58
+ def secret_key
59
+ if !@secret_key || @secret_key.length < 1
60
+ @secret_key = ENV['AWS_SECRET_ACCESS_KEY'] || ENV['AWS_SECRET_KEY'] || nil
61
+ end
62
+
63
+ @secret_key
64
+ end
65
+
66
+ # Create (if not already existing) and return an AWS::config object.
67
+ # If creating a new AWS::config object, will make calls to this class's
68
+ # region, access_key, and secret_key methods to populate the config data
69
+ def config(reconfig = false)
70
+ if !@config || reconfig
71
+ @config = ::AWS.config(region: region, access_key_id: access_key, secret_access_key: secret_key)
72
+ end
73
+
74
+ @config
75
+ end
76
+
77
+ private
78
+
79
+ def _process_hash_init(args)
80
+ return unless args
81
+ @config = args[:config]
82
+ @region = args[:region]
83
+ @access_key = args[:access_key]
84
+ @secret_key = args[:secret_key]
85
+ end
86
+
87
+ def _process_array_init(args)
88
+ _process_hash_init(region: args[0], access_key: args[1], secret_key: args[2]) if args
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,203 @@
1
+ require_relative './core'
2
+
3
+ module Cloudutil
4
+ module AWS
5
+ # A class of utility methods for the AWS EC2 service
6
+ class EC2 < Cloudutil::AWS::Core
7
+ # Resolve the provided value to an AWS subnet id. By default, the search is not case-sensitive,
8
+ # but that can be overridden by supplying 'false' as a second argument to this method.
9
+ # Will return the 1st value in a set, if multiple values returned.
10
+ def resolve_subnet_id(subnet, ignore_case = true)
11
+ obj = lookup_subnet(subnet, ignore_case).first
12
+ return obj.subnet_id unless obj.nil?
13
+ nil
14
+ end
15
+
16
+ # Resolve the provided value to an array of AWS subnet objects. By default, the search is not
17
+ # case-sensitive, but that can be overridden by supplying 'false' as a second argument to this method.
18
+ def lookup_subnet(subnet, ignore_case = true, nap = 2, retries = 5)
19
+ ec2 = ::AWS::EC2.new
20
+ subnets = []
21
+
22
+ begin
23
+ if aws_subnet_id? subnet
24
+ subnets << ec2.subnets[subnet]
25
+ else
26
+ subnets = do_subnet_lookup(ec2.subnets.filter('state', 'available'), subnet, ignore_case)
27
+ end
28
+ rescue ::AWS::EC2::Errors::RequestLimitExceeded, ::AWS::Errors::ServerError
29
+ raise if retries < 1
30
+ sleep nap
31
+ lookup_subnet(subnet, ignore_case, (nap * 2), (retries - 1))
32
+ end
33
+
34
+ subnets
35
+ end
36
+
37
+ # Returns true if the supplied value looks like an AWS subnet id
38
+ def aws_subnet_id?(subnet)
39
+ return true if subnet.match(/^subnet-\h{8,}$/)
40
+ false
41
+ end
42
+
43
+ # Resolve the provided value to an AWS sec group id. By default, the search is not case-sensitive,
44
+ # but that can be overridden by supplying 'false' as a second argument to this method.
45
+ # Will return the 1st value in a set, if multiple values returned.
46
+ def resolve_security_group_id(group, ignore_case = true)
47
+ obj = lookup_security_group(group, ignore_case).first
48
+ return obj.security_group_id unless obj.nil?
49
+ nil
50
+ end
51
+
52
+ # Resolve the provided value to an array of AWS sec group objects. By default, the search is not
53
+ # case-sensitive, but that can be overridden by supplying 'false' as a second argument to this method.
54
+ def lookup_security_group(group, ignore_case = true, nap = 2, retries = 5)
55
+ ec2 = ::AWS::EC2.new
56
+ groups = []
57
+
58
+ begin
59
+ if aws_security_group_id? group
60
+ groups << ec2.security_groups[group]
61
+ else
62
+ groups = do_security_group_lookup_by_name(ec2, group, ignore_case)
63
+ groups = do_security_group_lookup_by_name_tag(ec2, group, ignore_case) if groups.nil? || groups.empty?
64
+ end
65
+ rescue ::AWS::EC2::Errors::RequestLimitExceeded, ::AWS::Errors::ServerError
66
+ raise if retries < 1
67
+ sleep nap
68
+ lookup_security_group(group, ignore_case, (nap * 2), (retries - 1))
69
+ end
70
+
71
+ groups
72
+ end
73
+
74
+ # Returns true if the supplied value looks like an AWS security group id
75
+ def aws_security_group_id?(group)
76
+ return true if group.match(/^sg-\h{8,}$/)
77
+ false
78
+ end
79
+
80
+ # Resolve the provided value to an AWS AMI id. By default, the search is not case-sensitive,
81
+ # but that can be overridden by supplying 'false' as a second argument to this method.
82
+ # Will return the 1st value in a set, if multiple values returned.
83
+ def resolve_ami_id(ami, ignore_case = true)
84
+ obj = lookup_ami(ami, ignore_case).first
85
+ return obj.image_id unless obj.nil?
86
+ nil
87
+ end
88
+
89
+ # Resolve the provided value to an array of AWS AMI objects. By default, the search is not
90
+ # case-sensitive, but that can be overridden by supplying 'false' as a second argument to this method.
91
+ def lookup_ami(ami, ignore_case = true, nap = 2, retries = 5)
92
+ ec2 = ::AWS::EC2.new
93
+ amis = []
94
+
95
+ begin
96
+ if aws_ami_id? ami
97
+ amis << ec2.images[ami]
98
+ else
99
+ # Don't bother memoizing, this is fast
100
+ imgs = ec2.images.filter('image-type', 'machine').filter('state', 'available')
101
+
102
+ amis = do_ami_lookup_by_name_tag(imgs, ami, ignore_case)
103
+ amis = do_private_ami_lookup_by_name(imgs, ami, ignore_case) if amis.nil? || amis.empty?
104
+ amis = do_ami_lookup_by_name(imgs, ami, ignore_case) if amis.nil? || amis.empty?
105
+ end
106
+ rescue ::AWS::EC2::Errors::RequestLimitExceeded, ::AWS::Errors::ServerError
107
+ raise if retries < 1
108
+ sleep nap
109
+ lookup_ami(ami, ignore_case, (nap * 2), (retries - 1))
110
+ end
111
+
112
+ amis
113
+ end
114
+
115
+ # Returns true if the supplied value looks like an AWS AMI id
116
+ def aws_ami_id?(ami)
117
+ return true if ami.match(/^ami-\h{8,}$/)
118
+ false
119
+ end
120
+
121
+ protected
122
+
123
+ # Find an AMI based on the value of the 'Name' tag
124
+ def do_ami_lookup_by_name_tag(filter, ami, ignore_case)
125
+ # Using memoization, this is fast, relativly speaking (can be < 1 sec, 15-20 sec w/o memoization)
126
+ ::AWS.memoize do
127
+ if ignore_case
128
+ filter.tagged('Name')
129
+ .select { |obj| !obj.tags.Name.nil? && obj.tags.Name.casecmp(ami) == 0 }
130
+ else
131
+ filter.tagged('Name')
132
+ .select { |obj| !obj.tags.Name.nil? && obj.tags.Name.eql?(ami) }
133
+ end
134
+ end
135
+ end
136
+
137
+ # Find a non-public AMI based on the value of the AMI's name property
138
+ def do_private_ami_lookup_by_name(filter, ami, ignore_case)
139
+ # Do lookup of non-public AMIs we have access to. This should be a really short list,
140
+ # so it should come back pretty fast
141
+ ::AWS.memoize do
142
+ if ignore_case
143
+ filter.filter('is-public', 'false')
144
+ .select { |obj| !obj.name.nil? && obj.name.casecmp(ami) == 0 }
145
+ else
146
+ filter.filter('is-public', 'false')
147
+ .select { |obj| !obj.name.nil? && obj.name.eql?(ami) }
148
+ end
149
+ end
150
+ end
151
+
152
+ # Find an AMI based on the value of the AMI's name property
153
+ def do_ami_lookup_by_name(filter, ami, ignore_case)
154
+ # This is an absolute pig of a lookup (30+ sec to return), that's why we do it after the faster tag
155
+ # and private AMI lookups. Otherwise this code ends up inspecting all 31k+ public AMIs on AWS
156
+ ::AWS.memoize do
157
+ if ignore_case
158
+ filter.select { |obj| !obj.name.nil? && obj.name.casecmp(ami) == 0 }
159
+ else
160
+ filter.select { |obj| !obj.name.nil? && obj.name.eql?(ami) }
161
+ end
162
+ end
163
+ end
164
+
165
+ # Find a VPC subnet based on the 'Name' tag (subnets don't have a name attribute)
166
+ def do_subnet_lookup(filter, subnet, ignore_case)
167
+ ::AWS.memoize do
168
+ if ignore_case
169
+ filter.tagged('Name')
170
+ .select { |obj| !obj.tags.Name.nil? && obj.tags.Name.casecmp(subnet) == 0 }
171
+ else
172
+ filter.tagged('Name')
173
+ .select { |obj| !obj.tags.Name.nil? && obj.tags.Name.eql?(subnet) }
174
+ end
175
+ end
176
+ end
177
+
178
+ # Find a VPC security group based on the name attribute
179
+ def do_security_group_lookup_by_name(ec2, group, ignore_case)
180
+ ::AWS.memoize do
181
+ if ignore_case
182
+ ec2.security_groups.select { |obj| !obj.name.nil? && obj.name.casecmp(group) == 0 }
183
+ else
184
+ ec2.security_groups.select { |obj| !obj.name.nil? && obj.name.eql?(group) }
185
+ end
186
+ end
187
+ end
188
+
189
+ # Find a VPC security group based on the 'Name' tag
190
+ def do_security_group_lookup_by_name_tag(ec2, group, ignore_case)
191
+ ::AWS.memoize do
192
+ if ignore_case
193
+ ec2.security_groups.tagged('Name')
194
+ .select { |obj| !obj.tags.Name.nil? && obj.tags.Name.casecmp(group) == 0 }
195
+ else
196
+ ec2.security_groups.tagged('Name')
197
+ .select { |obj| !obj.tags.Name.nil? && obj.tags.Name.eql?(group) }
198
+ end
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1 @@
1
+ require_relative './aws/ec2'
@@ -0,0 +1,4 @@
1
+ # Module to hold the version number for this library
2
+ module Cloudutil
3
+ VERSION = '0.0.1'
4
+ end
data/lib/cloudutil.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'cloudutil/version'
2
+ require 'cloudutil/aws'
@@ -0,0 +1,107 @@
1
+ require_relative '../lib/cloudutil/aws.rb'
2
+
3
+ describe Cloudutil::AWS::Core do
4
+ context 'object initialization' do
5
+ my_env = ENV.to_h
6
+
7
+ it 'creates an object using primary env vars' do
8
+ ENV.clear
9
+ ENV['AWS_ACCESS_KEY_ID'] = 'my_primary_access_key'
10
+ ENV['AWS_SECRET_ACCESS_KEY'] = 'my_primary_secret_key'
11
+
12
+ aws = Cloudutil::AWS::Core.new
13
+
14
+ expect(aws.region).to eq 'us-east-1'
15
+ expect(aws.access_key).to eq 'my_primary_access_key'
16
+ expect(aws.secret_key).to eq 'my_primary_secret_key'
17
+ end
18
+
19
+ it 'creates an object using secondary env vars' do
20
+ ENV.clear
21
+ ENV['AWS_ACCESS_KEY'] = 'my_secondary_access_key'
22
+ ENV['AWS_SECRET_KEY'] = 'my_secondary_secret_key'
23
+
24
+ aws = Cloudutil::AWS::Core.new
25
+
26
+ expect(aws.region).to eq 'us-east-1'
27
+ expect(aws.access_key).to eq 'my_secondary_access_key'
28
+ expect(aws.secret_key).to eq 'my_secondary_secret_key'
29
+ end
30
+
31
+ it 'creates an object without env vars' do
32
+ ENV.clear
33
+
34
+ aws = Cloudutil::AWS::Core.new
35
+
36
+ expect(aws.region).to eq 'us-east-1'
37
+ expect(aws.access_key).to be_nil
38
+ expect(aws.secret_key).to be_nil
39
+ end
40
+
41
+ ENV.update(my_env)
42
+
43
+ it 'creates an object using implicit hash args' do
44
+ reg = 'us-west-1'
45
+ ak = 'my_access_key1'
46
+ sk = 'my_secret_key1'
47
+
48
+ aws = Cloudutil::AWS::Core.new(region: reg, access_key: ak, secret_key: sk)
49
+
50
+ expect(aws.region).to eq reg
51
+ expect(aws.access_key).to eq ak
52
+ expect(aws.secret_key).to eq sk
53
+ end
54
+
55
+ it 'creates an object using explicit hash args' do
56
+ reg = 'us-west-2'
57
+ ak = 'my_access_key2'
58
+ sk = 'my_secret_key2'
59
+
60
+ aws = Cloudutil::AWS::Core.new(region: reg, access_key: ak, secret_key: sk)
61
+
62
+ expect(aws.region).to eq reg
63
+ expect(aws.access_key).to eq ak
64
+ expect(aws.secret_key).to eq sk
65
+ end
66
+
67
+ it 'creates an object using sparse hash args' do
68
+ aws = Cloudutil::AWS::Core.new(access_key: 'test_key')
69
+
70
+ expect(aws.region).to eq 'us-east-1'
71
+ expect(aws.access_key).to eq 'test_key'
72
+ expect(aws.secret_key).to_not be_nil if ENV['AWS_SECRET_ACCESS_KEY']
73
+ end
74
+
75
+ it 'creates an object using implicit array args' do
76
+ reg = 'us-west-1'
77
+ ak = 'my_access_key3'
78
+ sk = 'my_secret_key3'
79
+
80
+ aws = Cloudutil::AWS::Core.new(region: reg, access_key: ak, secret_key: sk)
81
+
82
+ expect(aws.region).to eq reg
83
+ expect(aws.access_key).to eq ak
84
+ expect(aws.secret_key).to eq sk
85
+ end
86
+
87
+ it 'creates an object using explicit array args' do
88
+ reg = 'us-west-2'
89
+ ak = 'my_access_key4'
90
+ sk = 'my_secret_key4'
91
+
92
+ aws = Cloudutil::AWS::Core.new(region: reg, access_key: ak, secret_key: sk)
93
+
94
+ expect(aws.region).to eq reg
95
+ expect(aws.access_key).to eq ak
96
+ expect(aws.secret_key).to eq sk
97
+ end
98
+
99
+ it 'creates an object using sparse array args' do
100
+ aws = Cloudutil::AWS::Core.new('us-west-2')
101
+
102
+ expect(aws.region).to eq 'us-west-2'
103
+ expect(aws.access_key).to_not be_nil if ENV['AWS_ACCESS_KEY_ID']
104
+ expect(aws.secret_key).to_not be_nil if ENV['AWS_SECRET_ACCESS_KEY']
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,170 @@
1
+ require_relative '../lib/cloudutil/aws.rb'
2
+
3
+ describe Cloudutil::AWS::EC2 do
4
+ context 'object initialization' do
5
+ it 'creates an object using primary env vars' do
6
+ ENV.clear
7
+ ENV['AWS_ACCESS_KEY_ID'] = 'my_primary_access_key'
8
+ ENV['AWS_SECRET_ACCESS_KEY'] = 'my_primary_secret_key'
9
+
10
+ aws = Cloudutil::AWS::EC2.new
11
+
12
+ expect(aws.region).to eq 'us-east-1'
13
+ expect(aws.access_key).to eq 'my_primary_access_key'
14
+ expect(aws.secret_key).to eq 'my_primary_secret_key'
15
+ end
16
+
17
+ it 'creates an object using implicit hash args' do
18
+ reg = 'us-west-1'
19
+ ak = 'my_access_key1'
20
+ sk = 'my_secret_key1'
21
+
22
+ aws = Cloudutil::AWS::EC2.new(region: reg, access_key: ak, secret_key: sk)
23
+
24
+ expect(aws.region).to eq reg
25
+ expect(aws.access_key).to eq ak
26
+ expect(aws.secret_key).to eq sk
27
+ end
28
+ end
29
+
30
+ context 'resolving VPC subnets' do
31
+ # Need to do this to read AWS creds from env
32
+ my_env = ENV.to_h
33
+ before(:each) do
34
+ @aws = Cloudutil::AWS::EC2.new(access_key: my_env['AWS_ACCESS_KEY_ID'], secret_key: my_env['AWS_SECRET_ACCESS_KEY'])
35
+ end
36
+
37
+ it 'returns what we passed in, if it looks like an AWS subnet id' do
38
+ id = @aws.resolve_subnet_id('subnet-deadbeef')
39
+ expect(id).to eq 'subnet-deadbeef'
40
+ end
41
+
42
+ it 'returns a known VPC subnet object, case-sensitive', account_specific: true do
43
+ id = @aws.resolve_subnet_id('vpc-private-azA', false)
44
+
45
+ expect(id).to_not be_nil
46
+ expect(id).to match(/^subnet-\h{8,}$/)
47
+ end
48
+
49
+ it 'returns a known VPC subnet object, case-insensitive', account_specific: true do
50
+ id = @aws.resolve_subnet_id('VPC-Private-AZa')
51
+
52
+ expect(id).to_not be_nil
53
+ expect(id).to match(/^subnet-\h{8,}$/)
54
+ end
55
+
56
+ it 'returns nil for no case-sensitive VPC subnet match', account_specific: true do
57
+ id = @aws.resolve_subnet_id('VPC-private-aza', false)
58
+ expect(id).to be_nil
59
+ end
60
+
61
+ it 'returns nil if given a completely bogus name' do
62
+ id = @aws.resolve_subnet_id('my_totally_bogus_subnet_name')
63
+ expect(id).to be_nil
64
+ end
65
+ end
66
+
67
+ context 'resolving security groups' do
68
+ my_env = ENV.to_h
69
+ before(:each) do
70
+ @aws = Cloudutil::AWS::EC2.new(access_key: my_env['AWS_ACCESS_KEY_ID'], secret_key: my_env['AWS_SECRET_ACCESS_KEY'])
71
+ end
72
+
73
+ it 'returns what we pass in, if it looks like an AWS security group id' do
74
+ id = @aws.resolve_security_group_id('sg-deadbeef')
75
+ expect(id).to eq 'sg-deadbeef'
76
+ end
77
+
78
+ it 'returns a known security group by name, case-sensitive', account_specific: true do
79
+ id = @aws.resolve_security_group_id('VPC_Private', false)
80
+
81
+ expect(id).to_not be_nil
82
+ expect(id).to match(/^sg-\h{8,}$/)
83
+ end
84
+
85
+ it 'returns a known security group by name, case-insensitive', account_specific: true do
86
+ id = @aws.resolve_security_group_id('vpc_PRIVATE')
87
+
88
+ expect(id).to_not be_nil
89
+ expect(id).to match(/^sg-\h{8,}$/)
90
+ end
91
+
92
+ it 'returns a known security group by tag, case-sensitive', account_specific: true do
93
+ id = @aws.resolve_security_group_id('vpc-private', false)
94
+
95
+ expect(id).to_not be_nil
96
+ expect(id).to match(/^sg-\h{8,}$/)
97
+ end
98
+
99
+ it 'returns a known security group by tag, case-insensitive', account_specific: true do
100
+ id = @aws.resolve_security_group_id('VPC-PrIvAtE')
101
+
102
+ expect(id).to_not be_nil
103
+ expect(id).to match(/^sg-\h{8,}$/)
104
+ end
105
+
106
+ it 'returns nil for no case-sensitive security group name or tag match', account_specific: true do
107
+ id = @aws.resolve_security_group_id('vpc_PrivatE', false)
108
+ expect(id).to be_nil
109
+ end
110
+
111
+ it 'returns nil if given a completely bogus name/tag value' do
112
+ id = @aws.resolve_subnet_id('my_totally_bogus_subnet_name')
113
+ expect(id).to be_nil
114
+ end
115
+ end
116
+
117
+ context 'resolving AMIs' do
118
+ my_env = ENV.to_h
119
+ before(:each) do
120
+ @aws = Cloudutil::AWS::EC2.new(access_key: my_env['AWS_ACCESS_KEY_ID'], secret_key: my_env['AWS_SECRET_ACCESS_KEY'])
121
+ end
122
+
123
+ it 'returns what we pass in, if it looks like an AWS ami id' do
124
+ id = @aws.resolve_ami_id('ami-deadbeef')
125
+ expect(id).to eq 'ami-deadbeef'
126
+ end
127
+
128
+ it 'returns a known AMI by name, case-sensitive', account_specific: true do
129
+ id = @aws.resolve_ami_id('AMIBakery-MRE-28', false)
130
+
131
+ expect(id).to_not be_nil
132
+ expect(id).to match(/^ami-\h{8,}$/)
133
+ end
134
+
135
+ it 'returns a known AMI by name, case-insensitive', account_specific: true do
136
+ id = @aws.resolve_ami_id('amiBAKERY-mre-28')
137
+
138
+ expect(id).to_not be_nil
139
+ expect(id).to match(/^ami-\h{8,}$/)
140
+ end
141
+
142
+ it 'returns a known AMI by tag, case-sensitive', account_specific: true do
143
+ id = @aws.resolve_ami_id('pearson_jenkins_ubuntu', false)
144
+
145
+ expect(id).to_not be_nil
146
+ expect(id).to match(/^ami-\h{8,}$/)
147
+ end
148
+
149
+ it 'returns a known AMI by tag, case-insensitive', account_specific: true do
150
+ id = @aws.resolve_ami_id('Pearson_JENKINS_uBuntu')
151
+
152
+ expect(id).to_not be_nil
153
+ expect(id).to match(/^ami-\h{8,}$/)
154
+ end
155
+
156
+ # WARNING: This test can take over a minute to run, since it has to inspect the
157
+ # properties of all 31k public AMIs + any private AMIs my account has access to.
158
+ it 'returns nil for no case-sensitive AMI name or tag match', slow: true, account_specific: true do
159
+ id = @aws.resolve_ami_id('amiBakery-mRe-28', false)
160
+ expect(id).to be_nil
161
+ end
162
+
163
+ # WARNING: This test can take over a minute to run, since it has to inspect the
164
+ # properties of all 31k public AMIs + any private AMIs my account has access to.
165
+ it 'returns nil if given a completly bogus name/tag value', slow: true do
166
+ id = @aws.resolve_ami_id('my_totally_bogus_ami_name')
167
+ expect(id).to be_nil
168
+ end
169
+ end
170
+ end
metadata ADDED
@@ -0,0 +1,169 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudutil
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Mike Morris
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-11-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rubocop
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: aws-sdk
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ~>
74
+ - !ruby/object:Gem::Version
75
+ version: '1.44'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ~>
81
+ - !ruby/object:Gem::Version
82
+ version: '1.44'
83
+ description: |
84
+ # Cloudutil
85
+
86
+ A utility library for performing helpful tasks with various cloud platform providers
87
+
88
+ ## Installation
89
+
90
+ Add this line to your application's Gemfile:
91
+
92
+ gem 'cloudutil'
93
+
94
+ And then execute:
95
+
96
+ $ bundle install
97
+
98
+ Or install it yourself as:
99
+
100
+ $ gem install cloudutil
101
+
102
+ ## Usage
103
+
104
+ For AWS helpers:
105
+
106
+ require 'cloudutil/aws'
107
+
108
+ aws = Cloudutil::AWS(config: existing_AWS::Config_object) -or-
109
+ aws = Cloudutil::AWS(access_key: your_AWS_access_key, secret_key: your_AWS_secret_key)
110
+
111
+ subnet_id = aws.resolve_subnet_id('my_subnet_name_or_tag')
112
+ sec_grp_id = aws.resolve_subnet_id('my_security_group_name_or_tag')
113
+ ami_id = aws.resolve_subnet_id('my_ami_name_or_tag')
114
+
115
+ ## Contributing
116
+
117
+ 1. Fork it ( https://github.com/mmmorris1975/cloudutil/fork )
118
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
119
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
120
+ 4. Push to the branch (`git push origin my-new-feature`)
121
+ 5. Create a new Pull Request
122
+ email:
123
+ - michael.m.morris@pearson.com
124
+ executables: []
125
+ extensions: []
126
+ extra_rdoc_files: []
127
+ files:
128
+ - .gitignore
129
+ - .rubocop.yml
130
+ - Gemfile
131
+ - LICENSE
132
+ - README.md
133
+ - Rakefile
134
+ - cloudutil.gemspec
135
+ - lib/cloudutil.rb
136
+ - lib/cloudutil/aws.rb
137
+ - lib/cloudutil/aws/core.rb
138
+ - lib/cloudutil/aws/ec2.rb
139
+ - lib/cloudutil/version.rb
140
+ - spec/aws_core_spec.rb
141
+ - spec/aws_ec2_spec.rb
142
+ homepage: ''
143
+ licenses:
144
+ - MIT
145
+ metadata: {}
146
+ post_install_message:
147
+ rdoc_options: []
148
+ require_paths:
149
+ - lib
150
+ required_ruby_version: !ruby/object:Gem::Requirement
151
+ requirements:
152
+ - - '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ required_rubygems_version: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ requirements: []
161
+ rubyforge_project:
162
+ rubygems_version: 2.2.2
163
+ signing_key:
164
+ specification_version: 4
165
+ summary: A utility library for performing helpful tasks with various cloud platform
166
+ providers
167
+ test_files:
168
+ - spec/aws_core_spec.rb
169
+ - spec/aws_ec2_spec.rb