aws_ami_cleanup 0.1 → 1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: db5bf4d59de51127ee6dab8a547cce124a734dd1c628096e59509ea21dd572d4
4
- data.tar.gz: 5a6aa3840422b64a71be65ce11ac2a290e4e46a2e5f8730865537ce8676c3368
3
+ metadata.gz: fdb3d28f7c0eb4b2c6acd19468ff42990802239afed6d39d966bdf9e314af913
4
+ data.tar.gz: aec4c2d2bea2f67e295df587023c300075602037c093063d726e3a9dffe797b0
5
5
  SHA512:
6
- metadata.gz: 8f6000074b50a25f566478022a78a341b676a0fa10eb8cc7945043889035bf5b0b080bac0eede9748ce1886db13c0f92745f0fe2f0abe254acc2a80d93f95f16
7
- data.tar.gz: 212429abd100adba8cf1be8cbda5a322237a5114ffba2114b3266bce54e1be56d5f1a1dad184f1d2a5245b9713f039063ab2c33f6359a3d506f1d0b3769fadf3
6
+ metadata.gz: 00bc9351ee496669abbc4e5c0bb66c6ece7c7ad4f71ea3e1607785fa9f4a2890066d9d94cffc10c5b998cb99afa17ad0bf2535cc305e7655303f40151a668e2e
7
+ data.tar.gz: 3c2741cb1ae825e8ee0e6433914635839415c8365f2fdb5244e8c6a7c5d9fcfb99c8aa83f95a2936ef79a6c058e580d726dd1e36f88efc51441279eaedad374f
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- ruby-2.6.6
1
+ ruby-3.1.2
data/README.md CHANGED
@@ -8,6 +8,7 @@ This gem provides the `cleanup_amis` script that allows deregistering unused AMI
8
8
  - ec2:DeregisterImage
9
9
  - ec2:DeleteSnapshot
10
10
  - autoscaling:DescribeAutoScalingGroups
11
+ - autoscaling:DescribeLaunchConfigurations
11
12
 
12
13
  Script should be invoked as follows:
13
14
 
@@ -17,4 +18,9 @@ cleanup_amis clean_amis --ami_name 'my-ami' --ami_owner 'self'
17
18
 
18
19
  Where `ami_owner` can be a combination of AWS account IDs, `self`, `amazon`, and `aws-marketplace`.
19
20
 
20
- Additionally you can provide the `number_of_amis_to_keep` argument to specify how many AMIs to keep (default is 3) and `region` for the AWS region (default is `us-east-1`).
21
+ Additionally you can provide the following arguments:
22
+
23
+ - `number_of_amis_to_keep` to specify how many AMIs to keep (default is 3).
24
+ - `region` for the AWS region (default is `us-east-1`).
25
+ - `dry_run` for running without deleting any resources in AWS.
26
+ - `skip_image_under_use_verification` for skipping verification on whether the AMI is being used by any auto scaling group or reserved EC2 instance.
@@ -26,5 +26,5 @@ Gem::Specification.new do |s|
26
26
  s.add_runtime_dependency "aws-sdk-ec2", "~> 1"
27
27
  s.add_runtime_dependency "aws-sdk-autoscaling", "~> 1"
28
28
  s.add_runtime_dependency "thor", "~> 1"
29
- s.add_development_dependency("byebug", "~> 11")
29
+ s.add_development_dependency("debug")
30
30
  end
@@ -7,21 +7,41 @@ module AwsAmiCleanup
7
7
  class CleanupAmis
8
8
  DEFAULT_NUMBER_OF_AMIS_TO_KEEP = 3
9
9
 
10
- attr_accessor :region, :number_of_amis_to_keep
10
+ attr_accessor :region, :number_of_amis_to_keep, :skip_image_under_use_verification
11
11
 
12
- def initialize(region, number_of_amis_to_keep)
12
+ def initialize(region, number_of_amis_to_keep, skip_image_under_use_verification:, assume_role_for_querying_state:, aws_role_for_querying_state:)
13
13
  @region = region
14
14
 
15
15
  @number_of_amis_to_keep = number_of_amis_to_keep || DEFAULT_NUMBER_OF_AMIS_TO_KEEP
16
16
  if number_of_amis_to_keep <= 0
17
17
  raise 'Number of AMIs to keep must be higher than 0.'
18
18
  end
19
+
20
+ @skip_image_under_use_verification = skip_image_under_use_verification
21
+ @assume_role_for_querying_state = assume_role_for_querying_state
22
+
23
+ if @skip_image_under_use_verification && @assume_role_for_querying_state
24
+ raise 'Cannot include skip image under use verification and assume role for querying state options'
25
+ end
26
+
27
+ if @assume_role_for_querying_state
28
+ raise "Must include the IAM role's ARN to assume if using a different role for querying state" if aws_role_for_querying_state.nil?
29
+ @aws_role_for_querying_state = aws_role_for_querying_state
30
+ end
19
31
  end
20
32
 
