awspec 0.0.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 +7 -0
- data/.editorconfig +13 -0
- data/.gitignore +10 -0
- data/.rubocop.yml +50 -0
- data/.travis.yml +11 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +68 -0
- data/Rakefile +16 -0
- data/awspec.gemspec +29 -0
- data/bin/awspec +5 -0
- data/lib/awspec.rb +11 -0
- data/lib/awspec/cli.rb +11 -0
- data/lib/awspec/ext/string.rb +14 -0
- data/lib/awspec/helper.rb +6 -0
- data/lib/awspec/helper/type.rb +18 -0
- data/lib/awspec/matcher.rb +9 -0
- data/lib/awspec/matcher/be_opened.rb +17 -0
- data/lib/awspec/matcher/belong_to_db_subnet_group.rb +5 -0
- data/lib/awspec/matcher/belong_to_subnet.rb +33 -0
- data/lib/awspec/matcher/belong_to_vpc.rb +8 -0
- data/lib/awspec/setup.rb +75 -0
- data/lib/awspec/type/base.rb +63 -0
- data/lib/awspec/type/ec2.rb +90 -0
- data/lib/awspec/type/rds.rb +115 -0
- data/lib/awspec/type/security_group.rb +90 -0
- data/lib/awspec/type/vpc.rb +45 -0
- data/lib/awspec/version.rb +3 -0
- metadata +169 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c7cdec523d2ed0c3f17c1fe819f9ec63907135d7
|
4
|
+
data.tar.gz: 8a56f108f5fd80304b1c7f2d12cd14992cf0ebd7
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f22da57b3c932b9e98ab55e6a07db11346c45ba90e126e72a411a81d0d315eb424b49502e453b8a77b2d19cf639bac380b7eef610a91b7c095ff2beca1d2cc5
|
7
|
+
data.tar.gz: 74de2a12f8a98ab7fc1f4409d86972e36611e781be22db161caddc0cf99becd3f3c195b1f7cc594b22167dc5302bd5e8e129521440f134c40fb6a63c87e92500
|
data/.editorconfig
ADDED
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
Lint/Eval:
|
2
|
+
Enabled: false
|
3
|
+
|
4
|
+
Lint/HandleExceptions:
|
5
|
+
Enabled: false
|
6
|
+
|
7
|
+
Lint/UselessAssignment:
|
8
|
+
Enabled: false
|
9
|
+
|
10
|
+
Metrics/AbcSize:
|
11
|
+
Max: 50
|
12
|
+
|
13
|
+
Metrics/ClassLength:
|
14
|
+
Max: 120
|
15
|
+
|
16
|
+
Metrics/CyclomaticComplexity:
|
17
|
+
Max: 15
|
18
|
+
|
19
|
+
Metrics/LineLength:
|
20
|
+
Max: 120
|
21
|
+
|
22
|
+
Metrics/MethodLength:
|
23
|
+
Max: 30
|
24
|
+
|
25
|
+
Metrics/PerceivedComplexity:
|
26
|
+
Max: 15
|
27
|
+
|
28
|
+
Style/BarePercentLiterals:
|
29
|
+
Enabled: false
|
30
|
+
|
31
|
+
Style/ClassAndModuleChildren:
|
32
|
+
Enabled: false
|
33
|
+
|
34
|
+
Style/Documentation:
|
35
|
+
Enabled: false
|
36
|
+
|
37
|
+
Style/PercentLiteralDelimiters:
|
38
|
+
Enabled: false
|
39
|
+
|
40
|
+
Style/PredicateName:
|
41
|
+
Enabled: false
|
42
|
+
|
43
|
+
Style/RedundantSelf:
|
44
|
+
Enabled: false
|
45
|
+
|
46
|
+
Style/SymbolProc:
|
47
|
+
Enabled: false
|
48
|
+
|
49
|
+
Style/BracesAroundHashParameters:
|
50
|
+
Enabled: false
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Ken'ichiro Oyama
|
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
|
13
|
+
all 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
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# awspec [](https://travis-ci.org/k1LoW/awspec)
|
2
|
+
|
3
|
+
RSpec tests for your AWS resources.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'awspec'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install awspec
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
### 1. Generate awspec template
|
24
|
+
|
25
|
+
$ awspec init
|
26
|
+
|
27
|
+
### 2. Write *_spec.rb
|
28
|
+
|
29
|
+
```ruby
|
30
|
+
describe ec2('i-ec12345a') do
|
31
|
+
it { should be_running }
|
32
|
+
its(:instance_id) { should eq 'i-ec12345a' }
|
33
|
+
its(:image_id) { should eq 'ami-abc12def' }
|
34
|
+
its(:public_ip_address) { should eq '123.0.456.789' }
|
35
|
+
it { should have_security_group('my-security-group-name') }
|
36
|
+
it { should belong_to_vpc('my-vpc') }
|
37
|
+
it { should belong_to_subnet('subnet-1234a567') }
|
38
|
+
it { should have_eip('123.0.456.789') }
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
## Support AWS Resources
|
43
|
+
|
44
|
+
- [X] EC2
|
45
|
+
- [X] RDS
|
46
|
+
- [ ] RDS DB Parameter
|
47
|
+
- [X] Security Group
|
48
|
+
- [X] VPC
|
49
|
+
|
50
|
+
### Next..
|
51
|
+
|
52
|
+
- [ ] S3
|
53
|
+
- [ ] Route53
|
54
|
+
- ...
|
55
|
+
|
56
|
+
## Contributing
|
57
|
+
|
58
|
+
1. Fork it ( https://github.com/k1LoW/awspec/fork )
|
59
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
60
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
61
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
62
|
+
5. Create a new Pull Request
|
63
|
+
|
64
|
+
## References
|
65
|
+
|
66
|
+
- Original idea (code / architecture) -> [Serverspec](https://github.com/serverspec/serverspec)
|
67
|
+
- awspec original concept -> https://github.com/marcy-terui/awspec
|
68
|
+
- [Serverspec book](http://www.oreilly.co.jp/books/9784873117096/)
|
data/Rakefile
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'bundler/gem_tasks'
|
2
|
+
begin
|
3
|
+
require 'rspec/core/rake_task'
|
4
|
+
rescue LoadError
|
5
|
+
end
|
6
|
+
|
7
|
+
if defined?(RSpec)
|
8
|
+
task spec: 'spec:all'
|
9
|
+
namespace :spec do
|
10
|
+
task all: ['spec:type']
|
11
|
+
|
12
|
+
RSpec::Core::RakeTask.new(:type) do |t|
|
13
|
+
t.pattern = 'spec/type/*_spec.rb'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/awspec.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'awspec/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'awspec'
|
8
|
+
spec.version = Awspec::VERSION
|
9
|
+
spec.authors = ['k1LoW']
|
10
|
+
spec.email = ['k1lowxb@gmail.com']
|
11
|
+
|
12
|
+
spec.summary = 'RSpec tests for your AWS resources.'
|
13
|
+
spec.description = 'RSpec tests for your AWS resources.'
|
14
|
+
spec.homepage = 'https://github.com/k1LoW/awspec'
|
15
|
+
spec.license = 'MIT'
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = 'exe'
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ['lib']
|
21
|
+
|
22
|
+
spec.add_runtime_dependency 'rspec', '~> 3.0'
|
23
|
+
spec.add_runtime_dependency 'rspec-its'
|
24
|
+
spec.add_runtime_dependency 'aws-sdk', '~> 2'
|
25
|
+
spec.add_runtime_dependency 'thor'
|
26
|
+
spec.add_development_dependency 'bundler', '~> 1.9'
|
27
|
+
spec.add_development_dependency 'rake', '~> 10.0'
|
28
|
+
spec.add_development_dependency 'rubocop'
|
29
|
+
end
|
data/bin/awspec
ADDED
data/lib/awspec.rb
ADDED
data/lib/awspec/cli.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
class String
|
2
|
+
def to_snake_case
|
3
|
+
self.gsub(/::/, '/')
|
4
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
5
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
6
|
+
.tr('-', '_')
|
7
|
+
.downcase
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_camel_case
|
11
|
+
return self if self !~ /_/ && self =~ /[A-Z]+.*/
|
12
|
+
split('_').map { |e| e.capitalize }.join
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Awspec
|
2
|
+
module Helper
|
3
|
+
module Type
|
4
|
+
types = %w(
|
5
|
+
base ec2 rds security_group vpc
|
6
|
+
)
|
7
|
+
|
8
|
+
types.each { |type| require "awspec/type/#{type}" }
|
9
|
+
|
10
|
+
types.each do |type|
|
11
|
+
define_method type do |*args|
|
12
|
+
name = args.first
|
13
|
+
eval "Awspec::Type::#{type.to_camel_case}.new(name)"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
RSpec::Matchers.define :be_opened do |port|
|
2
|
+
match do |sg|
|
3
|
+
sg.opened?(port, @protocol, @cidr)
|
4
|
+
end
|
5
|
+
|
6
|
+
chain :protocol do |protocol|
|
7
|
+
@protocol = protocol
|
8
|
+
end
|
9
|
+
|
10
|
+
chain :for do |cidr|
|
11
|
+
@cidr = cidr
|
12
|
+
end
|
13
|
+
|
14
|
+
chain :target do |cidr|
|
15
|
+
@cidr = cidr
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
RSpec::Matchers.define :belong_to_subnet do |subnet_id|
|
2
|
+
match do |resource|
|
3
|
+
# EC2
|
4
|
+
if resource.instance_of?(Awspec::Type::Ec2)
|
5
|
+
return true if resource.subnet_id == subnet_id
|
6
|
+
ret = resource.client.describe_subnets({
|
7
|
+
filters: [{ name: 'tag:Name', values: [subnet_id] }]
|
8
|
+
})
|
9
|
+
return false unless ret
|
10
|
+
return ret[:subnets][0][:subnet_id] == resource.subnet_id
|
11
|
+
end
|
12
|
+
|
13
|
+
# RDS
|
14
|
+
if resource.instance_of?(Awspec::Type::Rds)
|
15
|
+
subnets = resource.instance[:db_subnet_group][:subnets]
|
16
|
+
ret = subnets.find do |subnet|
|
17
|
+
subnet[:subnet_identifier] == subnet_id
|
18
|
+
end
|
19
|
+
|
20
|
+
return ret[:subnet_availability_zone][:name] == resource.availability_zone if ret
|
21
|
+
|
22
|
+
res = resource.ec2_client.describe_subnets({
|
23
|
+
filters: [{ name: 'tag:Name', values: [subnet_id] }]
|
24
|
+
})
|
25
|
+
return false unless res
|
26
|
+
ret = subnets.find do |subnet|
|
27
|
+
subnet[:subnet_identifier] == res[:subnets][0][:subnet_id]
|
28
|
+
end
|
29
|
+
|
30
|
+
return ret[:subnet_availability_zone][:name] == resource.availability_zone if ret
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
data/lib/awspec/setup.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Awspec
|
4
|
+
class Setup
|
5
|
+
def self.run
|
6
|
+
generate_spec_helper
|
7
|
+
generate_rakefile
|
8
|
+
generate_dotgitignore
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.generate_spec_helper
|
12
|
+
content = <<-'EOF'
|
13
|
+
require 'awspec'
|
14
|
+
if File.exist?('secrets.yml')
|
15
|
+
creds = YAML.load_file('secrets.yml')
|
16
|
+
Aws.config.update({
|
17
|
+
region: creds['region'],
|
18
|
+
credentials: Aws::Credentials.new(
|
19
|
+
creds['aws_access_key_id'],
|
20
|
+
creds['aws_secret_access_key'])
|
21
|
+
})
|
22
|
+
end
|
23
|
+
EOF
|
24
|
+
dir = 'spec'
|
25
|
+
if File.exist? dir
|
26
|
+
unless File.directory? dir
|
27
|
+
$stderr.puts '!! #{dir} already exists and is not a directory'
|
28
|
+
end
|
29
|
+
else
|
30
|
+
FileUtils.mkdir dir
|
31
|
+
puts ' + #{dir}/'
|
32
|
+
end
|
33
|
+
|
34
|
+
if File.exist? 'spec/spec_helper.rb'
|
35
|
+
$stderr.puts '!! spec/spec_helper.rb already exists'
|
36
|
+
else
|
37
|
+
File.open('spec/spec_helper.rb', 'w') do |f|
|
38
|
+
f.puts content
|
39
|
+
end
|
40
|
+
puts ' + spec/spec_helper.rb'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.generate_rakefile
|
45
|
+
content = <<-'EOF'
|
46
|
+
require 'rspec/core/rake_task'
|
47
|
+
RSpec::Core::RakeTask.new('spec')
|
48
|
+
task :default => :spec
|
49
|
+
EOF
|
50
|
+
|
51
|
+
if File.exist? 'Rakefile'
|
52
|
+
$stderr.puts '!! Rakefile already exists'
|
53
|
+
else
|
54
|
+
File.open('Rakefile', 'w') do |f|
|
55
|
+
f.puts content
|
56
|
+
end
|
57
|
+
puts ' + Rakefile'
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.generate_dotgitignore
|
62
|
+
content = <<-'EOF'
|
63
|
+
secrets.yml
|
64
|
+
EOF
|
65
|
+
if File.exist? 'spec/.gitignore'
|
66
|
+
$stderr.puts '!! spec/.gitignore already exists'
|
67
|
+
else
|
68
|
+
File.open('spec/.gitignore', 'w') do |f|
|
69
|
+
f.puts content
|
70
|
+
end
|
71
|
+
puts ' + spec/.gitignore'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'aws-sdk'
|
2
|
+
|
3
|
+
module Awspec::Type
|
4
|
+
class Base
|
5
|
+
attr_reader :id, :ec2_client
|
6
|
+
|
7
|
+
def initialize(id = nil)
|
8
|
+
@tmp = id
|
9
|
+
@ec2_client = Aws::EC2::Client.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def find_vpc(id)
|
13
|
+
res = @ec2_client.describe_vpcs({
|
14
|
+
filters: [{ name: 'vpc-id', values: [id] }]
|
15
|
+
})
|
16
|
+
return res[:vpcs][0] if res[:vpcs].count == 1
|
17
|
+
res = @ec2_client.describe_vpcs({
|
18
|
+
filters: [{ name: 'tag:Name', values: [id] }]
|
19
|
+
})
|
20
|
+
return res[:vpcs][0] if res[:vpcs].count == 1
|
21
|
+
end
|
22
|
+
|
23
|
+
def find_route_table(id)
|
24
|
+
res = @ec2_client.describe_route_tables({
|
25
|
+
filters: [{ name: 'route-table-id', values: [id] }]
|
26
|
+
})
|
27
|
+
return res[:route_tables][0] if res[:route_tables].count == 1
|
28
|
+
res = @ec2_client.describe_route_tables({
|
29
|
+
filters: [{ name: 'tag:Name', values: [id] }]
|
30
|
+
})
|
31
|
+
return res[:route_tables][0] if res[:route_tables].count == 1
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_network_acl(id)
|
35
|
+
res = @ec2_client.describe_network_acls({
|
36
|
+
filters: [{ name: 'network-acl-id', values: [id] }]
|
37
|
+
})
|
38
|
+
return res[:network_acls][0] if res[:network_acls].count == 1
|
39
|
+
res = @ec2_client.describe_network_acls({
|
40
|
+
filters: [{ name: 'tag:Name', values: [id] }]
|
41
|
+
})
|
42
|
+
return res[:network_acls][0] if res[:network_acls].count == 1
|
43
|
+
end
|
44
|
+
|
45
|
+
def find_security_group(id)
|
46
|
+
res = @ec2_client.describe_security_groups({
|
47
|
+
filters: [{ name: 'group-id', values: [id] }]
|
48
|
+
})
|
49
|
+
|
50
|
+
return res[:security_groups][0] if res[:security_groups].count == 1
|
51
|
+
res = @ec2_client.describe_security_groups({
|
52
|
+
filters: [{ name: 'group-name', values: [id] }]
|
53
|
+
})
|
54
|
+
|
55
|
+
return res[:security_groups][0] if res[:security_groups].count == 1
|
56
|
+
res = @ec2_client.describe_security_groups({
|
57
|
+
filters: [{ name: 'tag:Name', values: [id] }]
|
58
|
+
})
|
59
|
+
|
60
|
+
return res[:security_groups][0] if res[:security_groups].count == 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Awspec::Type
|
2
|
+
class Ec2 < Base
|
3
|
+
attr_reader :client, :instance
|
4
|
+
|
5
|
+
def initialize(id)
|
6
|
+
super
|
7
|
+
@client = @ec2_client
|
8
|
+
if id.is_a?(Array)
|
9
|
+
# Aws::EC2::Client.describe_instances native filters format
|
10
|
+
res = @client.describe_instances({
|
11
|
+
filters: id
|
12
|
+
})
|
13
|
+
elsif id.is_a?(Hash)
|
14
|
+
# syntax sugar
|
15
|
+
filters = []
|
16
|
+
id.each do |k, v|
|
17
|
+
filters.push({ name: k, values: Array(v) })
|
18
|
+
end
|
19
|
+
res = @client.describe_instances({
|
20
|
+
filters: filters
|
21
|
+
})
|
22
|
+
else
|
23
|
+
# instance_id or tag:Name
|
24
|
+
begin
|
25
|
+
res = @client.describe_instances({
|
26
|
+
instance_ids: [id]
|
27
|
+
})
|
28
|
+
rescue
|
29
|
+
# Aws::EC2::Errors::InvalidInstanceIDMalformed
|
30
|
+
# Aws::EC2::Errors::InvalidInstanceIDNotFound
|
31
|
+
res = @client.describe_instances({
|
32
|
+
filters: [{ name: 'tag:Name', values: [id] }]
|
33
|
+
})
|
34
|
+
end
|
35
|
+
end
|
36
|
+
@id = res[:reservations][0][:instances][0][:instance_id]
|
37
|
+
@instance = res[:reservations][0][:instances][0]
|
38
|
+
end
|
39
|
+
|
40
|
+
states = %w(
|
41
|
+
pending running shutting-down
|
42
|
+
terminated stopping stopped
|
43
|
+
)
|
44
|
+
|
45
|
+
states.each do |state|
|
46
|
+
define_method state + '?' do
|
47
|
+
@instance[:state][:name] == state
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describes = %w(
|
52
|
+
instance_id image_id state private_dns_name public_dns_name
|
53
|
+
state_transition_reason key_name ami_launch_index product_codes
|
54
|
+
instance_type launch_time placement kernel_id ramdisk_id platform
|
55
|
+
monitoring subnet_id vpc_id private_ip_address public_ip_address
|
56
|
+
state_reason architecture root_device_type root_device_name
|
57
|
+
block_device_mappings virtualization_type instance_lifecycle
|
58
|
+
spot_instance_request_id client_token tags security_groups
|
59
|
+
source_dest_check hypervisor network_interfaces
|
60
|
+
iam_instance_profile ebs_optimized sriov_net_support
|
61
|
+
)
|
62
|
+
|
63
|
+
describes.each do |describe|
|
64
|
+
define_method describe do
|
65
|
+
@instance[describe]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def has_eip?(ip_address = nil)
|
70
|
+
option = {
|
71
|
+
filters: [{ name: 'instance-id', values: [@id] }]
|
72
|
+
}
|
73
|
+
option[:public_ips] = [ip_address] if ip_address
|
74
|
+
ret = @client.describe_addresses(option)
|
75
|
+
ret[:addresses].count == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
def has_security_group?(sg_id)
|
79
|
+
sgs = @instance[:security_groups]
|
80
|
+
ret = sgs.find do |sg|
|
81
|
+
sg[:group_id] == sg_id || sg[:group_name] == sg_id
|
82
|
+
end
|
83
|
+
return true if ret
|
84
|
+
sg2 = find_security_group(sg_id)
|
85
|
+
sg2[:tags].find do |tag|
|
86
|
+
tag[:key] == 'Name' && tag[:value] == sg_id
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
module Awspec::Type
|
2
|
+
class Rds < Base
|
3
|
+
attr_reader :client, :instance
|
4
|
+
|
5
|
+
def initialize(id)
|
6
|
+
super
|
7
|
+
@client = Aws::RDS::Client.new
|
8
|
+
# db_instance_identifier
|
9
|
+
res = @client.describe_db_instances({
|
10
|
+
db_instance_identifier: id
|
11
|
+
})
|
12
|
+
@id = res[:db_instances][0][:db_instance_identifier]
|
13
|
+
@instance = res[:db_instances][0]
|
14
|
+
end
|
15
|
+
|
16
|
+
states = %w(
|
17
|
+
available backing-up creating deleting
|
18
|
+
failed inaccessible-encryption-credentials
|
19
|
+
incompatible-credentials incompatible-network
|
20
|
+
incompatible-option-group incompatible-parameters
|
21
|
+
incompatible-restore maintenance
|
22
|
+
modifying rebooting renaming resetting-master-credentials
|
23
|
+
restore-error storage-full upgrading
|
24
|
+
)
|
25
|
+
|
26
|
+
states.each do |state|
|
27
|
+
define_method state + '?' do
|
28
|
+
@instance[:db_instance_status] == state
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describes = %w(
|
33
|
+
db_instance_identifier db_instance_class engine db_instance_status
|
34
|
+
master_username db_name endpoint allocated_storage instance_create_time
|
35
|
+
preferred_backup_window backup_retention_period db_security_groups
|
36
|
+
vpc_security_groups db_parameter_groups availability_zone
|
37
|
+
db_subnet_group preferred_maintenance_window pending_modified_values
|
38
|
+
latest_restorable_time multi_az engine_version auto_minor_version_upgrade
|
39
|
+
read_replica_source_db_instance_identifier
|
40
|
+
read_replica_db_instance_identifiers license_model iops
|
41
|
+
option_group_memberships character_set_name secondary_availability_zone
|
42
|
+
publicly_accessible status_infos storage_type tde_credential_arn
|
43
|
+
storage_encrypted kms_key_id dbi_resource_id ca_certificate_identifier
|
44
|
+
)
|
45
|
+
|
46
|
+
describes.each do |describe|
|
47
|
+
define_method describe do
|
48
|
+
@instance[describe]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def vpc_id
|
53
|
+
@instance[:db_subnet_group][:vpc_id]
|
54
|
+
end
|
55
|
+
|
56
|
+
def has_security_group?(sg_id)
|
57
|
+
return true if has_vpc_security_group_id?(sg_id)
|
58
|
+
return true if has_vpc_security_group_name?(sg_id)
|
59
|
+
return true if has_vpc_security_group_tag_name?(sg_id)
|
60
|
+
return true if has_db_security_group_name?(sg_id)
|
61
|
+
end
|
62
|
+
|
63
|
+
def has_db_parameter_group?(name)
|
64
|
+
pgs = @instance[:db_parameter_groups]
|
65
|
+
pgs.find do |pg|
|
66
|
+
pg[:db_parameter_group_name] == name
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def has_option_group?(name)
|
71
|
+
ogs = @instance[:option_group_memberships]
|
72
|
+
ogs.find do |og|
|
73
|
+
og[:option_group_name] == name
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def has_vpc_security_group_id?(sg_id)
|
80
|
+
sgs = @instance[:vpc_security_groups]
|
81
|
+
sgs.find do |sg|
|
82
|
+
sg[:vpc_security_group_id] == sg_id
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def has_vpc_security_group_name?(sg_id)
|
87
|
+
sgs = @instance[:vpc_security_groups]
|
88
|
+
res = @ec2_client.describe_security_groups({
|
89
|
+
filters: [{ name: 'group-name', values: [sg_id] }]
|
90
|
+
})
|
91
|
+
return false unless res[:security_groups].count == 1
|
92
|
+
sgs.find do |sg|
|
93
|
+
sg[:vpc_security_group_id] == res[:security_groups][0][:group_id]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def has_vpc_security_group_tag_name?(sg_id)
|
98
|
+
sgs = @instance[:vpc_security_groups]
|
99
|
+
res = @ec2_client.describe_security_groups({
|
100
|
+
filters: [{ name: 'tag:Name', values: [sg_id] }]
|
101
|
+
})
|
102
|
+
return false unless res[:security_groups].count == 1
|
103
|
+
sgs.find do |sg|
|
104
|
+
sg[:vpc_security_group_id] == res[:security_groups][0][:group_id]
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def has_db_security_group_name?(sg_id)
|
109
|
+
sgs = @instance[:db_security_groups]
|
110
|
+
sgs.find do |sg|
|
111
|
+
sg[:db_security_group_name] == sg_id
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Awspec::Type
|
2
|
+
class SecurityGroup < Base
|
3
|
+
attr_reader :client, :sg, :inbound
|
4
|
+
|
5
|
+
def initialize(id)
|
6
|
+
super
|
7
|
+
@client = @ec2_client
|
8
|
+
@inbound = true
|
9
|
+
@sg = find_security_group(id)
|
10
|
+
@id = @sg[:group_id]
|
11
|
+
end
|
12
|
+
|
13
|
+
describes = %w(
|
14
|
+
owner_id group_name group_id description
|
15
|
+
ip_permissions ip_permissions_egress vpc_id tags
|
16
|
+
)
|
17
|
+
|
18
|
+
describes.each do |describe|
|
19
|
+
define_method describe do
|
20
|
+
@sg[describe]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def opened?(port = nil, protocol = nil, cidr = nil)
|
25
|
+
if @inbound
|
26
|
+
return inbound_opened?(port, protocol, cidr)
|
27
|
+
else
|
28
|
+
return outbound_opened?(port, protocol, cidr)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def inbound_opened?(port = nil, protocol = nil, cidr = nil)
|
33
|
+
@sg[:ip_permissions].find do |permission|
|
34
|
+
next true unless port
|
35
|
+
next true unless permission[:from_port]
|
36
|
+
next true unless permission[:to_port]
|
37
|
+
next false unless port.between?(permission[:from_port], permission[:to_port])
|
38
|
+
next false if protocol && permission[:ip_protocol] != protocol
|
39
|
+
next true unless cidr
|
40
|
+
ret = permission[:ip_ranges].select do |ip_range|
|
41
|
+
ip_range[:cidr_ip] == cidr
|
42
|
+
end
|
43
|
+
next true if ret.count > 0
|
44
|
+
ret = permission[:user_id_group_pairs].select do |sg|
|
45
|
+
next true if sg[:group_id] == cidr
|
46
|
+
sg2 = find_security_group(sg[:group_id])
|
47
|
+
next true if sg2[:group_name] == cidr
|
48
|
+
sg2[:tags].find do |tag|
|
49
|
+
tag[:key] == 'Name' && tag[:value] == cidr
|
50
|
+
end
|
51
|
+
end
|
52
|
+
next true if ret.count > 0
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def outbound_opened?(port = nil, protocol = nil, cidr = nil)
|
57
|
+
@sg[:ip_permissions_egress].find do |permission|
|
58
|
+
next true unless port
|
59
|
+
next true unless permission[:from_port]
|
60
|
+
next true unless permission[:to_port]
|
61
|
+
next false unless port.between?(permission[:from_port], permission[:to_port])
|
62
|
+
next false if protocol && permission[:ip_protocol] != protocol
|
63
|
+
next true unless cidr
|
64
|
+
ret = permission[:ip_ranges].select do |ip_range|
|
65
|
+
ip_range[:cidr_ip] == cidr
|
66
|
+
end
|
67
|
+
next true if ret.count > 0
|
68
|
+
ret = permission[:user_id_group_pairs].select do |sg|
|
69
|
+
next true if sg[:group_id] == cidr
|
70
|
+
sg2 = find_security_group(sg[:group_id])
|
71
|
+
next true if sg2[:group_name] == cidr
|
72
|
+
sg2[:tags].find do |tag|
|
73
|
+
tag[:key] == 'Name' && tag[:value] == cidr
|
74
|
+
end
|
75
|
+
end
|
76
|
+
next true if ret.count > 0
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def inbound
|
81
|
+
@inbound = true
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def outbound
|
86
|
+
@inbound = false
|
87
|
+
self
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Awspec::Type
|
2
|
+
class Vpc < Base
|
3
|
+
attr_reader :client, :vpc
|
4
|
+
|
5
|
+
def initialize(id)
|
6
|
+
super
|
7
|
+
@client = @ec2_client
|
8
|
+
@vpc = find_vpc(id)
|
9
|
+
@id = @vpc[:vpc_id]
|
10
|
+
end
|
11
|
+
|
12
|
+
states = %w(
|
13
|
+
available pending
|
14
|
+
)
|
15
|
+
|
16
|
+
states.each do |state|
|
17
|
+
define_method state + '?' do
|
18
|
+
@vpc[:state] == state
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describes = %w(
|
23
|
+
vpc_id state cidr_block dhcp_options_id
|
24
|
+
tags instance_tenancy is_default
|
25
|
+
)
|
26
|
+
|
27
|
+
describes.each do |describe|
|
28
|
+
define_method describe do
|
29
|
+
@vpc[describe]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def has_route_table?(id)
|
34
|
+
route_table = find_route_table(id)
|
35
|
+
return false unless route_table
|
36
|
+
route_table[:vpc_id] == @id
|
37
|
+
end
|
38
|
+
|
39
|
+
def has_network_acl?(id)
|
40
|
+
n = find_network_acl(id)
|
41
|
+
return false unless n
|
42
|
+
n[:vpc_id] == @id
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
metadata
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: awspec
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- k1LoW
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-07-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec-its
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
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: aws-sdk
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: thor
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :runtime
|
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: bundler
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.9'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.9'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '10.0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '10.0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rubocop
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
description: RSpec tests for your AWS resources.
|
112
|
+
email:
|
113
|
+
- k1lowxb@gmail.com
|
114
|
+
executables: []
|
115
|
+
extensions: []
|
116
|
+
extra_rdoc_files: []
|
117
|
+
files:
|
118
|
+
- ".editorconfig"
|
119
|
+
- ".gitignore"
|
120
|
+
- ".rubocop.yml"
|
121
|
+
- ".travis.yml"
|
122
|
+
- Gemfile
|
123
|
+
- LICENSE.txt
|
124
|
+
- README.md
|
125
|
+
- Rakefile
|
126
|
+
- awspec.gemspec
|
127
|
+
- bin/awspec
|
128
|
+
- lib/awspec.rb
|
129
|
+
- lib/awspec/cli.rb
|
130
|
+
- lib/awspec/ext/string.rb
|
131
|
+
- lib/awspec/helper.rb
|
132
|
+
- lib/awspec/helper/type.rb
|
133
|
+
- lib/awspec/matcher.rb
|
134
|
+
- lib/awspec/matcher/be_opened.rb
|
135
|
+
- lib/awspec/matcher/belong_to_db_subnet_group.rb
|
136
|
+
- lib/awspec/matcher/belong_to_subnet.rb
|
137
|
+
- lib/awspec/matcher/belong_to_vpc.rb
|
138
|
+
- lib/awspec/setup.rb
|
139
|
+
- lib/awspec/type/base.rb
|
140
|
+
- lib/awspec/type/ec2.rb
|
141
|
+
- lib/awspec/type/rds.rb
|
142
|
+
- lib/awspec/type/security_group.rb
|
143
|
+
- lib/awspec/type/vpc.rb
|
144
|
+
- lib/awspec/version.rb
|
145
|
+
homepage: https://github.com/k1LoW/awspec
|
146
|
+
licenses:
|
147
|
+
- MIT
|
148
|
+
metadata: {}
|
149
|
+
post_install_message:
|
150
|
+
rdoc_options: []
|
151
|
+
require_paths:
|
152
|
+
- lib
|
153
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
154
|
+
requirements:
|
155
|
+
- - ">="
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
158
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
|
+
requirements:
|
160
|
+
- - ">="
|
161
|
+
- !ruby/object:Gem::Version
|
162
|
+
version: '0'
|
163
|
+
requirements: []
|
164
|
+
rubyforge_project:
|
165
|
+
rubygems_version: 2.2.2
|
166
|
+
signing_key:
|
167
|
+
specification_version: 4
|
168
|
+
summary: RSpec tests for your AWS resources.
|
169
|
+
test_files: []
|