aws-cleaner 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/aws_cleaner.rb +24 -185
- data/lib/aws_cleaner/aws_cleaner.rb +197 -0
- metadata +62 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 634ceede119aecae922a17090cb5d18a18855e54
|
4
|
+
data.tar.gz: e1f7409e0ba5e6096bbc9d2667aba98333e47054
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d03730f5c4a09e5ba56eb1dc4cebce0c3a27fe320a776a543faa30d70f11d85a06de04010a69537d7cd1712fbf26e4a61b96474271bd4627e7e32974c081ad4
|
7
|
+
data.tar.gz: 51409d6d97e5abb81c4bdc722f1ac7b7e0ff1d6a9915fe3ac1ff9ea356d8b4cb9ce9f5e76ebb5c95c5427747270ece2540fd6e2c73e107defd2599884e2df007
|
data/bin/aws_cleaner.rb
CHANGED
@@ -4,10 +4,11 @@
|
|
4
4
|
# and remove the node from Chef and Sensu and send a notification
|
5
5
|
# to Hipchat or Slack
|
6
6
|
#
|
7
|
-
# Copyright (c) 2015
|
7
|
+
# Copyright (c) 2015-2017 Eric Heydrick
|
8
8
|
# Licensed under The MIT License
|
9
9
|
#
|
10
10
|
|
11
|
+
# ensure gems are present
|
11
12
|
begin
|
12
13
|
require 'json'
|
13
14
|
require 'yaml'
|
@@ -21,6 +22,9 @@ rescue LoadError => e
|
|
21
22
|
raise "Missing gems: #{e}"
|
22
23
|
end
|
23
24
|
|
25
|
+
# require our class
|
26
|
+
require_relative '../lib/aws_cleaner/aws_cleaner.rb'
|
27
|
+
|
24
28
|
def config(file)
|
25
29
|
YAML.load(File.read(file))
|
26
30
|
rescue StandardError => e
|
@@ -28,185 +32,21 @@ rescue StandardError => e
|
|
28
32
|
end
|
29
33
|
|
30
34
|
# get options
|
31
|
-
opts = Trollop
|
35
|
+
opts = Trollop.options do
|
32
36
|
opt :config, 'Path to config file', type: :string, default: 'config.yml'
|
33
37
|
end
|
34
38
|
|
35
39
|
@config = config(opts[:config])
|
36
40
|
|
37
|
-
@sqs = Aws::SQS::Client.new(@config[:aws])
|
38
|
-
|
39
|
-
@chef = ChefAPI::Connection.new(
|
40
|
-
endpoint: @config[:chef][:url],
|
41
|
-
client: @config[:chef][:client],
|
42
|
-
key: @config[:chef][:key]
|
43
|
-
)
|
44
|
-
|
45
|
-
# delete the message from SQS
|
46
|
-
def delete_message(id)
|
47
|
-
delete = @sqs.delete_message(
|
48
|
-
queue_url: @config[:sqs][:queue],
|
49
|
-
receipt_handle: id
|
50
|
-
)
|
51
|
-
delete ? true : false
|
52
|
-
end
|
53
|
-
|
54
|
-
# return the body of the SQS message in JSON
|
55
|
-
def parse(body)
|
56
|
-
JSON.parse(body)
|
57
|
-
rescue JSON::ParserError
|
58
|
-
return false
|
59
|
-
end
|
60
|
-
|
61
|
-
# return the instance_id of the terminated instance
|
62
|
-
def process_message(message_body)
|
63
|
-
return false if message_body['detail']['instance-id'].nil? &&
|
64
|
-
message_body['detail']['state'] != 'terminated'
|
65
|
-
|
66
|
-
instance_id = message_body['detail']['instance-id']
|
67
|
-
instance_id
|
68
|
-
end
|
69
|
-
|
70
|
-
# call the Chef API to get the node name of the instance
|
71
|
-
def get_chef_node_name(instance_id)
|
72
|
-
results = @chef.search.query(:node, "ec2_instance_id:#{instance_id} OR chef_provisioning_reference_server_id:#{instance_id}")
|
73
|
-
if results.rows.size > 0
|
74
|
-
return results.rows.first['name']
|
75
|
-
else
|
76
|
-
return false
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
# call the Chef API to get the FQDN of the instance
|
81
|
-
def get_chef_fqdn(instance_id)
|
82
|
-
results = @chef.search.query(:node, "ec2_instance_id:#{instance_id} OR chef_provisioning_reference_server_id:#{instance_id}")
|
83
|
-
if results.rows.size > 0
|
84
|
-
return results.rows.first['automatic']['fqdn']
|
85
|
-
else
|
86
|
-
return false
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
# check if the node exists in Sensu
|
91
|
-
def in_sensu?(node_name)
|
92
|
-
begin
|
93
|
-
RestClient::Request.execute(url: "#{@config[:sensu][:url]}/clients/#{node_name}", method: :get, timeout: 5, open_timeout: 5)
|
94
|
-
rescue RestClient::ResourceNotFound
|
95
|
-
return false
|
96
|
-
rescue => e
|
97
|
-
puts "Sensu request failed: #{e}"
|
98
|
-
return false
|
99
|
-
else
|
100
|
-
return true
|
101
|
-
end
|
102
|
-
end
|
103
|
-
|
104
|
-
# call the Sensu API to remove the node
|
105
|
-
def remove_from_sensu(node_name)
|
106
|
-
response = RestClient::Request.execute(url: "#{@config[:sensu][:url]}/clients/#{node_name}", method: :delete, timeout: 5, open_timeout: 5)
|
107
|
-
case response.code
|
108
|
-
when 202
|
109
|
-
notify_chat('Removed ' + node_name + ' from Sensu')
|
110
|
-
return true
|
111
|
-
else
|
112
|
-
notify_chat('Failed to remove ' + node_name + ' from Sensu')
|
113
|
-
return false
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# call the Chef API to remove the node
|
118
|
-
def remove_from_chef(node_name)
|
119
|
-
begin
|
120
|
-
client = @chef.clients.fetch(node_name)
|
121
|
-
client.destroy
|
122
|
-
node = @chef.nodes.fetch(node_name)
|
123
|
-
node.destroy
|
124
|
-
rescue => e
|
125
|
-
puts "Failed to remove chef node: #{e}"
|
126
|
-
else
|
127
|
-
notify_chat('Removed ' + node_name + ' from Chef')
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
# notify hipchat
|
132
|
-
def notify_hipchat(msg)
|
133
|
-
hipchat = HipChat::Client.new(
|
134
|
-
@config[:hipchat][:api_token],
|
135
|
-
api_version: 'v2'
|
136
|
-
)
|
137
|
-
room = @config[:hipchat][:room]
|
138
|
-
hipchat[room].send('AWS Cleaner', msg)
|
139
|
-
end
|
140
|
-
|
141
|
-
# notify slack
|
142
|
-
def notify_slack(msg)
|
143
|
-
slack = Slack::Poster.new(@config[:slack][:webhook_url])
|
144
|
-
slack.channel = @config[:slack][:channel]
|
145
|
-
slack.username = @config[:slack][:username] ||= 'aws-cleaner'
|
146
|
-
slack.icon_emoji = @config[:slack][:icon_emoji] ||= nil
|
147
|
-
slack.send_message(msg)
|
148
|
-
end
|
149
|
-
|
150
|
-
# generic chat notification method
|
151
|
-
def notify_chat(msg)
|
152
|
-
if @config[:hipchat][:enable]
|
153
|
-
notify_hipchat(msg)
|
154
|
-
elsif @config[:slack][:enable]
|
155
|
-
notify_slack(msg)
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
# generate the URL for the webhook
|
160
|
-
def generate_template(item, template_variable_method, template_variable_argument, template_variable)
|
161
|
-
begin
|
162
|
-
replacement = send(template_variable_method, eval(template_variable_argument))
|
163
|
-
item.gsub!(/{#{template_variable}}/, replacement)
|
164
|
-
rescue Exception => e
|
165
|
-
puts "Error generating template: #{e.message}"
|
166
|
-
return false
|
167
|
-
else
|
168
|
-
item
|
169
|
-
end
|
170
|
-
end
|
41
|
+
# @sqs = Aws::SQS::Client.new(@config[:aws])
|
42
|
+
@sqs_client = AwsCleaner::SQS.client(@config)
|
171
43
|
|
172
|
-
|
173
|
-
def fire_webhook(config)
|
174
|
-
# generate templated URL
|
175
|
-
if config[:template_variables] && config[:url] =~ /\{\S+\}/
|
176
|
-
url = generate_template(
|
177
|
-
config[:url],
|
178
|
-
config[:template_variables][:method],
|
179
|
-
config[:template_variables][:argument],
|
180
|
-
config[:template_variables][:variable]
|
181
|
-
)
|
182
|
-
return false unless url
|
183
|
-
else
|
184
|
-
url = config[:url]
|
185
|
-
end
|
186
|
-
|
187
|
-
hook = { method: config[:method].to_sym, url: url }
|
188
|
-
r = RestClient::Request.execute(hook)
|
189
|
-
if r.code != 200
|
190
|
-
return false
|
191
|
-
else
|
192
|
-
# notify chat when webhook is successful
|
193
|
-
if config[:chat][:enable]
|
194
|
-
msg = generate_template(
|
195
|
-
config[:chat][:message],
|
196
|
-
config[:chat][:method],
|
197
|
-
config[:chat][:argument],
|
198
|
-
config[:chat][:variable]
|
199
|
-
)
|
200
|
-
notify_chat(msg)
|
201
|
-
end
|
202
|
-
return true
|
203
|
-
end
|
204
|
-
end
|
44
|
+
@chef_client = AwsCleaner::Chef.client(@config)
|
205
45
|
|
206
46
|
# main loop
|
207
47
|
loop do
|
208
48
|
# get messages from SQS
|
209
|
-
messages = @
|
49
|
+
messages = @sqs_client.receive_message(
|
210
50
|
queue_url: @config[:sqs][:queue],
|
211
51
|
max_number_of_messages: 10,
|
212
52
|
visibility_timeout: 3
|
@@ -216,53 +56,52 @@ loop do
|
|
216
56
|
|
217
57
|
messages.each_with_index do |message, index|
|
218
58
|
puts "Looking at message number #{index}"
|
219
|
-
body = parse(message.body)
|
59
|
+
body = AwsCleaner.new.parse(message.body)
|
220
60
|
id = message.receipt_handle
|
221
61
|
|
222
62
|
unless body
|
223
|
-
delete_message(id)
|
63
|
+
AwsCleaner.new.delete_message(id, @config)
|
224
64
|
next
|
225
65
|
end
|
226
66
|
|
227
|
-
@instance_id = process_message(body)
|
67
|
+
@instance_id = AwsCleaner.new.process_message(body)
|
228
68
|
|
229
69
|
if @instance_id
|
230
70
|
if @config[:webhooks]
|
231
|
-
@config[:webhooks].each do |hook,
|
232
|
-
if fire_webhook(config)
|
71
|
+
@config[:webhooks].each do |hook, hook_config|
|
72
|
+
if AwsCleaner::Webhooks.fire_webhook(hook_config, @config, @instance_id)
|
233
73
|
puts "Successfully ran webhook #{hook}"
|
234
74
|
else
|
235
75
|
puts "Failed to run webhook #{hook}"
|
236
76
|
end
|
237
77
|
end
|
238
|
-
delete_message(id)
|
78
|
+
AwsCleaner.new.delete_message(id, @config)
|
239
79
|
end
|
240
80
|
|
241
|
-
chef_node = get_chef_node_name(@instance_id)
|
81
|
+
chef_node = AwsCleaner::Chef.get_chef_node_name(@instance_id, @config)
|
242
82
|
|
243
83
|
if chef_node
|
244
|
-
if remove_from_chef(chef_node)
|
84
|
+
if AwsCleaner::Chef.remove_from_chef(chef_node, @chef_client, @config)
|
245
85
|
puts "Removed #{chef_node} from Chef"
|
246
|
-
delete_message(id)
|
86
|
+
AwsCleaner.new.delete_message(id, @config)
|
247
87
|
end
|
248
88
|
else
|
249
89
|
puts "Instance #{@instance_id} does not exist in Chef, deleting message"
|
250
|
-
delete_message(id)
|
90
|
+
AwsCleaner.new.delete_message(id, @config)
|
251
91
|
end
|
252
92
|
|
253
|
-
if in_sensu?(chef_node)
|
254
|
-
if remove_from_sensu(chef_node)
|
93
|
+
if AwsCleaner::Sensu.in_sensu?(chef_node, @config)
|
94
|
+
if AwsCleaner::Sensu.remove_from_sensu(chef_node, @config)
|
255
95
|
puts "Removed #{chef_node} from Sensu"
|
256
|
-
delete_message(id)
|
257
96
|
else
|
258
97
|
puts "Instance #{@instance_id} does not exist in Sensu, deleting message"
|
259
|
-
delete_message(id)
|
260
98
|
end
|
99
|
+
AwsCleaner.new.delete_message(id, @config)
|
261
100
|
end
|
262
101
|
|
263
102
|
else
|
264
103
|
puts 'Message not relevant, deleting'
|
265
|
-
delete_message(id)
|
104
|
+
AwsCleaner.new.delete_message(id, @config)
|
266
105
|
end
|
267
106
|
end
|
268
107
|
|
@@ -0,0 +1,197 @@
|
|
1
|
+
# main aws_cleaner lib
|
2
|
+
class AwsCleaner
|
3
|
+
# SQS related stuff
|
4
|
+
module SQS
|
5
|
+
# sqs connection
|
6
|
+
def self.client(config)
|
7
|
+
Aws::SQS::Client.new(config[:aws])
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
# delete the message from SQS
|
12
|
+
def delete_message(id, config)
|
13
|
+
delete = AwsCleaner::SQS.client(config).delete_message(
|
14
|
+
queue_url: config[:sqs][:queue],
|
15
|
+
receipt_handle: id
|
16
|
+
)
|
17
|
+
delete ? true : false
|
18
|
+
end
|
19
|
+
|
20
|
+
module Chef
|
21
|
+
# chef connection
|
22
|
+
def self.client(config)
|
23
|
+
ChefAPI::Connection.new(
|
24
|
+
endpoint: config[:chef][:url],
|
25
|
+
client: config[:chef][:client],
|
26
|
+
key: config[:chef][:key]
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
# call the Chef API to get the node name of the instance
|
31
|
+
def self.get_chef_node_name(instance_id, config)
|
32
|
+
chef = client(config)
|
33
|
+
results = chef.search.query(:node, "ec2_instance_id:#{instance_id} OR chef_provisioning_reference_server_id:#{instance_id}")
|
34
|
+
return false if results.rows.empty?
|
35
|
+
results.rows.first['name']
|
36
|
+
end
|
37
|
+
|
38
|
+
# call the Chef API to get the FQDN of the instance
|
39
|
+
def self.get_chef_fqdn(instance_id, config)
|
40
|
+
chef = client(config)
|
41
|
+
results = chef.search.query(:node, "ec2_instance_id:#{instance_id} OR chef_provisioning_reference_server_id:#{instance_id}")
|
42
|
+
return false if results.rows.empty?
|
43
|
+
results.rows.first['automatic']['fqdn']
|
44
|
+
end
|
45
|
+
|
46
|
+
# call the Chef API to remove the node
|
47
|
+
def self.remove_from_chef(node_name, chef, config)
|
48
|
+
client = chef.clients.fetch(node_name)
|
49
|
+
client.destroy
|
50
|
+
node = chef.nodes.fetch(node_name)
|
51
|
+
node.destroy
|
52
|
+
rescue => e
|
53
|
+
puts "Failed to remove chef node: #{e}"
|
54
|
+
else
|
55
|
+
# puts "Removed #{node_name} from chef"
|
56
|
+
AwsCleaner::Notify.notify_chat('Removed ' + node_name + ' from Chef', config)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module Sensu
|
61
|
+
# check if the node exists in Sensu
|
62
|
+
def self.in_sensu?(node_name, config)
|
63
|
+
RestClient::Request.execute(
|
64
|
+
url: "#{config[:sensu][:url]}/clients/#{node_name}",
|
65
|
+
method: :get,
|
66
|
+
timeout: 5,
|
67
|
+
open_timeout: 5
|
68
|
+
)
|
69
|
+
rescue RestClient::ResourceNotFound
|
70
|
+
return false
|
71
|
+
rescue => e
|
72
|
+
puts "Sensu request failed: #{e}"
|
73
|
+
return false
|
74
|
+
else
|
75
|
+
return true
|
76
|
+
end
|
77
|
+
|
78
|
+
# call the Sensu API to remove the node
|
79
|
+
def self.remove_from_sensu(node_name, config)
|
80
|
+
response = RestClient::Request.execute(
|
81
|
+
url: "#{config[:sensu][:url]}/clients/#{node_name}",
|
82
|
+
method: :delete,
|
83
|
+
timeout: 5,
|
84
|
+
open_timeout: 5
|
85
|
+
)
|
86
|
+
case response.code
|
87
|
+
when 202
|
88
|
+
AwsCleaner::Notify.notify_chat('Removed ' + node_name + ' from Sensu', config)
|
89
|
+
return true
|
90
|
+
else
|
91
|
+
AwsCleaner::Notify.notify_chat('Failed to remove ' + node_name + ' from Sensu', config)
|
92
|
+
return false
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# return the body of the SQS message in JSON
|
98
|
+
def parse(body)
|
99
|
+
JSON.parse(body)
|
100
|
+
rescue JSON::ParserError
|
101
|
+
return false
|
102
|
+
end
|
103
|
+
|
104
|
+
# return the instance_id of the terminated instance
|
105
|
+
def process_message(message_body)
|
106
|
+
return false if message_body['detail']['instance-id'].nil? &&
|
107
|
+
message_body['detail']['state'] != 'terminated'
|
108
|
+
|
109
|
+
instance_id = message_body['detail']['instance-id']
|
110
|
+
instance_id
|
111
|
+
end
|
112
|
+
|
113
|
+
module Notify
|
114
|
+
# notify hipchat
|
115
|
+
def self.notify_hipchat(msg, config)
|
116
|
+
hipchat = HipChat::Client.new(
|
117
|
+
config[:hipchat][:api_token],
|
118
|
+
api_version: 'v2'
|
119
|
+
)
|
120
|
+
room = config[:hipchat][:room]
|
121
|
+
hipchat[room].send('AWS Cleaner', msg)
|
122
|
+
end
|
123
|
+
|
124
|
+
# notify slack
|
125
|
+
def self.notify_slack(msg, config)
|
126
|
+
slack = Slack::Poster.new(config[:slack][:webhook_url])
|
127
|
+
slack.channel = config[:slack][:channel]
|
128
|
+
slack.username = config[:slack][:username] ||= 'aws-cleaner'
|
129
|
+
slack.icon_emoji = config[:slack][:icon_emoji] ||= nil
|
130
|
+
slack.send_message(msg)
|
131
|
+
end
|
132
|
+
|
133
|
+
# generic chat notification method
|
134
|
+
def self.notify_chat(msg, config)
|
135
|
+
if config[:hipchat][:enable]
|
136
|
+
notify_hipchat(msg, config)
|
137
|
+
elsif config[:slack][:enable]
|
138
|
+
notify_slack(msg, config)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
module Webhooks
|
144
|
+
# generate the URL for the webhook
|
145
|
+
def self.generate_template(item, template_variable_method, template_variable, config, instance_id)
|
146
|
+
if template_variable_method == 'get_chef_fqdn'
|
147
|
+
replacement = AwsCleaner::Chef.get_chef_fqdn(instance_id, config)
|
148
|
+
elsif template_variable_method == 'get_chef_node_name'
|
149
|
+
replacement = AwsCleaner::Chef.get_chef_node_name(instance_id, config)
|
150
|
+
else
|
151
|
+
raise 'Unknown templating method'
|
152
|
+
end
|
153
|
+
item.gsub!(/{#{template_variable}}/, replacement)
|
154
|
+
rescue StandardError => e
|
155
|
+
puts "Error generating template: #{e.message}"
|
156
|
+
return false
|
157
|
+
else
|
158
|
+
item
|
159
|
+
end
|
160
|
+
|
161
|
+
# call an HTTP endpoint
|
162
|
+
def self.fire_webhook(hook_config, config, instance_id)
|
163
|
+
# generate templated URL
|
164
|
+
if hook_config[:template_variables] && hook_config[:url] =~ /\{\S+\}/
|
165
|
+
url = AwsCleaner::Webhooks.generate_template(
|
166
|
+
hook_config[:url],
|
167
|
+
hook_config[:template_variables][:method],
|
168
|
+
hook_config[:template_variables][:variable],
|
169
|
+
config,
|
170
|
+
instance_id
|
171
|
+
)
|
172
|
+
return false unless url
|
173
|
+
else
|
174
|
+
url = hook_config[:url]
|
175
|
+
end
|
176
|
+
|
177
|
+
hook = { method: hook_config[:method].to_sym, url: url }
|
178
|
+
r = RestClient::Request.execute(hook)
|
179
|
+
if r.code != 200
|
180
|
+
return false
|
181
|
+
else
|
182
|
+
# notify chat when webhook is successful
|
183
|
+
if hook_config[:chat][:enable]
|
184
|
+
msg = AwsCleaner::Webhooks.generate_template(
|
185
|
+
hook_config[:chat][:message],
|
186
|
+
hook_config[:chat][:method],
|
187
|
+
hook_config[:chat][:variable],
|
188
|
+
config,
|
189
|
+
instance_id
|
190
|
+
)
|
191
|
+
AwsCleaner::Notify.notify_chat(msg, config)
|
192
|
+
end
|
193
|
+
return true
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-cleaner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Heydrick
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-03-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.12'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.12'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '12.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '12.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.5'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.5'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rubocop
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.46.0
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 0.46.0
|
13
69
|
- !ruby/object:Gem::Dependency
|
14
70
|
name: aws-sdk-core
|
15
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -58,14 +114,14 @@ dependencies:
|
|
58
114
|
requirements:
|
59
115
|
- - "~>"
|
60
116
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
117
|
+
version: '2'
|
62
118
|
type: :runtime
|
63
119
|
prerelease: false
|
64
120
|
version_requirements: !ruby/object:Gem::Requirement
|
65
121
|
requirements:
|
66
122
|
- - "~>"
|
67
123
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
124
|
+
version: '2'
|
69
125
|
- !ruby/object:Gem::Dependency
|
70
126
|
name: slack-poster
|
71
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,6 +158,7 @@ extensions: []
|
|
102
158
|
extra_rdoc_files: []
|
103
159
|
files:
|
104
160
|
- bin/aws_cleaner.rb
|
161
|
+
- lib/aws_cleaner/aws_cleaner.rb
|
105
162
|
homepage: https://github.com/eheydrick/aws-cleaner
|
106
163
|
licenses:
|
107
164
|
- MIT
|
@@ -122,7 +179,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
122
179
|
version: '0'
|
123
180
|
requirements: []
|
124
181
|
rubyforge_project:
|
125
|
-
rubygems_version: 2.
|
182
|
+
rubygems_version: 2.6.6
|
126
183
|
signing_key:
|
127
184
|
specification_version: 4
|
128
185
|
summary: AWS Cleaner cleans up after EC2 instances are terminated
|