21
- def execute!(ami_name:, ami_owner:)
33
+ def execute!(ami_name:, ami_owner:, dry_run:)
34
+ puts "RUNNING IN DRY MODE." if dry_run
35
+
22
36
  potential_amis_to_remove = amis(ami_name, ami_owner)
23
37
  ami_ids = potential_amis_to_remove.collect(&:image_id)
24
- ami_ids_to_remove = ami_ids - amis_in_use
38
+
39
+ if skip_image_under_use_verification
40
+ ami_ids_to_remove = ami_ids
41
+ else
42
+ ami_ids_to_remove = ami_ids - amis_in_use
43
+ end
44
+
25
45
  potential_amis_to_remove.keep_if {|a| ami_ids_to_remove.include?(a.image_id) }
26
46
 
27
47
  if potential_amis_to_remove.count > number_of_amis_to_keep
@@ -29,11 +49,18 @@ module AwsAmiCleanup
29
49
  amis_to_keep = potential_amis_to_remove[0..(number_of_amis_to_keep-1)]
30
50
 
31
51
  puts "Deregistering old AMIs..."
52
+
32
53
  amis_to_remove.each do |ami|
33
54
  ebs_mappings = ami.block_device_mappings
34
55
  puts "Deregistering #{ami.image_id}"
35
- ami.deregister
36
- delete_ami_snapshots(ebs_mappings)
56
+
57
+ begin
58
+ ec2_client_for_cleanup.deregister_image(image_id: ami.image_id, dry_run: dry_run)
59
+ rescue Aws::EC2::Errors::DryRunOperation
60
+ # When running in dry mode, EC2 raises this exception if operation would have succeeded, we catch them so the full process can run
61
+ end
62
+
63
+ delete_ami_snapshots(ebs_mappings, dry_run)
37
64
  end
38
65
 
39
66
  puts "Currently active AMIs..."
@@ -47,12 +74,40 @@ module AwsAmiCleanup
47
74
 
48
75
  protected
49
76
 
50
- def ec2
77
+ def ec2_client_for_query_state
78
+ return @__ec2_client_for_query_state if defined?(@__ec2_client_for_query_state)
79
+
80
+ @__ec2_client_for_query_state =
81
+ if @assume_role_for_querying_state
82
+ role_credentials = Aws::AssumeRoleCredentials.new(
83
+ role_arn: @aws_role_for_querying_state,
84
+ role_session_name: 'ami-cleanup',
85
+ region: region
86
+ )
87
+ Aws::EC2::Client.new(credentials: role_credentials, region: region)
88
+ else
89
+ ec2_client_for_cleanup
90
+ end
91
+ end
92
+
93
+ def ec2_client_for_cleanup
51
94
  @__ec2 ||= Aws::EC2::Client.new(region: region)
52
95
  end
53
96
 
54
97
  def auto_scaling
55
- @__auto_scaling ||= Aws::AutoScaling::Client.new(region: region)
98
+ return @__auto_scaling if defined?(@__auto_scaling)
99
+
100
+ @__auto_scaling =
101
+ if @aws_role_for_querying_state
102
+ role_credentials = Aws::AssumeRoleCredentials.new(
103
+ role_arn: @aws_role_for_querying_state,
104
+ role_session_name: 'ami-cleanup',
105
+ region: region
106
+ )
107
+ Aws::AutoScaling::Client.new(credentials: role_credentials, region: region)
108
+ else
109
+ Aws::AutoScaling::Client.new(region: region)
110
+ end
56
111
  end
57
112
 
58
113
  def amis(ami_name, ami_owner)
@@ -60,7 +115,7 @@ module AwsAmiCleanup
60
115
 
61
116
  # Cannot lookup by Name tag because that's only available from the owner account.
62
117
  describe_images_params = { owners: [ ami_owner ] }
63
- all_images_from_owner = ec2.describe_images(describe_images_params).images
118
+ all_images_from_owner = ec2_client_for_query_state.describe_images(describe_images_params).images
64
119
  name_matching_images = all_images_from_owner.filter {|i| i.name.match?(ami_name) }
65
120
 
66
121
  @__amis = sort_by_created_at(name_matching_images)
@@ -80,11 +135,11 @@ module AwsAmiCleanup
80
135
  launch_template_ids = autoscaling_groups.reject {|asg| asg.launch_template.nil? }
81
136
  .collect {|asg| asg.launch_template.launch_template_id }
82
137
  launch_template_ids.each do |launch_template_id|
83
- image_ids << ec2.describe_launch_template_versions(launch_template_id: launch_template_id, max_results: 1)
84
- .launch_template_versions
85
- .first
86
- .launch_template_data
87
- .image_id
138
+ image_ids << ec2_client_for_query_state.describe_launch_template_versions(launch_template_id: launch_template_id, max_results: 1)
139
+ .launch_template_versions
140
+ .first
141
+ .launch_template_data
142
+ .image_id
88
143
  end
89
144
 
90
145
  # Find AMIs used by auto scaling groups with launch configurations
