aws-cleanup 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/.gitignore +2 -1
- data/.rubocop.yml +6 -0
- data/Gemfile.lock +45 -0
- data/exe/aws-cleanup +1 -1
- data/lib/aws-cleanup.rb +13 -102
- data/lib/aws-cleanup/version.rb +1 -1
- data/lib/modules/cloudwatch.rb +64 -0
- data/lib/modules/instances.rb +67 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02e9500fcca4dfdde54f6f7192d98edcccf7535f
|
4
|
+
data.tar.gz: 7dc4b26dd7fbffdcae6525927dda09e5e5d01059
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 929a7bf9ded486e1769500f32453c263f417275d3f9a4c2612898621260172116f6077418822fea70b99ffe85393632c752690c5c0964658cf552acf58d694d4
|
7
|
+
data.tar.gz: 8c0609881fe5016af4922830c7e2ab731811a8d2d33648ad9a68d99b4280d30e38fcf469f19568cc300941e7adc3a0e7001b8e9c9ef4d8a2b28ab7a5e8751ce1
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
aws-cleanup (1.0.1)
|
5
|
+
aws-sdk
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
aws-sdk (2.9.16)
|
11
|
+
aws-sdk-resources (= 2.9.16)
|
12
|
+
aws-sdk-core (2.9.16)
|
13
|
+
aws-sigv4 (~> 1.0)
|
14
|
+
jmespath (~> 1.0)
|
15
|
+
aws-sdk-resources (2.9.16)
|
16
|
+
aws-sdk-core (= 2.9.16)
|
17
|
+
aws-sigv4 (1.0.0)
|
18
|
+
diff-lcs (1.3)
|
19
|
+
jmespath (1.3.1)
|
20
|
+
rake (10.5.0)
|
21
|
+
rspec (3.6.0)
|
22
|
+
rspec-core (~> 3.6.0)
|
23
|
+
rspec-expectations (~> 3.6.0)
|
24
|
+
rspec-mocks (~> 3.6.0)
|
25
|
+
rspec-core (3.6.0)
|
26
|
+
rspec-support (~> 3.6.0)
|
27
|
+
rspec-expectations (3.6.0)
|
28
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
+
rspec-support (~> 3.6.0)
|
30
|
+
rspec-mocks (3.6.0)
|
31
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
32
|
+
rspec-support (~> 3.6.0)
|
33
|
+
rspec-support (3.6.0)
|
34
|
+
|
35
|
+
PLATFORMS
|
36
|
+
ruby
|
37
|
+
|
38
|
+
DEPENDENCIES
|
39
|
+
aws-cleanup!
|
40
|
+
bundler (~> 1.13)
|
41
|
+
rake (~> 10.0)
|
42
|
+
rspec (~> 3.0)
|
43
|
+
|
44
|
+
BUNDLED WITH
|
45
|
+
1.13.3
|
data/exe/aws-cleanup
CHANGED
data/lib/aws-cleanup.rb
CHANGED
@@ -5,100 +5,27 @@ class AwsCleanup
|
|
5
5
|
TEST_INSTANCE_EXPIRE_AGE = (3_600 * 24).freeze
|
6
6
|
TEST_GROUP_ID = 'sg-1e804874'.freeze
|
7
7
|
TEST_GROUP_NAME = 'ci-testing'.freeze
|
8
|
+
DELETE_LIMIT = 10
|
8
9
|
|
9
|
-
def self.run
|
10
|
-
AwsCleanup.new.run
|
10
|
+
def self.run(resource)
|
11
|
+
AwsCleanup.new.run resource
|
11
12
|
end
|
12
13
|
|
13
|
-
def run
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def cleanup_instances
|
21
|
-
eii = expired_instances_ids
|
22
|
-
return unless eii.any?
|
23
|
-
puts 'Deleting instances: ' + eii.join(', ')
|
24
|
-
ec2.terminate_instances instance_ids: eii
|
25
|
-
end
|
26
|
-
|
27
|
-
def cleaup_alarms
|
28
|
-
oa = orphaned_alarms.map(&:alarm_name)
|
29
|
-
return unless oa.any?
|
30
|
-
puts 'Deleting alarms: ' + oa.join(', ')
|
31
|
-
cloudwatch.delete_alarms alarm_names: oa
|
32
|
-
end
|
33
|
-
|
34
|
-
def orphaned_alarms
|
35
|
-
insufficient_data_alarms.select do |alarm|
|
36
|
-
alarm.dimensions.any? &&
|
37
|
-
!alarm.dimensions.find { |dimension| dimension_in_use? dimension }
|
14
|
+
def run(resource = nil)
|
15
|
+
if resource
|
16
|
+
require "#{resource}-cleanup"
|
17
|
+
AwsCleanup.const_get("#{resource.capitalize}Cleanup").run
|
18
|
+
return
|
38
19
|
end
|
39
|
-
end
|
40
20
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
when 'QueueName'
|
46
|
-
queue_names.include? dimension.value
|
47
|
-
when 'DBInstanceIdentifier'
|
48
|
-
db_names.include? dimension.value
|
49
|
-
else
|
50
|
-
puts "Unsupported dimension: #{dimension.name}"
|
51
|
-
true
|
21
|
+
Dir.glob(File.dirname(File.absolute_path __FILE__) + '/modules/*').each do |resource_file|
|
22
|
+
require resource_file
|
23
|
+
class_name = "#{File.basename(resource_file).sub('.rb', '').capitalize}Cleanup"
|
24
|
+
AwsCleanup.const_get(class_name).run
|
52
25
|
end
|
53
26
|
end
|
54
27
|
|
55
|
-
|
56
|
-
@queue_names ||= sqs.list_queues.queue_urls.map { |q| URI(q).path.split('/')[2..-1].join('/') }
|
57
|
-
end
|
58
|
-
|
59
|
-
def db_names
|
60
|
-
@db_names ||= rds.describe_db_instances.db_instances.map(&:db_instance_identifier)
|
61
|
-
end
|
62
|
-
|
63
|
-
def expired_instances_ids
|
64
|
-
expired_instances.map(&:instance_id)
|
65
|
-
end
|
66
|
-
|
67
|
-
def expired_instances
|
68
|
-
expired_test_instances | instances_expired_by_tag
|
69
|
-
end
|
70
|
-
|
71
|
-
def expired_test_instances
|
72
|
-
test_instances.select { |instance| expired_age? TEST_INSTANCE_EXPIRE_AGE, instance.launch_time }
|
73
|
-
end
|
74
|
-
|
75
|
-
def test_instances
|
76
|
-
instances.select do |instance|
|
77
|
-
instance.security_groups.find do |sg|
|
78
|
-
sg.group_name == TEST_GROUP_NAME || sg.group_id == TEST_GROUP_ID
|
79
|
-
end ||
|
80
|
-
instance.tags.find { |t| t.key == 'Type' && t.value == 'test' }
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def instances_expired_by_tag
|
85
|
-
instances.select do |instance|
|
86
|
-
instance.tags.find do |t|
|
87
|
-
(t.key == 'expire_after' && expired_age?(t.value, instance.launch_time)) ||
|
88
|
-
(t.key == 'expires' && expired_time?(t.value))
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def expired_age?(secs, launch_time)
|
94
|
-
Time.now > (launch_time + secs)
|
95
|
-
end
|
96
|
-
|
97
|
-
def expired_time?(timestamp)
|
98
|
-
# `timestamp` should be a string in this format:
|
99
|
-
# 2017-05-10 13:04:01 -0400
|
100
|
-
Time.now > Time.parse(timestamp)
|
101
|
-
end
|
28
|
+
private
|
102
29
|
|
103
30
|
def instance_ids
|
104
31
|
instances.map(&:instance_id)
|
@@ -111,23 +38,7 @@ class AwsCleanup
|
|
111
38
|
).reservations.map(&:instances).flatten
|
112
39
|
end
|
113
40
|
|
114
|
-
def insufficient_data_alarms
|
115
|
-
cloudwatch.describe_alarms(state_value: 'INSUFFICIENT_DATA').metric_alarms
|
116
|
-
end
|
117
|
-
|
118
|
-
def cloudwatch
|
119
|
-
@cloudwatch ||= Aws::CloudWatch::Client.new
|
120
|
-
end
|
121
|
-
|
122
41
|
def ec2
|
123
42
|
@ec2 ||= Aws::EC2::Client.new
|
124
43
|
end
|
125
|
-
|
126
|
-
def sqs
|
127
|
-
@sqs ||= Aws::SQS::Client.new
|
128
|
-
end
|
129
|
-
|
130
|
-
def rds
|
131
|
-
@rds ||= Aws::RDS::Client.new
|
132
|
-
end
|
133
44
|
end
|
data/lib/aws-cleanup/version.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
class CloudwatchCleanup < AwsCleanup
|
2
|
+
def self.run
|
3
|
+
CloudwatchCleanup.new.cleaup_alarms
|
4
|
+
end
|
5
|
+
|
6
|
+
def cleaup_alarms
|
7
|
+
oa = orphaned_alarms.map(&:alarm_name)
|
8
|
+
|
9
|
+
if oa.any?
|
10
|
+
puts 'Deleting alarms: ' + oa.join(', ')
|
11
|
+
cloudwatch.delete_alarms alarm_names: oa
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
puts 'No alarms to clean up'
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def orphaned_alarms
|
21
|
+
insufficient_data_alarms.select do |alarm|
|
22
|
+
alarm.dimensions.any? &&
|
23
|
+
!alarm.dimensions.find { |dimension| dimension_in_use? dimension }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def dimension_in_use?(dimension)
|
28
|
+
case dimension.name
|
29
|
+
when 'InstanceId'
|
30
|
+
instance_ids.include? dimension.value
|
31
|
+
when 'QueueName'
|
32
|
+
queue_names.include? dimension.value
|
33
|
+
when 'DBInstanceIdentifier'
|
34
|
+
db_names.include? dimension.value
|
35
|
+
else
|
36
|
+
puts "Unsupported dimension: #{dimension.name}"
|
37
|
+
true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def db_names
|
42
|
+
@db_names ||= rds.describe_db_instances.db_instances.map(&:db_instance_identifier)
|
43
|
+
end
|
44
|
+
|
45
|
+
def queue_names
|
46
|
+
@queue_names ||= sqs.list_queues.queue_urls.map { |q| URI(q).path.split('/')[2..-1].join('/') }
|
47
|
+
end
|
48
|
+
|
49
|
+
def insufficient_data_alarms
|
50
|
+
cloudwatch.describe_alarms(state_value: 'INSUFFICIENT_DATA').metric_alarms
|
51
|
+
end
|
52
|
+
|
53
|
+
def cloudwatch
|
54
|
+
@cloudwatch ||= Aws::CloudWatch::Client.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def sqs
|
58
|
+
@sqs ||= Aws::SQS::Client.new
|
59
|
+
end
|
60
|
+
|
61
|
+
def rds
|
62
|
+
@rds ||= Aws::RDS::Client.new
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
class InstancesCleanup < AwsCleanup
|
2
|
+
def self.run
|
3
|
+
InstancesCleanup.new.cleanup_instances
|
4
|
+
end
|
5
|
+
|
6
|
+
def cleanup_instances
|
7
|
+
eii = expired_instances_ids
|
8
|
+
if eii.any?
|
9
|
+
prompt_user eii if eii.count > DELETE_LIMIT
|
10
|
+
puts 'Deleting instances: ' + eii.join(', ')
|
11
|
+
ec2.terminate_instances instance_ids: eii
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
puts 'No instances to clean up'
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def prompt_user(eii)
|
21
|
+
puts "WARNING: The following #{eii.count} instances will be terminated."
|
22
|
+
print 'Are you sure? '
|
23
|
+
return if %w(y ye yes).include? gets.strip
|
24
|
+
puts 'Aborted'
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
def expired_instances_ids
|
29
|
+
expired_instances.map(&:instance_id)
|
30
|
+
end
|
31
|
+
|
32
|
+
def expired_instances
|
33
|
+
expired_test_instances | instances_expired_by_tag
|
34
|
+
end
|
35
|
+
|
36
|
+
def expired_test_instances
|
37
|
+
test_instances.select { |instance| expired_age? TEST_INSTANCE_EXPIRE_AGE, instance.launch_time }
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_instances
|
41
|
+
instances.select do |instance|
|
42
|
+
instance.security_groups.find do |sg|
|
43
|
+
sg.group_name == TEST_GROUP_NAME || sg.group_id == TEST_GROUP_ID
|
44
|
+
end ||
|
45
|
+
instance.tags.find { |t| t.key == 'Type' && t.value == 'test' }
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def instances_expired_by_tag
|
50
|
+
instances.select do |instance|
|
51
|
+
instance.tags.find do |t|
|
52
|
+
(t.key == 'expire_after' && expired_age?(t.value, instance.launch_time)) ||
|
53
|
+
(t.key == 'expires' && expired_time?(t.value))
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def expired_age?(secs, launch_time)
|
59
|
+
Time.now > (launch_time + secs)
|
60
|
+
end
|
61
|
+
|
62
|
+
def expired_time?(timestamp)
|
63
|
+
# `timestamp` should be a string in this format:
|
64
|
+
# 2017-05-10 13:04:01 -0400
|
65
|
+
Time.now > Time.parse(timestamp)
|
66
|
+
end
|
67
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: aws-cleanup
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Herot
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: aws-sdk
|
@@ -79,6 +79,7 @@ files:
|
|
79
79
|
- ".rubocop.yml"
|
80
80
|
- ".travis.yml"
|
81
81
|
- Gemfile
|
82
|
+
- Gemfile.lock
|
82
83
|
- LICENSE.txt
|
83
84
|
- README.md
|
84
85
|
- Rakefile
|
@@ -88,6 +89,8 @@ files:
|
|
88
89
|
- exe/aws-cleanup
|
89
90
|
- lib/aws-cleanup.rb
|
90
91
|
- lib/aws-cleanup/version.rb
|
92
|
+
- lib/modules/cloudwatch.rb
|
93
|
+
- lib/modules/instances.rb
|
91
94
|
homepage: https://github.com/evertrue/aws-cleanup
|
92
95
|
licenses:
|
93
96
|
- Apache License 2.0
|