outliers 0.0.0 → 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.
Files changed (78) hide show
  1. checksums.yaml +7 -0
  2. data/.ruby-gemset +1 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +5 -0
  5. data/CHANGELOG.md +3 -0
  6. data/LICENSE.txt +10 -19
  7. data/README.md +175 -8
  8. data/Rakefile +7 -0
  9. data/bin/outliers +6 -0
  10. data/lib/outliers/cli/evaluate.rb +115 -0
  11. data/lib/outliers/cli/process.rb +56 -0
  12. data/lib/outliers/cli/providers.rb +29 -0
  13. data/lib/outliers/cli/resources.rb +57 -0
  14. data/lib/outliers/cli.rb +78 -0
  15. data/lib/outliers/collection.rb +124 -0
  16. data/lib/outliers/credentials.rb +28 -0
  17. data/lib/outliers/evaluation.rb +85 -0
  18. data/lib/outliers/exceptions.rb +40 -0
  19. data/lib/outliers/mixins.rb +27 -0
  20. data/lib/outliers/provider.rb +32 -0
  21. data/lib/outliers/providers/aws/base.rb +33 -0
  22. data/lib/outliers/providers/aws/cloud_formation.rb +20 -0
  23. data/lib/outliers/providers/aws/ec2.rb +20 -0
  24. data/lib/outliers/providers/aws/elb.rb +20 -0
  25. data/lib/outliers/providers/aws/iam.rb +20 -0
  26. data/lib/outliers/providers/aws/rds.rb +20 -0
  27. data/lib/outliers/providers/aws/s3.rb +20 -0
  28. data/lib/outliers/providers/aws/sqs.rb +20 -0
  29. data/lib/outliers/providers/aws.rb +9 -0
  30. data/lib/outliers/providers/github.rb +23 -0
  31. data/lib/outliers/providers.rb +19 -0
  32. data/lib/outliers/resource.rb +34 -0
  33. data/lib/outliers/resources/aws/cloud_formation/stack.rb +10 -0
  34. data/lib/outliers/resources/aws/cloud_formation/stack_collection.rb +15 -0
  35. data/lib/outliers/resources/aws/ec2/instance.rb +75 -0
  36. data/lib/outliers/resources/aws/ec2/instance_collection.rb +15 -0
  37. data/lib/outliers/resources/aws/ec2/security_group.rb +28 -0
  38. data/lib/outliers/resources/aws/ec2/security_group_collection.rb +15 -0
  39. data/lib/outliers/resources/aws/elb/load_balancer.rb +51 -0
  40. data/lib/outliers/resources/aws/elb/load_balancer_collection.rb +15 -0
  41. data/lib/outliers/resources/aws/iam/user.rb +40 -0
  42. data/lib/outliers/resources/aws/iam/user_collection.rb +15 -0
  43. data/lib/outliers/resources/aws/rds/db_instance.rb +35 -0
  44. data/lib/outliers/resources/aws/rds/db_instance_collection.rb +15 -0
  45. data/lib/outliers/resources/aws/rds/db_snapshot.rb +13 -0
  46. data/lib/outliers/resources/aws/rds/db_snapshot_collection.rb +15 -0
  47. data/lib/outliers/resources/aws/s3/bucket.rb +73 -0
  48. data/lib/outliers/resources/aws/s3/bucket_collection.rb +18 -0
  49. data/lib/outliers/resources/aws/sqs/queue.rb +13 -0
  50. data/lib/outliers/resources/aws/sqs/queue_collection.rb +15 -0
  51. data/lib/outliers/resources/aws.rb +18 -0
  52. data/lib/outliers/resources/github/repo.rb +24 -0
  53. data/lib/outliers/resources/github/repo_collection.rb +13 -0
  54. data/lib/outliers/resources/github.rb +2 -0
  55. data/lib/outliers/resources.rb +12 -0
  56. data/lib/outliers/result.rb +24 -0
  57. data/lib/outliers/run.rb +40 -0
  58. data/lib/outliers/verifications/shared.rb +31 -0
  59. data/lib/outliers/verifications.rb +1 -0
  60. data/lib/outliers/version.rb +1 -1
  61. data/lib/outliers.rb +24 -1
  62. data/outliers.gemspec +9 -5
  63. data/spec/collection_spec.rb +103 -0
  64. data/spec/credentials_spec.rb +42 -0
  65. data/spec/evaluation_spec.rb +96 -0
  66. data/spec/fixtures/credentials1.yml +5 -0
  67. data/spec/fixtures/credentials2.yml +5 -0
  68. data/spec/helpers/fixtures.rb +8 -0
  69. data/spec/mixins_spec.rb +33 -0
  70. data/spec/provider_spec.rb +35 -0
  71. data/spec/providers_spec.rb +18 -0
  72. data/spec/resource_spec.rb +19 -0
  73. data/spec/resources_spec.rb +15 -0
  74. data/spec/results_spec.rb +33 -0
  75. data/spec/run_spec.rb +56 -0
  76. data/spec/spec_helper.rb +21 -0
  77. data/spec/verifications/shared_spec.rb +35 -0
  78. metadata +145 -29
