cloudspec 0.0.2

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 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