@@ -94,21 +149,24 @@ module AwsAmiCleanup
94
149
  image_ids += launch_configurations.map(&:image_id)
95
150
 
96
151
  # Finally, find AMIs used by instances not belonging to auto scaling groups
97
- ec2_reservations = ec2.describe_instances
152
+ ec2_reservations = ec2_client_for_query_state.describe_instances
98
153
  image_ids += ec2_reservations.reservations.collect {|res| res.instances.map(&:image_id) }.flatten
99
154
 
100
155
  image_ids.flatten
101
156
  end
102
157
 
103
- def delete_ami_snapshots(ebs_mappings)
158
+ def delete_ami_snapshots(ebs_mappings, dry_run)
104
159
  ebs_mappings.each do |ebs_mapping|
105
160
  # Skip ephimeral block devices
106
161
  next if ebs_mapping.ebs.nil? || ebs_mapping.ebs.snapshot_id.nil?
107
162
 
108
163
  snapshot_id = ebs_mapping.ebs.snapshot_id
109
164
  puts "Deleting snapshot #{snapshot_id}"
110
- snapshot = Aws::EC2::Snapshot.new(snapshot_id)
111
- snapshot.delete
165
+ begin
166
+ ec2_client_for_cleanup.delete_snapshot(snapshot_id: snapshot_id, dry_run: dry_run)
167
+ rescue Aws::EC2::Errors::DryRunOperation
168
+ # When running in dry mode, EC2 raises this exception if operation would have succeeded, we catch them so the full process can run
169
+ end
112
170
  end
113
171
  end
114
172
  end
@@ -5,18 +5,30 @@ module AwsAmiCleanup
5
5
  desc "clean_amis", "delete unused AMIs owned by ami_owner with ami_name name"
6
6
  option :ami_name, required: true
7
7
  option :ami_owner, required: true
8
- option :number_of_amis_to_keep, required: false
8
+ option :number_of_amis_to_keep, required: true
9
+ option :assume_role_for_querying_state, type: :boolean, required: false
10
+ option :aws_role_for_querying_state, required: false
11
+ option :dry_run, type: :boolean, required: false
9
12
  option :region, required: false
13
+ option :skip_verification, type: :boolean, required: false
10
14
  def clean_amis
11
- cleanup_amis = AwsAmiCleanup::CleanupAmis.new(region, options[:number_of_amis_to_keep]&.to_i)
15
+ cleanup_amis = AwsAmiCleanup::CleanupAmis.new(
16
+ region,
17
+ options[:number_of_amis_to_keep]&.to_i,
18
+ skip_image_under_use_verification: options[:skip_verification],
19
+ assume_role_for_querying_state: options[:assume_role_for_querying_state],
20
+ aws_role_for_querying_state: options[:aws_role_for_querying_state]
21
+ )
12
22
 
13
- cleanup_amis.execute!(ami_name: options[:ami_name], ami_owner: options[:ami_owner])
23
+ cleanup_amis.execute!(ami_name: options[:ami_name],
24
+ ami_owner: options[:ami_owner],
25
+ dry_run: options[:dry_run])
14
26
  end
15
27
 
16
28
  desc "console", "interactive session"
17
29
  def console
18
- require 'byebug'
19
- byebug
30
+ require 'debug'
31
+ debugger
20
32
  end
21
33
 
22
34
  protected
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AwsAmiCleanup
4
- VERSION = "0.1"
4
+ VERSION = "1.1"
5
5
  end
6
6
 
metadata CHANGED
@@ -1,11 +1,11 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws_ami_cleanup
3
3
  version: !ruby/object:Gem::Version
4
- version: '0.1'
4
+ version: '1.1'
5
5
  platform: ruby
6
6
  authors:
7
7
  - Diego Marcet
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
  date: 2021-02-19 00:00:00.000000000 Z
@@ -53,20 +53,20 @@ dependencies:
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1'
55
55
  - !ruby/object:Gem::Dependency
56
- name: byebug
56
+ name: debug
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - "~>"
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: '11'
61
+ version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - "~>"
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
- version: '11'
69
- description:
68
+ version: '0'
69
+ description:
70
70
  email: diego@controlshiftlabs.com
71
71
  executables:
72
72
  - cleanup_amis
@@ -88,7 +88,7 @@ homepage: http://github.com/controlshift/aws_ami_cleanup
88
88
  licenses:
89
89
  - MIT
90
90
  metadata: {}
91
- post_install_message:
91
+ post_install_message:
92
92
  rdoc_options: []
93
93
  require_paths:
94
94
  - lib
@@ -103,8 +103,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
103
103
  - !ruby/object:Gem::Version
104
104
  version: '0'
105
105
  requirements: []
106
- rubygems_version: 3.0.8
107
- signing_key:
106
+ rubygems_version: 3.3.19
107
+ signing_key:
108
108
  specification_version: 4
109
109
  summary: Script for deleting obsolete AMIs
110
110
  test_files: []