@@ -0,0 +1,124 @@
1
+ require 'enumerator'
2
+
3
+ module Outliers
4
+ class Collection
5
+
6
+ include Enumerable
7
+ include Outliers::Verifications::Shared
8
+
9
+ attr_reader :provider
10
+ attr_accessor :targets
11
+
12
+ def self.to_human
13
+ (self.to_s.split('::') - ['Outliers', 'Resources']).map { |p| p.underscore }.join('_').downcase.gsub(/_collection$/, '')
14
+ end
15
+
16
+ def self.verifications
17
+ Outliers::Verifications::Shared.verifications + self.resource_class.verifications
18
+ end
19
+
20
+ def self.resource_class
21
+ array = self.to_s.gsub(/Collection$/, '').split('::')
22
+ array.inject(Object) {|o,c| o.const_get c}
23
+ end
24
+
25
+ def initialize(provider)
26
+ @targets = []
27
+ @provider = provider
28
+ @logger = Outliers.logger
29
+ end
30
+
31
+ def each &block
32
+ all.each do |resource|
33
+ block.call resource
34
+ end
35
+ end
36
+
37
+ def exclude_by_key(exclusions)
38
+ @logger.info "Excluding the following resources: '#{exclusions.join(',')}'."
39
+ save = all.reject {|u| exclusions.include? u.public_send key}
40
+ @all = save
41
+ end
42
+
43
+ def verify(name, arguments={})
44
+ name << "?" unless name =~ /^.*\?$/
45
+
46
+ logger.debug "Verifying resources '#{all_by_key.join(', ')}'."
47
+
48
+ if collection_verification? name
49
+ send_verification self, name, arguments
50
+ else
51
+ send_resources_verification name, arguments
52
+ end
53
+ end
54
+
55
+ def all
56
+ @all ||= load_all
57
+ end
58
+
59
+ def key
60
+ resource_class.key
61
+ end
62
+
63
+ def resource_class
64
+ self.class.resource_class
65
+ end
66
+
67
+ private
68
+
69
+ def all_by_key
70
+ all.map {|r| r.public_send key}
71
+ end
72
+
73
+ def connect
74
+ @provider.connect
75
+ end
76
+
77
+ def logger
78
+ @logger
79
+ end
80
+
81
+ def collection_verification?(name)
82
+ self.public_methods.include? name.to_sym
83
+ end
84
+
85
+ def send_resources_verification(verification, arguments)
86
+ set_target_resources verification if targets.any?
87
+
88
+ results = map do |resource|
89
+ result = send_verification resource, verification, arguments
90
+ logger.debug "Verification of resource '#{resource.id}' #{result ? 'passed' : 'failed'}."
91
+ result
92
+ end
93
+ !results.include? false
94
+ end
95
+
96
+ def set_target_resources(verification)
97
+ logger.info "Verifying target '#{targets.join(', ')}'."
98
+
99
+ @all = all.select {|r| targets.include? r.id }
100
+
101
+ unless all.any?
102
+ raise Outliers::Exceptions::TargetNotFound.new "No '#{targets}' found."
103
+ end
104
+
105
+ @all
106
+ end
107
+
108
+ def send_verification(object, verification, arguments)
109
+ if object.method(verification).arity.zero?
110
+ if arguments.any?
111
+ raise Outliers::Exceptions::NoArgumentRequired.new "Verification '#{verification}' does not require an arguments."
112
+ end
113
+
114
+ object.public_send verification
115
+ else
116
+ if arguments.none?
117
+ raise Outliers::Exceptions::ArgumentRequired.new "Verification '#{verification}' requires arguments."
118
+ end
119
+ object.public_send verification, arguments
120
+ end
121
+ end
122
+
123
+ end
124
+ end
@@ -0,0 +1,28 @@
1
+ module Outliers
2
+ module Credentials
3
+ module_function
4
+
5
+ # To Do - Remove me once validated not needed
6
+ def load_from_config_folder
7
+ credentials = {}
8
+ files = Dir.entries(File.join(Outliers.config_path, 'credentials')) - ['.', '..']
9
+ files.each do |file|
10
+ contents = File.read File.join(Outliers.config_path, 'credentials', file)
11
+ YAML.load(contents).each_pair do |k,v|
12
+ credentials[k] = v
13
+ end
14
+ end
15
+ credentials
16
+ end
17
+
18
+ def load_from_file(file)
19
+ credentials = {}
20
+ contents = File.read file
21
+ YAML.load(contents).each_pair do |k,v|
22
+ credentials[k] = v
23
+ end
24
+ credentials
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,85 @@
1
+ module Outliers
2
+ class Evaluation
3
+
4
+ attr_reader :collection, :provider_name, :provider_name_array
5
+
6
+ def initialize(args)
7
+ @run = args[:run]
8
+ @name = args[:name]
9
+ end
10
+
11
+ def connect(name, options={})
12
+ @provider_name = merged_credentials(name, options).fetch 'provider'
13
+
14
+ logger.info "Connecting via '#{name}' to '#{@provider_name}'."
15
+ logger.info "Including connection options '#{options.map {|k,v| "#{k}=#{v}"}.join(',')}'." if options.any?
16
+
17
+ set_provider_name_array
18
+
19
+ @provider = Outliers::Provider.connect_to merged_credentials(name, options)
20
+ end
21
+
22
+ def resources(name, targets=[])
23
+ logger.info "Loading '#{name}' resource collection."
24
+ @collection = collection_object name
25
+
26
+ targets_array = Array(targets)
27
+
28
+ if targets_array.any?
29
+ logger.info "Verifying against '#{targets_array.join(', ')}' from '#{name}' collection."
30
+ collection.targets = targets_array
31
+ end
32
+ collection
33
+ end
34
+
35
+ def exclude(exclusions)
36
+ collection.exclude_by_key Array(exclusions)
37
+ end
38
+
39
+ def verify(verification, arguments={})
40
+ collection.load_all
41
+
42
+ r = collection.verify verification, arguments.keys_to_sym
43
+
44
+ result = Outliers::Result.new :description => @name, :passed => r
45
+
46
+ logger.info "Evaluation '#{result}'."
47
+
48
+ @run.results << result
49
+ end
50
+
51
+ private
52
+
53
+ def set_provider_name_array
54
+ begin
55
+ array = Outliers::Providers.name_map.fetch(provider_name).to_s.split('::')
56
+ @provider_name_array = array[2..array.size]
57
+ rescue KeyError
58
+ raise Outliers::Exceptions::UnknownProvider.new "Unkown provider '#{provider_name}'"
59
+ end
60
+ end
61
+
62
+ def collection_object(name)
63
+ collection_object = name.split('_').map {|c| c.capitalize}.join('') + 'Collection'
64
+ collection_array = ['Outliers', 'Resources'] + provider_name_array + [collection_object]
65
+ collection_array.inject(Object) {|o,c| o.const_get c}.new(@provider)
66
+ rescue NameError
67
+ raise Outliers::Exceptions::UnknownCollection.new "Unknown collection '#{name}'."
68
+ end
69
+
70
+ def credentials(name)
71
+ @run.credentials.fetch name
72
+ end
73
+
74
+ def merged_credentials(name, options)
75
+ credentials(name).merge! options.keys_to_s
76
+ credentials(name).merge :name => name
77
+ end
78
+
79
+ def logger
80
+ @logger ||= Outliers.logger
81
+ end
82
+
83
+ end
84
+ end
85
+
@@ -0,0 +1,40 @@
1
+ module Outliers
2
+ module Exceptions
3
+
4
+ class Base < RuntimeError
5
+ attr_accessor :message
6
+
7
+ def initialize(message="")
8
+ @message = message
9
+ end
10
+ end
11
+
12
+ class ArgumentRequired < Base
13
+ end
14
+
15
+ class NoArgumentRequired < Base
16
+ end
17
+
18
+ class UnknownCollection < Base
19
+ end
20
+
21
+ class UnknownCredentials < Base
22
+ end
23
+
24
+ class UnknownVerification < Base
25
+ end
26
+
27
+ class UnknownProvider < Base
28
+ end
29
+
30
+ class InvalidBucket < Base
31
+ end
32
+
33
+ class UnsupportedRegion < Base
34
+ end
35
+
36
+ class TargetNotFound < Base
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,27 @@
1
+ class Module
2
+ def all_the_modules
3
+ [self] + constants.map {|const| const_get(const) }
4
+ .select {|const| const.is_a? Module }
5
+ .flat_map {|const| const.all_the_modules }
6
+ end
7
+ end
8
+
9
+ class Hash
10
+ def keys_to_sym
11
+ Hash[self.map {|k, v| [k.to_sym, v] }]
12
+ end
13
+
14
+ def keys_to_s
15
+ Hash[self.map {|k, v| [k.to_s, v] }]
16
+ end
17
+ end
18
+
19
+ class String
20
+ def underscore
21
+ self.gsub(/::/, '/').
22
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
23
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
24
+ tr("-", "_").
25
+ downcase
26
+ end
27
+ end
@@ -0,0 +1,32 @@
1
+ module Outliers
2
+ class Provider
3
+
4
+ attr_reader :credentials
5
+
6
+ def self.connect_to(credentials)
7
+ provider = credentials.fetch 'provider'
8
+ Outliers::Providers.name_map.fetch(provider).new credentials
9
+ rescue KeyError
10
+ raise Outliers::Exceptions::UnknownProvider.new "Unkown provider '#{provider.join('_').downcase}'."
11
+ end
12
+
13
+ def self.to_human
14
+ (self.to_s.split('::') - ['Outliers', 'Providers']).map { |p| p.underscore }.join('_').downcase
15
+ end
16
+
17
+ def self.credential_arguments
18
+ {}
19
+ end
20
+
21
+ def initialize(credentials)
22
+ @credentials = credentials
23
+ @logger = Outliers.logger
24
+ settings credentials.keys_to_sym
25
+ end
26
+
27
+ def logger
28
+ @logger
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,33 @@
1
+ require "aws-sdk"
2
+
3
+ module Outliers
4
+ module Providers
5
+ module Aws
6
+ module Shared
7
+
8
+ def settings(args)
9
+ @access_key_id = args.fetch :access_key_id
10
+ @secret_access_key = args.fetch :secret_access_key
11
+ @region = args.fetch :region, 'us-east-1'
12
+ end
13
+
14
+ def config
15
+ { :access_key_id => @access_key_id,
16
+ :secret_access_key => @secret_access_key,
17
+ :region => @region }
18
+ end
19
+
20
+ module_function
21
+
22
+ def credential_arguments
23
+ {
24
+ 'access_key_id' => 'AWS Account Access Key',
25
+ 'secret_access_key' => 'AWS Account Secret Key',
26
+ 'region' => 'AWS Region (Default us-east-1)'
27
+ }
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,20 @@
1
+ module Outliers
2
+ module Providers
3
+ module Aws
4
+ class CloudFormation < Provider
5
+
6
+ include Shared
7
+
8
+ def self.credential_arguments
9
+ Shared.credential_arguments
10
+ end
11
+
12
+ def connect
13
+ logger.info "Connecting to region '#{@region}'." unless @cf
14
+ @cf ||= ::AWS::CloudFormation.new config
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Outliers
2
+ module Providers
3
+ module Aws
4
+ class Ec2 < Provider
5
+
6
+ include Shared
7
+
8
+ def self.credential_arguments
9
+ Shared.credential_arguments
10
+ end
11
+
12
+ def connect
13
+ logger.info "Connecting to region '#{@region}'." unless @ec2
14
+ @ec2 ||= ::AWS::EC2.new config
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Outliers
2
+ module Providers
3
+ module Aws
4
+ class Elb < Provider
5
+
6
+ include Shared
7
+
8
+ def self.credential_arguments
9
+ Shared.credential_arguments
10
+ end
11
+
12
+ def connect
13
+ logger.info "Connecting to region '#{@region}'." unless @elb
14
+ @elb ||= ::AWS::ELB.new config
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Outliers
2
+ module Providers
3
+ module Aws
4
+ class Iam < Provider
5
+
6
+ include Shared
7
+
8
+ def self.credential_arguments
9
+ Shared.credential_arguments
10
+ end
11
+
12
+ def connect
13
+ logger.info "Connecting to region '#{@region}'." unless @iam
14
+ @iam ||= ::AWS::IAM.new config
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Outliers
2
+ module Providers
3
+ module Aws
4
+ class Rds < Provider
5
+
6
+ include Shared
7
+
8
+ def self.credential_arguments
9
+ Shared.credential_arguments
10
+ end
11
+
12
+ def connect
13
+ logger.info "Connecting to region '#{@region}'." unless @rds
14
+ @rds ||= ::AWS::RDS.new config
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Outliers
2
+ module Providers
3
+ module Aws
4
+ class S3 < Provider
5
+
6
+ include Shared
7
+
8
+ def self.credential_arguments
9
+ Shared.credential_arguments
10
+ end
11
+
12
+ def connect
13
+ logger.info "Connecting to region '#{@region}'." unless @iam
14
+ @iam ||= ::AWS::S3.new config
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Outliers
2
+ module Providers
3
+ module Aws
4
+ class Sqs < Provider
5
+
6
+ include Shared
7
+
8
+ def self.credential_arguments
9
+ Shared.credential_arguments
10
+ end
11
+
12
+ def connect
13
+ logger.info "Connecting to region '#{@region}'." unless @sqs
14
+ @sqs ||= ::AWS::SQS.new config
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ require 'outliers/providers/aws/base'
2
+
3
+ require 'outliers/providers/aws/cloud_formation'
4
+ require 'outliers/providers/aws/ec2'
5
+ require 'outliers/providers/aws/elb'
6
+ require 'outliers/providers/aws/iam'
7
+ require 'outliers/providers/aws/rds'
8
+ require 'outliers/providers/aws/s3'
9
+ require 'outliers/providers/aws/sqs'
@@ -0,0 +1,23 @@
1
+ require "github_api"
2
+
3
+ module Outliers
4
+ module Providers
5
+ class Github < Provider
6
+
7
+ def settings(args)
8
+ @token = args[:token]
9
+ end
10
+
11
+ def connect
12
+ c = ::Github.new
13
+ c.oauth_token = @token if @token
14
+ c
15
+ end
16
+
17
+ def self.credential_arguments
18
+ { 'token' => 'Github API token.' }
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,19 @@
1
+ require 'outliers/providers/aws'
2
+ require 'outliers/providers/github'
3
+
4
+ module Outliers
5
+ module Providers
6
+ module_function
7
+
8
+ def all
9
+ all_the_modules.select{|m| m.is_a? Class}
10
+ end
11
+
12
+ def name_map
13
+ r = {}
14
+ all.each { |p| r.merge! p.to_human => p }
15
+ r
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,34 @@
1
+ module Outliers
2
+ class Resource
3
+
4
+ attr_reader :source
5
+
6
+ def self.key
7
+ 'name'
8
+ end
9
+
10
+ def self.verifications
11
+ {}
12
+ end
13
+
14
+ def initialize(source)
15
+ @source = source
16
+ @logger = Outliers.logger
17
+ end
18
+
19
+ def id
20
+ @source.send self.class.key
21
+ end
22
+
23
+ def method_missing(method)
24
+ @source.send method
25
+ end
26
+
27
+ private
28
+
29
+ def logger
30
+ @logger
31
+ end
32
+
33
+ end
34
+ end
@@ -0,0 +1,10 @@
1
+ module Outliers
2
+ module Resources
3
+ module Aws
4
+ module CloudFormation
5
+ class Stack < Resource
6
+ end
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Outliers
2
+ module Resources
3
+ module Aws
4
+ module CloudFormation
5
+ class StackCollection < Collection
6
+
7
+ def load_all
8
+ connect.stacks.map {|r| resource_class.new r}
9
+ end
10
+
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end