cloudpatrol 0.1.3

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.
data/README.rdoc ADDED
@@ -0,0 +1,3 @@
1
+ = Cloudpatrol
2
+
3
+ :include:cloudpatrol.rdoc
data/bin/cloudpatrol ADDED
@@ -0,0 +1,220 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gli'
3
+ require 'json'
4
+
5
+ begin # Remove this begin/rescue before distributing the app
6
+ require 'cloudpatrol'
7
+ rescue LoadError
8
+ exit 64
9
+ end
10
+
11
+ include GLI::App
12
+
13
+ program_desc "Helps you keep Amazon cloud clean"
14
+
15
+ version Cloudpatrol::VERSION
16
+
17
+ result = []
18
+
19
+ desc 'Specify AWS Access Key ID'
20
+ arg_name 'string'
21
+ flag :aws_access_key_id
22
+
23
+ desc 'Specify AWS Secret Access Key'
24
+ arg_name 'string'
25
+ flag :aws_secret_access_key
26
+
27
+ desc 'Specify region'
28
+ arg_name 'string'
29
+ flag :region
30
+
31
+ desc 'Specify config file'
32
+ flag :config_file
33
+
34
+ desc 'Display performance log of the task'
35
+ default_value false
36
+ switch [ :log ]
37
+
38
+ desc 'AWS Identity and Access Management'
39
+ command "iam" do |c|
40
+ c.desc "Deletes all IAM users that do not have MFA enabled. Usernames that begin with underscore (_) are kept."
41
+ c.command "clean-users" do |subc|
42
+ subc.action do |global_options,options,args|
43
+ result = Cloudpatrol.perform($aws_credentials, nil, :IAM, :clean_users)
44
+ puts "Deleted #{result[:task].count} users" if result[:task]
45
+ end
46
+ end
47
+ end
48
+
49
+ desc 'AWS Elastic Compute Cloud'
50
+ command "ec2" do |c|
51
+ c.desc "specifies maximum age"
52
+ c.default_value 5
53
+ c.arg_name "number"
54
+ c.flag [ :d, :days ]
55
+
56
+ # This action needs a feature for constant monitoring of creation time.
57
+ # c.desc "Deletes AWS EC2 key pairs that have existed for configurable number of days"
58
+ # c.command "clean-keypairs" do |subc|
59
+ # subc.action do |global_options,options,args|
60
+ # puts "doesn't work"
61
+ # end
62
+ # end
63
+
64
+ c.desc "Deletes AWS EC2 Instances that have existed for configurable number of days"
65
+ c.command "clean-instances" do |subc|
66
+ subc.action do |global_options,options,args|
67
+ days = options[:days] or $config["ec2_instance_age"] or raise "Specify max age for an instance with -d option or --config_file"
68
+ result = Cloudpatrol.perform($aws_credentials, nil, :EC2, :clean_instances, days.to_i)
69
+ puts "Deleted #{result[:task].count} instances" if result[:task]
70
+ end
71
+ end
72
+
73
+ c.desc "Deletes Security Groups that are no longer being used by AWS EC2 Instances (notice that Security Groups featured in any inbound permission rules will not be deleted)"
74
+ c.command "clean-security-groups" do |subc|
75
+ subc.action do |global_options,options,args|
76
+ result = Cloudpatrol.perform($aws_credentials, nil, :EC2, :clean_security_groups)
77
+ puts "Deleted #{result[:task].count} security groups" if result[:task]
78
+ end
79
+ end
80
+
81
+ c.desc "Deletes ports assigned to the default security group"
82
+ c.command "clean-ports-in-default" do |subc|
83
+ subc.action do |global_options,options,args|
84
+ result = Cloudpatrol.perform($aws_credentials, nil, :EC2, :clean_ports_in_default)
85
+ puts "Deleted #{result[:task].count} rules" if result[:task]
86
+ end
87
+ end
88
+
89
+ c.desc "Starts AWS EC2 Instances"
90
+ c.command "start-instances" do |subc|
91
+ subc.action do |global_options,options,args|
92
+ result = Cloudpatrol.perform($aws_credentials, nil, :EC2, :start_instances)
93
+ puts "Started #{result[:task].count} instances" if result[:task]
94
+ end
95
+ end
96
+
97
+ c.desc "Stops AWS EC2 Instances"
98
+ c.command "stop-instances" do |subc|
99
+ subc.action do |global_options,options,args|
100
+ result = Cloudpatrol.perform($aws_credentials, nil, :EC2, :stop_instances)
101
+ puts "Stopped #{result[:task].count} instances" if result[:task]
102
+ end
103
+ end
104
+
105
+ c.desc "Releases EC2 Elastic IPs not associated with any instance"
106
+ c.command "clean-elastic-ips" do |subc|
107
+ subc.action do |global_options, options, args|
108
+ result = Cloudpatrol.perform($aws_credentials, nil, :EC2, :clean_elastic_ips)
109
+ puts "Deleted #{result[:task].count} Elastic IPs" if result[:task]
110
+ end
111
+ end
112
+ end
113
+
114
+ desc 'AWS OpsWorks'
115
+ command "opsworks" do |c|
116
+ c.desc "specifies maximum age"
117
+ c.default_value 5
118
+ c.arg_name "number"
119
+ c.flag [ :d, :days ]
120
+
121
+ c.desc "Deletes AWS OpsWorks apps that have existed for configurable number of days"
122
+ c.command "clean-apps" do |subc|
123
+ subc.action do |global_options,options,args|
124
+ days = options[:days] or $config["opsworks_app_age"] or raise "Specify max age for an app with -d option or --config_file"
125
+ result = Cloudpatrol.perform($aws_credentials, nil, :OpsWorks, :clean_apps, days.to_i)
126
+ puts "Deleted #{result[:task].count} OpsWorks apps" if result[:task]
127
+ end
128
+ end
129
+
130
+ c.desc "Deletes AWS OpsWorks instances that have existed for configurable number of days"
131
+ c.command "clean-instances" do |subc|
132
+ subc.action do |global_options,options,args|
133
+ days = options[:days] or $config["opsworks_instance_age"] or raise "Specify max age for an instance with -d option or --config_file"
134
+ result = Cloudpatrol.perform($aws_credentials, nil, :OpsWorks, :clean_instances, days.to_i)
135
+ puts "Deleted #{result[:task].count} OpsWorks instances" if result[:task]
136
+ end
137
+ end
138
+
139
+ c.desc "Deletes AWS OpsWorks layers that have existed for configurable number of days"
140
+ c.command "clean-layers" do |subc|
141
+ subc.action do |global_options,options,args|
142
+ days = options[:days] or $config["opsworks_layer_age"] or raise "Specify max age for a layer with -d option or --config_file"
143
+ result = Cloudpatrol.perform($aws_credentials, nil, :OpsWorks, :clean_layers, days.to_i)
144
+ puts "Deleted #{result[:task].count} OpsWorks layers" if result[:task]
145
+ end
146
+ end
147
+
148
+ c.desc "Deletes AWS OpsWorks stacks that have existed for configurable number of days"
149
+ c.command "clean-stacks" do |subc|
150
+ subc.action do |global_options,options,args|
151
+ days = options[:days] or $config["opsworks_stack_age"] or raise "Specify max age for a stack with -d option or --config_file"
152
+ result = Cloudpatrol.perform($aws_credentials, nil, :OpsWorks, :clean_stacks, days.to_i)
153
+ puts "Deleted #{result[:task].count} OpsWorks stacks" if result[:task]
154
+ end
155
+ end
156
+ end
157
+
158
+ desc 'AWS CloudFormation'
159
+ command "cloudformation" do |c|
160
+ c.desc "specifies maximum age"
161
+ c.default_value 5
162
+ c.arg_name "number"
163
+ c.flag [ :d, :days ]
164
+
165
+ c.desc "Deletes AWS CloudFormation stacks that have existed for configurable number of days"
166
+ c.command "clean-stacks" do |subc|
167
+ subc.action do |global_options,options,args|
168
+ days = options[:days] or $config["cloudformation_stack_age"] or raise "Specify max age for a stack with -d option or --config_file"
169
+ result = Cloudpatrol.perform($aws_credentials, nil, :CloudFormation, :clean_stacks, days.to_i)
170
+ puts "Deleted #{result[:task].count} CloudFormation stacks" if result[:task]
171
+ end
172
+ end
173
+ end
174
+
175
+ desc 'CloudPatrol log'
176
+ command "log" do |c|
177
+ c.desc "overrides default table name"
178
+ c.default_value "cloudpatrol-log"
179
+ c.flag [ :t, :table ]
180
+
181
+ c.action do |global_options,options,args|
182
+ table_name = options[:table] || "cloudpatrol-log"
183
+ result = Cloudpatrol.get_log($aws_credentials, table_name)
184
+ if result[:success]
185
+ puts result[:log]
186
+ else
187
+ puts result[:error]
188
+ end
189
+ end
190
+ end
191
+
192
+ pre do |global, command, options, args|
193
+ $aws_credentials = {}
194
+ $config = {}
195
+
196
+ if global[:config_file]
197
+ if File.readable?(global[:config_file])
198
+ $config = JSON.parse(File.read(global[:config_file])) rescue raise(ArgumentError, "invalid config file")
199
+ else
200
+ raise ArgumentError, "--config_file: no such file"
201
+ end
202
+ end
203
+
204
+ $aws_credentials[:access_key_id] = global[:aws_access_key_id] || $config["aws_access_key_id"] || raise(ArgumentError, "--aws_access_key_id or --config_file is required")
205
+ $aws_credentials[:secret_access_key] = global[:aws_secret_access_key] || $config["aws_secret_access_key"] || raise(ArgumentError, "--aws_secret_access_key or --config_file is required")
206
+ $aws_credentials[:region] = global[:region] or "us-east-1"
207
+ true
208
+ end
209
+
210
+ post do |global, command, options, args|
211
+ puts result[:formatted] if global[:log] and command.name != "log"
212
+ end
213
+
214
+ on_error do |exception|
215
+ # Error logic here
216
+ # return false to skip default error handling
217
+ true
218
+ end
219
+
220
+ exit run(ARGV)
data/cloudpatrol.rdoc ADDED
File without changes
@@ -0,0 +1,68 @@
1
+ require 'cloudpatrol/task.rb'
2
+ require 'cloudpatrol/version.rb'
3
+ require 'core_ext/integer.rb'
4
+
5
+ module Cloudpatrol
6
+ def self.perform aws_credentials, table_name, klass, method, *args
7
+ response = {}
8
+ table_name ||= "cloudpatrol-log"
9
+
10
+ response[:task] = begin
11
+ response[:formatted] = Task.const_get(klass).new(aws_credentials).send(method, *args)
12
+ rescue AWS::Errors::Base => e
13
+ response[:formatted] = "AWS error: #{e}"
14
+ false
15
+ rescue
16
+ response[:formatted] = "Unknown error"
17
+ false
18
+ end
19
+
20
+ response[:log] = begin
21
+ Task::DynamoDB.new(aws_credentials, table_name).log({ class: klass, method: method, args: args }, response[:formatted])
22
+ rescue
23
+ puts "Failed to write log to DynamoDB"
24
+ false
25
+ end
26
+
27
+ response
28
+ end
29
+
30
+ def self.get_log aws_credentials, table_name = "cloudpatrol-log"
31
+ gate = ::AWS::DynamoDB.new(aws_credentials)
32
+ response = {}
33
+ table = gate.tables[table_name]
34
+ if table.exists? and table.status == :active
35
+ table.load_schema
36
+ response[:log] = []
37
+ table.items.each do |item|
38
+ response[:log] << item.attributes.to_hash
39
+ end
40
+ response[:log].map! do |item|
41
+ {
42
+ time: Time.parse(item["time"]),
43
+ action: item["action"],
44
+ response: item["response"]
45
+ }
46
+ end
47
+ response[:log].sort!{ |x,y| x[:time] <=> y[:time] }
48
+ else
49
+ response[:success] = false
50
+ response[:error] = "Table doesn't exist"
51
+ end
52
+ rescue AWS::Errors::Base => e
53
+ response[:success] = false
54
+ response[:error] = "AWS error: #{e}"
55
+ rescue
56
+ response[:success] = false
57
+ response[:error] = "Unknown error"
58
+ else
59
+ response[:success] = if response[:log].empty?
60
+ response[:error] = "Log is empty"
61
+ false
62
+ else
63
+ true
64
+ end
65
+ ensure
66
+ return response
67
+ end
68
+ end
@@ -0,0 +1,10 @@
1
+ require 'cloudpatrol/task/cloud_formation.rb'
2
+ require 'cloudpatrol/task/dynamo_db.rb'
3
+ require 'cloudpatrol/task/ec2.rb'
4
+ require 'cloudpatrol/task/iam.rb'
5
+ require 'cloudpatrol/task/ops_works.rb'
6
+
7
+ module Cloudpatrol
8
+ module Task
9
+ end
10
+ end
@@ -0,0 +1,22 @@
1
+ require 'aws'
2
+
3
+ module Cloudpatrol
4
+ module Task
5
+ class CloudFormation
6
+ def initialize cred
7
+ @gate = ::AWS::CloudFormation.new(cred)
8
+ end
9
+
10
+ def clean_stacks allowed_age
11
+ deleted = []
12
+ @gate.stacks.each do |stack|
13
+ if (Time.now - stack.creation_time).to_i > allowed_age.days
14
+ deleted << stack.inspect
15
+ stack.delete
16
+ end
17
+ end
18
+ deleted
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,39 @@
1
+ require 'securerandom'
2
+ require 'aws'
3
+
4
+ module Cloudpatrol
5
+ module Task
6
+ class DynamoDB
7
+ def initialize cred, table_name
8
+ @gate = ::AWS::DynamoDB.new(cred)
9
+ @table = @gate.tables[table_name]
10
+
11
+ unless @table.exists?
12
+ puts "Creating DynamoDB table \"#{table_name}\", wait a while..."
13
+ @table = @gate.tables.create(table_name, 1, 1)
14
+ sleep 1 while @table.status == :creating
15
+ puts "Table created"
16
+ end
17
+ rescue
18
+ @table = nil
19
+ end
20
+
21
+ def log action, response
22
+ raise unless @table
23
+
24
+ if @table.status == :active
25
+ item = @table.items.create(
26
+ id: SecureRandom.uuid,
27
+ action: action.to_s,
28
+ response: response.to_s,
29
+ time: Time.now.to_s
30
+ )
31
+ else
32
+ nil
33
+ end
34
+ rescue
35
+ false
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,81 @@
1
+ require 'aws'
2
+
3
+ module Cloudpatrol
4
+ module Task
5
+ class EC2
6
+ def initialize cred
7
+ @gate = ::AWS::EC2.new(cred)
8
+ end
9
+
10
+ def start_instances
11
+ result = []
12
+ @gate.instances.each do |instance|
13
+ result << instance.inspect
14
+ instance.start
15
+ end
16
+ result
17
+ end
18
+
19
+ def stop_instances
20
+ result = []
21
+ @gate.instances.each do |instance|
22
+ result << instance.inspect
23
+ instance.stop
24
+ end
25
+ result
26
+ end
27
+
28
+ def clean_instances allowed_age
29
+ deleted = []
30
+ @gate.instances.each do |instance|
31
+ if (Time.now - instance.launch_time).to_i > allowed_age.days and instance.status != :terminated
32
+ deleted << instance.inspect
33
+ instance.delete
34
+ end
35
+ end
36
+ deleted
37
+ end
38
+
39
+ def clean_security_groups
40
+ deleted = []
41
+ protected_groups = []
42
+ @gate.security_groups.each do |sg|
43
+ sg.ip_permissions.each do |perm|
44
+ perm.groups.each do |dependent_sg|
45
+ protected_groups << dependent_sg
46
+ end
47
+ end
48
+ end
49
+ @gate.security_groups.each do |sg|
50
+ if !protected_groups.include?(sg) and sg.exists? and sg.instances.count == 0 and sg.name != "default"
51
+ deleted << sg.inspect
52
+ sg.delete
53
+ end
54
+ end
55
+ deleted
56
+ end
57
+
58
+ def clean_ports_in_default
59
+ deleted = []
60
+ @gate.security_groups.filter("group-name", "default").each do |sg|
61
+ sg.ingress_ip_permissions.each do |perm|
62
+ deleted << { port_range: perm.port_range }
63
+ perm.revoke
64
+ end
65
+ end
66
+ deleted
67
+ end
68
+
69
+ def clean_elastic_ips
70
+ deleted = []
71
+ @gate.elastic_ips.each do |ip|
72
+ unless ip.instance
73
+ deleted << ip.inspect
74
+ ip.release
75
+ end
76
+ end
77
+ deleted
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,22 @@
1
+ require 'aws'
2
+
3
+ module Cloudpatrol
4
+ module Task
5
+ class IAM
6
+ def initialize cred
7
+ @gate = ::AWS::IAM.new(cred)
8
+ end
9
+
10
+ def clean_users
11
+ deleted = []
12
+ @gate.users.each do |user|
13
+ unless user.name =~ /^_/ or user.mfa_devices.count > 0
14
+ deleted << user.inspect
15
+ user.delete!
16
+ end
17
+ end
18
+ deleted
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,61 @@
1
+ require 'aws'
2
+
3
+ module Cloudpatrol
4
+ module Task
5
+ class OpsWorks
6
+ def initialize cred
7
+ @gate = ::AWS::OpsWorks::Client.new(cred)
8
+ end
9
+
10
+ def clean_apps allowed_age
11
+ deleted = []
12
+ @gate.describe_stacks[:stacks].each do |stack|
13
+ @gate.describe_apps(stack_id: stack[:stack_id])[:apps].each do |app|
14
+ if (Time.now - Time.parse(app[:created_at])).to_i > allowed_age.days
15
+ deleted << app
16
+ @gate.delete_app app_id: app[:app_id]
17
+ end
18
+ end
19
+ end
20
+ deleted
21
+ end
22
+
23
+ def clean_instances allowed_age
24
+ deleted = []
25
+ @gate.describe_stacks[:stacks].each do |stack|
26
+ @gate.describe_instances(stack_id: stack[:stack_id])[:instances].each do |instance|
27
+ if (Time.now - Time.parse(instance[:created_at])).to_i > allowed_age.days
28
+ deleted << instance
29
+ @gate.delete_instance instance_id: instance[:instance_id]
30
+ end
31
+ end
32
+ end
33
+ deleted
34
+ end
35
+
36
+ def clean_layers allowed_age
37
+ deleted = []
38
+ @gate.describe_stacks[:stacks].each do |stack|
39
+ @gate.describe_layers(stack_id: stack[:stack_id])[:layers].each do |layer|
40
+ if (Time.now - Time.parse(layer[:created_at])).to_i > allowed_age.days
41
+ deleted << layer
42
+ @gate.delete_layer layer_id: layer[:layer_id]
43
+ end
44
+ end
45
+ end
46
+ deleted
47
+ end
48
+
49
+ def clean_stacks allowed_age
50
+ deleted = []
51
+ @gate.describe_stacks[:stacks].each do |stack|
52
+ if (Time.now - Time.parse(stack[:created_at])).to_i > allowed_age.days
53
+ deleted << stack
54
+ @gate.delete_stack stack_id: stack[:stack_id]
55
+ end
56
+ end
57
+ deleted
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,3 @@
1
+ module Cloudpatrol
2
+ VERSION = '0.1.3'
3
+ end
@@ -0,0 +1,5 @@
1
+ class Integer
2
+ def days
3
+ self * 24 * 60 * 60
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,161 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cloudpatrol
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.3
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Stelligent
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-08-15 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rdoc
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: aruba
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: gli
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - '='
68
+ - !ruby/object:Gem::Version
69
+ version: 2.6.0
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - '='
76
+ - !ruby/object:Gem::Version
77
+ version: 2.6.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: json
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ! '>='
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ type: :runtime
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ! '>='
92
+ - !ruby/object:Gem::Version
93
+ version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: aws-sdk
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - '='
100
+ - !ruby/object:Gem::Version
101
+ version: 1.11.0
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - '='
108
+ - !ruby/object:Gem::Version
109
+ version: 1.11.0
110
+ description:
111
+ email: developers@stelligent.com
112
+ executables:
113
+ - cloudpatrol
114
+ extensions: []
115
+ extra_rdoc_files:
116
+ - README.rdoc
117
+ - cloudpatrol.rdoc
118
+ files:
119
+ - bin/cloudpatrol
120
+ - lib/cloudpatrol/task/cloud_formation.rb
121
+ - lib/cloudpatrol/task/dynamo_db.rb
122
+ - lib/cloudpatrol/task/ec2.rb
123
+ - lib/cloudpatrol/task/iam.rb
124
+ - lib/cloudpatrol/task/ops_works.rb
125
+ - lib/cloudpatrol/task.rb
126
+ - lib/cloudpatrol/version.rb
127
+ - lib/core_ext/integer.rb
128
+ - lib/cloudpatrol.rb
129
+ - README.rdoc
130
+ - cloudpatrol.rdoc
131
+ homepage: http://stelligent.com
132
+ licenses: []
133
+ post_install_message:
134
+ rdoc_options:
135
+ - --title
136
+ - cloudpatrol
137
+ - --main
138
+ - README.rdoc
139
+ - -ri
140
+ require_paths:
141
+ - lib
142
+ - lib
143
+ required_ruby_version: !ruby/object:Gem::Requirement
144
+ none: false
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: 1.9.3
149
+ required_rubygems_version: !ruby/object:Gem::Requirement
150
+ none: false
151
+ requirements:
152
+ - - ! '>='
153
+ - !ruby/object:Gem::Version
154
+ version: '0'
155
+ requirements: []
156
+ rubyforge_project:
157
+ rubygems_version: 1.8.23
158
+ signing_key:
159
+ specification_version: 3
160
+ summary: Command-line tool that helps you keep Amazon cloud clean
161
+ test_files: []