cloudspec 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YWE4NGM4MzQ1OGIzMTA4MWMyMWMwMzMxYmJlOTFmM2RjNzMzNDBiYQ==
5
+ data.tar.gz: !binary |-
6
+ NWFlMThjZjAxMDExOTNjZDkyNTEyZTQwODM0ZjM4ZTE2NGJlNjFkNQ==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ M2JmNzdlN2ZhNWE5NmJmNDQxMTgyMjVmMmQyZjQ1MDA1N2EwZDU4NWZjMjNi
10
+ MmRhZTBlMjE5NWZhZTJiMjk3ZmU4ODAxOTAzNDljMzNlYzFiMTUxMjRhYjE1
11
+ M2IzMjQ3NmFkM2RlMmM5YzZhNzVlYjY5MmM1MWU4ODZkZWFkZDk=
12
+ data.tar.gz: !binary |-
13
+ YzE4MzQxZmUwOGZhYzVhNDJmMGM4NDg3OTc4ODFmZTk3Y2UwNjRjOGUyMWQx
14
+ MmQ1MTZhNmYxNmJhNTk2MjM0ZjkwZTdkNmQ4MzYwOTc3ZDgzYzlhZjQ0NWM2
15
+ OWM0MTM5YTBiNThiNzNmMmVhNDVjYTQ2YTY2ZGY1ZWU2MzE2Yjk=
data/.gitignore ADDED
@@ -0,0 +1,24 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ *.bundle
19
+ *.so
20
+ *.o
21
+ *.a
22
+ mkmf.log
23
+ .DS_Store
24
+ *.swp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ Metrics/LineLength:
3
+ Max: 150
4
+
5
+ AllCops:
6
+ Exclude:
7
+ - '*.gemspec'
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ cloudspec
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ ruby-2.2.4
data/.travis.yml ADDED
@@ -0,0 +1,11 @@
1
+ language: ruby
2
+ sudo: false
3
+ rvm:
4
+ - 2.2.4
5
+ script: bundle exec rake ci:build
6
+ deploy:
7
+ provider: rubygems
8
+ api_key:
9
+ secure: d0cXjiVXKoRIpjKkXOGpVmil1XZkoZHRWQ+mpLwBYwxsyXppHjO/9qVp1Br1qocXRN/IFTc/Q27Hq5PDLLy0UkVKUixXQ+Qbq6GhByHBuC2Y6gxO66ChrntxX4cbw3rHc42XR/LORYB4jjIPxZY5lQ6WjNGa08i6G3LeMfmMfCM=
10
+ on:
11
+ tags: true
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+ ruby '2.2.4'
3
+
4
+ # Specify your gem's dependencies in cloudspec.gemspec
5
+ gemspec
data/LICENSE.md ADDED
@@ -0,0 +1,24 @@
1
+ CloudSpec is distributed under the following license:
2
+ ----------------------------------------------------
3
+
4
+ Copyright (c) 2014 Lookout, Inc.
5
+ https://www.lookout.com/about/contact
6
+
7
+ Permission is hereby granted, free of charge, to any person obtaining
8
+ a copy of this software and associated documentation files (the
9
+ "Software"), to deal in the Software without restriction, including
10
+ without limitation the rights to use, copy, modify, merge, publish,
11
+ distribute, sublicense, and/or sell copies of the Software, and to
12
+ permit persons to whom the Software is furnished to do so, subject to
13
+ the following conditions:
14
+
15
+ The above copyright notice and this permission notice shall be
16
+ included in all copies or substantial portions of the Software.
17
+
18
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,30 @@
1
+ # CloudSpec
2
+ [![Build Status](https://travis-ci.org/AngryEgret/cloudspec.svg?branch=master)](https://travis-ci.org/AngryEgret/cloudspec)
3
+
4
+ TODO: Write a gem description
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ gem 'cloudspec'
11
+
12
+ And then execute:
13
+
14
+ $ bundle
15
+
16
+ Or install it yourself as:
17
+
18
+ $ gem install cloudspec
19
+
20
+ ## Usage
21
+
22
+ TODO: Write usage instructions here
23
+
24
+ ## Contributing
25
+
26
+ 1. Fork it ( https://github.com/[my-github-username]/cloudspec/fork )
27
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
28
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
29
+ 4. Push to the branch (`git push origin my-new-feature`)
30
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,52 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake'
3
+ require 'rubocop/rake_task'
4
+ require 'rspec/core/rake_task'
5
+ require 'cucumber/rake/task'
6
+ require 'cucumber'
7
+
8
+ desc 'Ensures we keep up 100% YARD coverage'
9
+ task :yard_coverage do
10
+ coverage_stats = `yard stats --list-undoc 2>&1`
11
+ puts coverage_stats
12
+
13
+ yard_regexp = /^\s*(.*)% documented/
14
+ percent = coverage_stats.scan(yard_regexp).first.first.to_f
15
+ minimum_coverage = 0.0
16
+
17
+ if percent < minimum_coverage
18
+ fail 'Documentation coverage is less than #{minimum_coverage}%'
19
+ else
20
+ puts "\nNice work! Documentation coverage above #{minimum_coverage}%!"
21
+ end
22
+ end
23
+
24
+ desc 'Checks the spec coverage and fails if it is less than 100%'
25
+ task :check_code_coverage do
26
+ percent = File.read('./coverage/coverage_percent.txt').to_f
27
+ minimum_coverage = 0.0
28
+ if percent < minimum_coverage
29
+ abort "Spec coverage was not high enough: #{percent.round(2)}% < #{minimum_coverage}%"
30
+ else
31
+ puts "Nice job! Spec coverage is still above #{minimum_coverage}%"
32
+ end
33
+ end
34
+
35
+ Cucumber::Rake::Task.new(:features) do |t|
36
+ t.cucumber_opts = 'features --format progress'
37
+ end
38
+
39
+ RuboCop::RakeTask.new(:rubocop) do |task|
40
+ task.fail_on_error = false
41
+ end
42
+
43
+ namespace :ci do
44
+ desc 'Sets things up for a ci build'
45
+
46
+ RSpec::Core::RakeTask.new(:spec) do |t|
47
+ t.verbose = true
48
+ end
49
+
50
+ desc 'Run a ci build'
51
+ task build: [:spec, :features, :yard_coverage, :check_code_coverage, :rubocop]
52
+ end
data/bin/cloudspec ADDED
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
4
+
5
+ require 'cloudspec'
6
+ require 'cloudspec/cli'
7
+
8
+ CloudSpec::CLI.start
9
+ exit 0
data/cloudspec.gemspec ADDED
@@ -0,0 +1,33 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cloudspec/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cloudspec'
8
+ spec.version = CloudSpec::VERSION
9
+ spec.authors = ['Ryan Greget']
10
+ spec.email = ['rgreget@gmail.com']
11
+ spec.summary = %q{Simple tool to harvest dead weight in AWS}
12
+ spec.description = spec.summary
13
+ spec.homepage = 'https://github.com/AngryEgret/cloudspec'
14
+ spec.license = ''
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency 'thor', '~> 0.19'
22
+ spec.add_dependency 'fog', '~> 1.37'
23
+ spec.add_dependency 'rspec-expectations', '~> 3.4'
24
+
25
+ spec.add_development_dependency 'bundler', '~> 1.11'
26
+ spec.add_development_dependency 'rake'
27
+ spec.add_development_dependency 'pry'
28
+ spec.add_development_dependency 'aruba'
29
+ spec.add_development_dependency 'rspec'
30
+ spec.add_development_dependency 'simplecov'
31
+ spec.add_development_dependency 'yard'
32
+ spec.add_development_dependency 'rubocop'
33
+ end
@@ -0,0 +1,9 @@
1
+ ---
2
+ aws:
3
+ prod:
4
+ access_key: abc123
5
+ secret_key: xyz789
6
+ dev:
7
+ access_key: def456
8
+ secret_key: uvw456
9
+
@@ -0,0 +1,36 @@
1
+ Feature: Harvest instances
2
+ In order to harvest deviant instances from the command line
3
+ A user should provide the incidents command and path to the creditials
4
+
5
+ Scenario: Correctly run the instances command
6
+ Given I run `cloudspec init --path=/tmp`
7
+ When I run `cloudspec amazon instances --yaml=/tmp/config/template.yml --rules=/tmp/rules --mock`
8
+ Then the exit status should be 0
9
+ And the output should contain "INFO -- : Beginning instance harvest ..."
10
+ And the output should contain "INFO -- : Instance harvest complete."
11
+
12
+ Given I run `cloudspec init --path=/tmp`
13
+ When I run `cloudspec amazon instances -y /tmp/config/template.yml -r /tmp/rules --mock`
14
+ Then the exit status should be 0
15
+ And the output should contain "INFO -- : Beginning instance harvest ..."
16
+ And the output should contain "INFO -- : Instance harvest complete."
17
+
18
+ Scenario: Run the instances command with no parameters
19
+ Given I run `cloudspec init --path=/tmp`
20
+ When I run `cloudspec amazon instances --mock`
21
+ Then the exit status should be 0
22
+ And the output should contain "No value provided for required options"
23
+ And the output should contain "--yaml"
24
+ And the output should contain "--rules"
25
+
26
+ Scenario: Run the instances command with a missing credentials file
27
+ Given I run `cloudspec init --path=/tmp`
28
+ When I run `cloudspec amazon instances --yaml=/fail --rules=/tmp/rules --mock`
29
+ Then the exit status should be 1
30
+ And the output should contain "Could not find YAML config file '/fail' (CloudSpec::FileNotFoundError)"
31
+
32
+ Scenario: Run the instances command with a missing rules path
33
+ Given I run `cloudspec init --path=/tmp`
34
+ When I run `cloudspec amazon instances --yaml=/tmp/config/template.yml --rules=/fail --mock`
35
+ Then the exit status should be 1
36
+ And the output should contain "Could not find rules path '/fail' (CloudSpec::FileNotFoundError)"
@@ -0,0 +1,2 @@
1
+ require 'aruba/cucumber'
2
+ require 'pry'
@@ -0,0 +1,67 @@
1
+ require 'fog'
2
+ require 'rspec/expectations'
3
+
4
+ module CloudSpec
5
+ module AMZN
6
+ class Base
7
+ include RSpec::Matchers
8
+
9
+ def initialize
10
+ mock?
11
+ super
12
+ end
13
+
14
+ def harvest
15
+ load_rules
16
+ self.class.include_rules
17
+
18
+ CloudSpec.log.warn 'harvesting ...'
19
+
20
+ accounts = CloudSpec.config['aws']
21
+
22
+ accounts.each do |account_name, credentials|
23
+ process_account(account_name, credentials)
24
+ end
25
+ end
26
+
27
+ def load_rules
28
+ CloudSpec.log.debug 'loading rules ...'
29
+
30
+ rules_path = File.expand_path(CloudSpec.options[:rules])
31
+ Dir["#{rules_path}/amzn/**/*.rb"].each do |file|
32
+ require file
33
+ end
34
+ end
35
+
36
+ def process_account(account_name, credentials = { 'access_key' => nil, 'secret_key' => nil })
37
+ CloudSpec.log.debug "processing account #{account_name} ..."
38
+ regions(credentials).each do |region|
39
+ objects(credentials, region).each do |object|
40
+ evaluate_object(account_name, region, object)
41
+ end
42
+ end
43
+ end
44
+
45
+ def regions(credentials)
46
+ CloudSpec.log.debug 'getting regions ...'
47
+ aws_client = compute_client(credentials)
48
+ aws_client.describe_regions.body['regionInfo'].map { |region| region['regionName'] }
49
+ end
50
+
51
+ def compute_client(credentials = { 'access_key' => '', 'secret_key' => '' }, region = nil)
52
+ CloudSpec.log.debug 'creating compute client ...'
53
+ Fog::Compute.new(
54
+ provider: 'AWS',
55
+ aws_access_key_id: credentials['access_key'],
56
+ aws_secret_access_key: credentials['secret_key'],
57
+ region: region
58
+ )
59
+ end
60
+
61
+ def mock?
62
+ CloudSpec.log.debug 'Checking Mocking settings ...'
63
+ Fog.mock! if CloudSpec.options[:mock]
64
+ end
65
+ end
66
+ end
67
+ end
File without changes
@@ -0,0 +1,25 @@
1
+ module CloudSpec
2
+ module AMZN
3
+ class Instances < Base
4
+ def self.include_rules
5
+ CloudSpec.log.debug 'including rules ...'
6
+ include ::AMZN::InstanceRules
7
+ end
8
+
9
+ def objects(credentials, region)
10
+ CloudSpec.log.debug 'getting instances ...'
11
+ aws_client = compute_client(credentials, region)
12
+ aws_client.servers
13
+ end
14
+
15
+ def evaluate_object(account_name, region, object)
16
+ CloudSpec.log.debug "Evaluating object #{object.id} ..."
17
+ begin
18
+ evaluate(object)
19
+ rescue RSpec::Expectations::ExpectationNotMetError => e
20
+ CloudSpec.log.error "[#{account_name}][#{region}][#{object.id}] - " + e.to_s
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,25 @@
1
+ module CloudSpec
2
+ module AMZN
3
+ class SecurityGroups < Base
4
+ def self.include_rules
5
+ CloudSpec.log.debug 'including rules ...'
6
+ include AMZN::SecurityGroupRules
7
+ end
8
+
9
+ def objects(credentials, region)
10
+ CloudSpec.log.debug 'getting groups ...'
11
+ aws_client = compute_client(credentials, region)
12
+ aws_client.security_groups
13
+ end
14
+
15
+ def evaluate_object(account_name, region, object)
16
+ CloudSpec.log.debug "Evaluating object #{object.group_id} ..."
17
+ begin
18
+ evaluate(object)
19
+ rescue RSpec::Expectations::ExpectationNotMetError => e
20
+ CloudSpec.log.error "[#{account_name}][#{region}][#{object.group_id}] - " + e.to_s
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
File without changes
@@ -0,0 +1,83 @@
1
+ require 'thor'
2
+
3
+ module CloudSpec
4
+ class AMZN_CLI < Thor
5
+ namespace :amazon
6
+
7
+ def self.shared_options
8
+ method_option :mock, type: :boolean, desc: 'Mock all cloud calls', aliases: '-m'
9
+ method_option :dry_run, type: :boolean, desc: 'Non-destructive run', aliases: '-d'
10
+ method_option :yaml, type: :string, required: true, aliases: '-y', desc: 'The path to the clould credentials yaml file'
11
+ method_option :rules, type: :string, required: true, aliases: '-r', desc: 'The path to the rules'
12
+ end
13
+
14
+ no_tasks do
15
+ def validate
16
+ CloudSpec.options(options)
17
+
18
+ CloudSpec.options[:verbose] ? CloudSpec.log.level = Logger::DEBUG : CloudSpec.log.level = Logger::INFO
19
+
20
+ fail CloudSpec::FileNotFoundError, "Could not find YAML config file '#{CloudSpec.options[:yaml]}'" unless File.exist? CloudSpec.options[:yaml]
21
+ fail CloudSpec::FileNotFoundError, "Could not find rules path '#{CloudSpec.options[:rules]}'" unless Dir.exist? CloudSpec.options[:rules]
22
+ end
23
+ end
24
+
25
+ desc 'all', 'Harvest all AWS objects'
26
+ shared_options
27
+ def all
28
+ validate
29
+
30
+ invoke :instances
31
+ invoke :groups
32
+ rescue => e
33
+ CloudSpec.log.error e.to_s
34
+ exit 1
35
+ end
36
+
37
+ desc 'instances', 'Harvest AWS Instances'
38
+ shared_options
39
+ def instances
40
+ validate
41
+
42
+ instances = CloudSpec::AMZN::Instances.new
43
+ CloudSpec.log.info 'Beginning instance harvest ...'
44
+ instances.harvest
45
+ CloudSpec.log.info 'Instance harvest complete.'
46
+ rescue => e
47
+ CloudSpec.log.error e.to_s
48
+ exit 1
49
+ end
50
+
51
+ desc 'groups', 'Harvest AWS Security Groups'
52
+ shared_options
53
+ def groups
54
+ validate
55
+
56
+ groups = CloudSpec::AMZN::SecurityGroups.new
57
+ CloudSpec.log.info 'Beginning group harvest ...'
58
+ groups.harvest
59
+ CloudSpec.log.info 'Group harvest complete.'
60
+ rescue => e
61
+ CloudSpec.log.error e.to_s
62
+ exit 1
63
+ end
64
+ end
65
+
66
+ class CLI < Thor
67
+ class_option :verbose, type: :boolean, desc: 'Enable verbose logging', aliases: '-v'
68
+
69
+ desc 'init', 'Initialize a rules directory and credentials file'
70
+ method_option :path, type: :string, required: true, aliases: '-p', desc: 'The path to create scaffolding within'
71
+ def init
72
+ fail CloudSpec::FileNotFoundError, "Could not find initialization path '#{options[:path]}'" unless Dir.exist? options[:path]
73
+
74
+ CloudSpec.build_scaffold(options[:path])
75
+ rescue => e
76
+ CloudSpec.log.error e.to_s
77
+ exit 1
78
+ end
79
+
80
+ desc 'amazon SUBCOMMAND ...ARGS', 'Evaluate Amazon Cloud Objects'
81
+ subcommand 'amazon', CloudSpec::AMZN_CLI
82
+ end
83
+ end
@@ -0,0 +1,3 @@
1
+ module CloudSpec
2
+ VERSION = '0.0.2'.freeze
3
+ end
data/lib/cloudspec.rb ADDED
@@ -0,0 +1,34 @@
1
+ require 'logger'
2
+ require 'yaml'
3
+
4
+ require 'cloudspec/version'
5
+
6
+ require 'cloudspec/amzn/base'
7
+ require 'cloudspec/amzn/instances'
8
+ require 'cloudspec/amzn/security_groups'
9
+
10
+ module CloudSpec
11
+ InvalidCLIOptionsError = Class.new(Exception)
12
+ FileNotFoundError = Class.new(Exception)
13
+
14
+ def self.log
15
+ @logger ||= Logger.new(STDOUT)
16
+ end
17
+
18
+ def self.config
19
+ @config ||= YAML.load_file(CloudSpec.options[:yaml])
20
+ end
21
+
22
+ def self.options(options = nil)
23
+ @options ||= options
24
+ end
25
+
26
+ def self.root
27
+ File.expand_path '../..', __FILE__
28
+ end
29
+
30
+ def self.build_scaffold(path)
31
+ FileUtils.cp_r File.join(root, './config'), path
32
+ FileUtils.cp_r File.join(root, './rules'), path
33
+ end
34
+ end
@@ -0,0 +1,7 @@
1
+ module AMZN
2
+ module BucketRules
3
+ def evaluate(bucket)
4
+ # expect(bucket.tags['Name']).to exist
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ module AMZN
2
+ module InstanceRules
3
+ # <Fog::Compute::AWS::Server
4
+ # id="i-12345678",
5
+ # ami_launch_index=0,
6
+ # associate_public_ip=nil,
7
+ # availability_zone="us-east-1a",
8
+ # block_device_mapping=[{"deviceName"=>"/dev/sda1", "volumeId"=>"vol-12345678", "status"=>"attached", "attachTime"=>2014-07-10 21:44:24 UTC, "deleteOnTermination"=>false}],
9
+ # network_interfaces=[],
10
+ # client_token="ckgps1234567890123",
11
+ # dns_name="ec2-11-22-33-44.compute-1.amazonaws.com",
12
+ # ebs_optimized=false,
13
+ # groups=["default", "other"],
14
+ # flavor_id="m4.large",
15
+ # hypervisor="xen",
16
+ # iam_instance_profile={},
17
+ # image_id="ami-abcd1234",
18
+ # kernel_id="aki-abcd1234",
19
+ # key_name="default",
20
+ # created_at=2014-07-10 21:44:40 UTC,
21
+ # lifecycle=nil,
22
+ # monitoring=false,
23
+ # placement_group=nil,
24
+ # platform=nil,
25
+ # product_codes=[],
26
+ # private_dns_name="ip-11-22-33-44.ec2.internal",
27
+ # private_ip_address="11.22.33.44",
28
+ # public_ip_address="22.33.44.55",
29
+ # ramdisk_id=nil,
30
+ # reason=nil,
31
+ # requester_id=nil,
32
+ # root_device_name=nil,
33
+ # root_device_type="ebs",
34
+ # security_group_ids=["sg-abcd1234", "sg-1234abcd"],
35
+ # source_dest_check=nil,
36
+ # spot_instance_request_id=nil,
37
+ # state="running",
38
+ # state_reason={},
39
+ # subnet_id=nil,
40
+ # tenancy="default",
41
+ # tags={"Name"=>"default"},
42
+ # user_data=nil,
43
+ # virtualization_type="paravirtual",
44
+ # vpc_id=nil
45
+ # >
46
+ def evaluate(instance)
47
+ expect(instance.tags).to have_key('Name'), 'expected instance.tags to have key "Name"'
48
+ expect(instance.flavor_id).to eq('m3.large'), "expected instance.flavor_id to equal 'm3.large', got #{instance.flavor_id}"
49
+ expect(instance.vpc_id).to_not be_nil, 'expected instance to belong to VPC'
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,24 @@
1
+ module AMZN
2
+ module SecurityGroupRules
3
+ # <Fog::Compute::AWS::SecurityGroup
4
+ # name="default",
5
+ # description="default security group",
6
+ # group_id="sg-12345678",
7
+ # ip_permissions=[{"groups"=>[], "ipRanges"=>[{"cidrIp"=>"0.0.0.0/0"}], "ipProtocol"=>"tcp", "fromPort"=>22, "toPort"=>22}],
8
+ # ip_permissions_egress=[],
9
+ # owner_id="123456789012",
10
+ # vpc_id=nil,
11
+ # tags={}
12
+ # >
13
+ def evaluate(group)
14
+ group.ip_permissions.each do |ip_permission|
15
+ ip_permission['ipRanges'].each do |range|
16
+ if range.value? '0.0.0.0/0'
17
+ expect(ip_permission['fromPort']).to eq(80).or eq(443)
18
+ end
19
+ end
20
+ end
21
+ expect(group.vpc_id).to_not be_nil, 'expected group to belong to VPC'
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,7 @@
1
+ module AMZN
2
+ module SubnetRules
3
+ def evaluate(subnet)
4
+ # expect(subnet.tags['Name']).to exist
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ describe CloudSpec do
2
+ pending
3
+ end
@@ -0,0 +1,75 @@
1
+ describe CloudSpec::AMZN::Base do
2
+ let(:base) { CloudSpec::AMZN::Base.new }
3
+ let(:credentials) { { 'access_key' => '', 'secret_key' => '' } }
4
+
5
+ before(:each) do
6
+ allow(CloudSpec).to receive_message_chain(:log, :debug)
7
+ allow(CloudSpec).to receive(:options) {
8
+ {
9
+ mock: true,
10
+ verbose: false,
11
+ rules: './rules'
12
+ }
13
+ }
14
+ end
15
+
16
+ describe '.initialize' do
17
+ it 'should call the mock? method' do
18
+ expect_any_instance_of(CloudSpec::AMZN::Base).to receive(:mock?)
19
+
20
+ CloudSpec::AMZN::Base.new
21
+ end
22
+ end
23
+
24
+ describe '.process_account' do
25
+ it 'should not raise error' do
26
+ expect_any_instance_of(CloudSpec::AMZN::Base).to receive(:objects).twice.and_return([])
27
+ expect { base.process_account('dev', credentials) }.to_not raise_error
28
+ end
29
+ end
30
+
31
+ describe '.load_rules' do
32
+ it 'should not raise error' do
33
+ expect { base.load_rules }.to_not raise_error
34
+ end
35
+ end
36
+
37
+ describe '.regions' do
38
+ it 'should return an array of regions' do
39
+ expect(base.regions(credentials)).to eq ['eu-west-1', 'us-east-1']
40
+ end
41
+ end
42
+
43
+ describe '.compute_client' do
44
+ it 'should return a Fog::Compute object' do
45
+ expect(base.compute_client(credentials)).to be_an_instance_of(Fog::Compute::AWS::Mock)
46
+ end
47
+
48
+ it 'should be able to consume a region argument' do
49
+ expect(base.compute_client(credentials, 'eu-west-1').region).to eq('eu-west-1')
50
+ expect(base.compute_client(credentials, 'us-east-1').region).to eq('us-east-1')
51
+ end
52
+ end
53
+
54
+ describe '.mock?' do
55
+ it 'should call Fog.mock! if the mock option is set' do
56
+ expect(Fog).to receive(:mock!).at_least(:twice)
57
+
58
+ base.mock?
59
+ end
60
+
61
+ it 'should not call Fog.mock! if the mock option is unset' do
62
+ allow(CloudSpec).to receive(:options) {
63
+ {
64
+ mock: false,
65
+ verbose: false,
66
+ rules: './rules'
67
+ }
68
+ }
69
+
70
+ expect(Fog).to_not receive(:mock!)
71
+
72
+ base.mock?
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,51 @@
1
+ describe CloudSpec::AMZN::Instances do
2
+ let(:instances) { CloudSpec::AMZN::Instances.new }
3
+ let(:credentials) { { 'access_key' => '', 'secret_key' => '' } }
4
+
5
+ before(:each) do
6
+ allow(CloudSpec).to receive_message_chain(:log, :debug)
7
+ allow(CloudSpec).to receive_message_chain(:log, :warn)
8
+ allow(CloudSpec).to receive(:options) {
9
+ {
10
+ mock: true,
11
+ dry_run: true,
12
+ yaml: 'config/template.yml',
13
+ rules: './rules/',
14
+ verbose: false
15
+ }
16
+ }
17
+ end
18
+
19
+ describe '.harvest' do
20
+ it 'should load the rules' do
21
+ expect(instances).to receive(:load_rules)
22
+ expect(CloudSpec::AMZN::Instances).to receive(:include_rules)
23
+ expect(instances).to receive(:process_account).at_least(:once)
24
+
25
+ instances.harvest
26
+ end
27
+ end
28
+
29
+ describe '.include_rules' do
30
+ it 'should implement the evaluate method from InstanceRules' do
31
+ instances.load_rules
32
+ CloudSpec::AMZN::Instances.include_rules
33
+
34
+ expect(instances).to respond_to :evaluate
35
+ end
36
+ end
37
+
38
+ describe '.evaluate_instance' do
39
+ pending
40
+ end
41
+
42
+ describe '.instances' do
43
+ it 'should return an Array of instances' do
44
+ expect(instances.objects(credentials, 'us-east-1')).to be_an_instance_of(Fog::Compute::AWS::Servers)
45
+ end
46
+ end
47
+
48
+ describe '.process_account' do
49
+ pending
50
+ end
51
+ end
File without changes
@@ -0,0 +1,34 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # The generated `.rspec` file contains `--require spec_helper` which will cause this
4
+ # file to always be loaded, without a need to explicitly require it in any files.
5
+ #
6
+ # Given that it is always loaded, you are encouraged to keep this file as
7
+ # light-weight as possible. Requiring heavyweight dependencies from this file
8
+ # will add to the boot time of your test suite on EVERY test run, even for an
9
+ # individual file that may not need all of that loaded. Instead, make a
10
+ # separate helper file that requires this one and then use it only in the specs
11
+ # that actually need it.
12
+ #
13
+ # The `.rspec` file also contains a few flags that are not defaults but that
14
+ # users commonly want.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+
18
+ require 'simplecov'
19
+ require 'cloudspec'
20
+
21
+ Fog.mock!
22
+
23
+ SimpleCov.start
24
+
25
+ SimpleCov.at_exit do
26
+ File.open(File.join(SimpleCov.coverage_path, 'coverage_percent.txt'), 'w') do |f|
27
+ f.write SimpleCov.result.covered_percent
28
+ end
29
+ SimpleCov.result.format!
30
+ end
31
+
32
+ RSpec.configure do |config|
33
+ config.order = :random
34
+ end
metadata ADDED
@@ -0,0 +1,238 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudspec
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Ryan Greget
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: thor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: '0.19'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: '0.19'
27
+ - !ruby/object:Gem::Dependency
28
+ name: fog
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '1.37'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '1.37'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec-expectations
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.4'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.4'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: '1.11'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ~>
67
+ - !ruby/object:Gem::Version
68
+ version: '1.11'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ! '>='
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: aruba
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
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ! '>='
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ! '>='
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: yard
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ! '>='
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ! '>='
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ! '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ! '>='
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: Simple tool to harvest dead weight in AWS
168
+ email:
169
+ - rgreget@gmail.com
170
+ executables:
171
+ - cloudspec
172
+ extensions: []
173
+ extra_rdoc_files: []
174
+ files:
175
+ - .gitignore
176
+ - .rspec
177
+ - .rubocop.yml
178
+ - .ruby-gemset
179
+ - .ruby-version
180
+ - .travis.yml
181
+ - Gemfile
182
+ - LICENSE.md
183
+ - README.md
184
+ - Rakefile
185
+ - bin/cloudspec
186
+ - cloudspec.gemspec
187
+ - config/template.yml
188
+ - features/instances.feature
189
+ - features/support/env.rb
190
+ - lib/cloudspec.rb
191
+ - lib/cloudspec/amzn/base.rb
192
+ - lib/cloudspec/amzn/buckets.rb
193
+ - lib/cloudspec/amzn/instances.rb
194
+ - lib/cloudspec/amzn/security_groups.rb
195
+ - lib/cloudspec/amzn/subnets.rb
196
+ - lib/cloudspec/cli.rb
197
+ - lib/cloudspec/version.rb
198
+ - rules/amzn/buckets.rb
199
+ - rules/amzn/instances.rb
200
+ - rules/amzn/security_groups.rb
201
+ - rules/amzn/subnets.rb
202
+ - spec/cloudspec_spec.rb
203
+ - spec/lib/amzn/base_spec.rb
204
+ - spec/lib/amzn/instances_spec.rb
205
+ - spec/lib/cli_spec.rb
206
+ - spec/spec_helper.rb
207
+ homepage: https://github.com/AngryEgret/cloudspec
208
+ licenses:
209
+ - ''
210
+ metadata: {}
211
+ post_install_message:
212
+ rdoc_options: []
213
+ require_paths:
214
+ - lib
215
+ required_ruby_version: !ruby/object:Gem::Requirement
216
+ requirements:
217
+ - - ! '>='
218
+ - !ruby/object:Gem::Version
219
+ version: '0'
220
+ required_rubygems_version: !ruby/object:Gem::Requirement
221
+ requirements:
222
+ - - ! '>='
223
+ - !ruby/object:Gem::Version
224
+ version: '0'
225
+ requirements: []
226
+ rubyforge_project:
227
+ rubygems_version: 2.4.5
228
+ signing_key:
229
+ specification_version: 4
230
+ summary: Simple tool to harvest dead weight in AWS
231
+ test_files:
232
+ - features/instances.feature
233
+ - features/support/env.rb
234
+ - spec/cloudspec_spec.rb
235
+ - spec/lib/amzn/base_spec.rb
236
+ - spec/lib/amzn/instances_spec.rb
237
+ - spec/lib/cli_spec.rb
238
+ - spec/spec_helper.rb