Clean up AMI and related snapshots #8
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,3 +1,4 @@
|
||||||
|
*.retry
|
||||||
.vagrant
|
.vagrant
|
||||||
vagrant-ssh-config
|
vagrant-ssh-config
|
||||||
package_updates/roles/debian-update
|
package_updates/roles/debian-update
|
||||||
|
|
140
cleanup_ami_snapshots/README.md
Normal file
140
cleanup_ami_snapshots/README.md
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
# Ansible playbook to remove oldest AMI and attached snapshots
|
||||||
|
|
||||||
|
Tested with Ansible version: 2.5.4
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
This playbook needs the Python AWS SDK installed (both boto & boto3)
|
||||||
|
|
||||||
|
```
|
||||||
|
sudo pip install boto boto3
|
||||||
|
# or
|
||||||
|
pip install --user boto boto3
|
||||||
|
# or use pipenv for a virtualenv setup..
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
- enable_debug: True / False (prints some info about registered variables)
|
||||||
|
- aws_profile: the AWS profile name
|
||||||
|
- log_destination: path to the file where actions will be logged.
|
||||||
|
- ami_tag: AMI's with given tag will be filtered out. The oldest is then removed
|
||||||
|
|
||||||
|
## AWS authentication
|
||||||
|
### AWS profiles
|
||||||
|
In this example we create an aws profile with the name `aws-ansible`.
|
||||||
|
|
||||||
|
Create an AWS profile by editing `~/.aws/credentials` and add the following
|
||||||
|
stanza:
|
||||||
|
```
|
||||||
|
[aws-ansible]
|
||||||
|
aws_access_key_id = ***
|
||||||
|
aws_secret_access_key = ***
|
||||||
|
region = eu-west-1
|
||||||
|
```
|
||||||
|
|
||||||
|
Set the Playbook variable `aws_profile` to the name of this profile
|
||||||
|
|
||||||
|
example:
|
||||||
|
```
|
||||||
|
vars:
|
||||||
|
aws_profile: aws-ansible
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
In the `test` folder of this repository you can find an Ansible playbook that
|
||||||
|
creates some test AMI's.
|
||||||
|
|
||||||
|
- AMI-001 (oldest)
|
||||||
|
- AMI-002
|
||||||
|
- AMI-003 (newest)
|
||||||
|
|
||||||
|
When running the cleanup playbook AMI-001 should be removed first. On subsequent runs AMI-002 should be removed and then AMI-003.
|
||||||
|
If no AMI's with the tag `DestroyImage: true` are available. The playbook skips
|
||||||
|
all tasks.
|
||||||
|
|
||||||
|
When AMI's with multiple snapshots are deregistered, all the attached snapshots
|
||||||
|
will be deleted.
|
||||||
|
|
||||||
|
**NOTE:** The deregistration of AMI's takes some time. So subsequent
|
||||||
|
runs of the cleanup playbook short after each other will result in the playbook
|
||||||
|
trying to deregister and delete snapshots of the same AMI. This should be an
|
||||||
|
idempotent action.
|
||||||
|
|
||||||
|
This is not the case if AMI's are tagged
|
||||||
|
|
||||||
|
## Cleanup Playbook
|
||||||
|
### prerequisites
|
||||||
|
The Playbook requires that you set the `AWS_REGION` environment variable because
|
||||||
|
some modules used in this playbook require this even if it's set in the aws
|
||||||
|
profile.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
export AWS_REGION=eu-west-1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Run the Playbook
|
||||||
|
```
|
||||||
|
$ ansible-playbook playbook.yaml
|
||||||
|
|
||||||
|
PLAY [Remove the oldest AMI and associated snapshots] **************************************************************************************
|
||||||
|
|
||||||
|
TASK [Gathering Facts] *********************************************************************************************************************
|
||||||
|
ok: [localhost]
|
||||||
|
|
||||||
|
TASK [Register the AWS_REGION environment variable.] ***************************************************************************************
|
||||||
|
ok: [localhost]
|
||||||
|
|
||||||
|
TASK [Fail if the AWs_REGION environemtn var is not set] ***********************************************************************************
|
||||||
|
skipping: [localhost]
|
||||||
|
|
||||||
|
TASK [Gather facts about all AMIs with given tag ] *****************************************************************************************
|
||||||
|
ok: [localhost]
|
||||||
|
|
||||||
|
TASK [Check if log file already exists] ****************************************************************************************************
|
||||||
|
ok: [localhost]
|
||||||
|
|
||||||
|
TASK [Create log file] *********************************************************************************************************************
|
||||||
|
skipping: [localhost]
|
||||||
|
|
||||||
|
TASK [debug] *******************************************************************************************************************************
|
||||||
|
skipping: [localhost]
|
||||||
|
|
||||||
|
TASK [oldest ami] **************************************************************************************************************************
|
||||||
|
ok: [localhost]
|
||||||
|
|
||||||
|
TASK [debug] *******************************************************************************************************************************
|
||||||
|
skipping: [localhost]
|
||||||
|
|
||||||
|
TASK [Deregister AMI.] *********************************************************************************************************************
|
||||||
|
changed: [localhost]
|
||||||
|
|
||||||
|
TASK [LOG action] **************************************************************************************************************************
|
||||||
|
changed: [localhost]
|
||||||
|
|
||||||
|
TASK [Cleanup AMI snapshots] ***************************************************************************************************************
|
||||||
|
changed: [localhost] => (item={u'ebs': {u'encrypted': False, u'snapshot_id': u'snap-0b4d8ef6c1bc098d1', u'delete_on_termination': True, u'volume_type': u'gp2', u'volume_size': 8}, u'device_name': u'/dev/xvda'})
|
||||||
|
changed: [localhost] => (item={u'ebs': {u'encrypted': False, u'snapshot_id': u'snap-09c25bbe838912ced', u'delete_on_termination': True, u'volume_type': u'standard', u'volume_size': 8}, u'device_name': u'/dev/sdb'})
|
||||||
|
|
||||||
|
TASK [LOG action] **************************************************************************************************************************
|
||||||
|
changed: [localhost] => (item={u'ebs': {u'encrypted': False, u'snapshot_id': u'snap-0b4d8ef6c1bc098d1', u'delete_on_termination': True, u'volume_type': u'gp2', u'volume_size': 8}, u'device_name': u'/dev/xvda'})
|
||||||
|
changed: [localhost] => (item={u'ebs': {u'encrypted': False, u'snapshot_id': u'snap-09c25bbe838912ced', u'delete_on_termination': True, u'volume_type': u'standard', u'volume_size': 8}, u'device_name': u'/dev/sdb'})
|
||||||
|
|
||||||
|
PLAY RECAP *********************************************************************************************************************************
|
||||||
|
localhost : ok=9 changed=4 unreachable=0 failed=0
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
Info about the cleanup actions are kept in a log file (default:
|
||||||
|
/tmp/ansible-ami-cleanup.log)
|
||||||
|
|
||||||
|
```
|
||||||
|
2018-06-09T07:52:44Z AMI CLEANUP - Deregistered AMI: ami-577e7d2e
|
||||||
|
2018-06-09T07:52:44Z AMI CLEANUP - Removed snapshots: snap-00c90dc0cfa23ae75
|
||||||
|
2018-06-09T07:52:44Z AMI CLEANUP - Removed snapshots: snap-0ebfc8f7defefc968
|
||||||
|
2018-06-09T08:10:58Z AMI CLEANUP - Deregistered AMI: ami-f77f7c8e
|
||||||
|
2018-06-09T08:10:58Z AMI CLEANUP - Removed snapshots: snap-0b4d8ef6c1bc098d1
|
||||||
|
2018-06-09T08:10:58Z AMI CLEANUP - Removed snapshots: snap-09c25bbe838912ced
|
||||||
|
```
|
85
cleanup_ami_snapshots/cleanup-ami-snapshots.yaml
Normal file
85
cleanup_ami_snapshots/cleanup-ami-snapshots.yaml
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
- name: Remove the oldest AMI and associated snapshots
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: True
|
||||||
|
|
||||||
|
vars:
|
||||||
|
enable_debug: False
|
||||||
|
aws_profile: aws-ansible
|
||||||
|
log_destination: /tmp/ansible-ami-cleanup.log
|
||||||
|
ami_tag:
|
||||||
|
"tag:DestroyImage": 'true'
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Register the AWS_REGION environment variable.
|
||||||
|
set_fact:
|
||||||
|
aws_region_env_var: "{{ lookup('env', 'AWS_REGION') }}"
|
||||||
|
register: aws_region_env_var
|
||||||
|
|
||||||
|
- name: Fail if the AWs_REGION environemtn var is not set
|
||||||
|
fail:
|
||||||
|
msg: "The AWS_REGION environment variable is not set"
|
||||||
|
when: not aws_region_env_var
|
||||||
|
|
||||||
|
- name: Gather facts about all AMIs with given tag.
|
||||||
|
ec2_ami_facts:
|
||||||
|
profile: "{{ aws_profile }}"
|
||||||
|
owners: self
|
||||||
|
filters: "{{ ami_tag }}"
|
||||||
|
register: ami_list
|
||||||
|
|
||||||
|
- name: Check if log file already exists
|
||||||
|
stat:
|
||||||
|
path: "{{ log_destination }}"
|
||||||
|
register: logfile
|
||||||
|
|
||||||
|
- name: Create log file
|
||||||
|
file:
|
||||||
|
state: touch
|
||||||
|
path: "{{ log_destination }}"
|
||||||
|
when: logfile.stat.exists == False
|
||||||
|
|
||||||
|
- name: debug
|
||||||
|
debug:
|
||||||
|
msg: "{{ ami_list }}"
|
||||||
|
when: enable_debug
|
||||||
|
|
||||||
|
- name: oldest ami
|
||||||
|
set_fact:
|
||||||
|
oldest_ami: "{{ ami_list.images | sort(attribute='creation_date') | first}}"
|
||||||
|
when: ami_list.images
|
||||||
|
|
||||||
|
- name: debug
|
||||||
|
debug:
|
||||||
|
msg: "{{ oldest_ami }}"
|
||||||
|
when: enable_debug and ami_list.images
|
||||||
|
|
||||||
|
- name: Deregister AMI.
|
||||||
|
ec2_ami:
|
||||||
|
profile: "{{ aws_profile }}"
|
||||||
|
image_id: "{{ oldest_ami.image_id }}"
|
||||||
|
state: absent
|
||||||
|
# Bug in deleting snapshots : https://github.com/ansible/ansible/issues/39541
|
||||||
|
#delete_snapshot: yes
|
||||||
|
when: ami_list.images
|
||||||
|
|
||||||
|
- name: LOG action
|
||||||
|
lineinfile:
|
||||||
|
line: "{{ ansible_date_time.iso8601 }} AMI CLEANUP - Deregistered AMI: {{ oldest_ami.image_id }}"
|
||||||
|
dest: "{{ log_destination }}"
|
||||||
|
when: ami_list.images
|
||||||
|
|
||||||
|
- name: Cleanup AMI snapshots
|
||||||
|
ec2_snapshot:
|
||||||
|
profile: "{{ aws_profile }}"
|
||||||
|
snapshot_id: "{{ item.ebs.snapshot_id }}"
|
||||||
|
state: absent
|
||||||
|
with_items: "{{ oldest_ami.block_device_mappings }}"
|
||||||
|
when: ami_list.images
|
||||||
|
|
||||||
|
- name: LOG action
|
||||||
|
lineinfile:
|
||||||
|
line: "{{ ansible_date_time.iso8601 }} AMI CLEANUP - Removed snapshots: {{ item.ebs.snapshot_id }}"
|
||||||
|
dest: "{{ log_destination }}"
|
||||||
|
with_items: "{{ oldest_ami.block_device_mappings }}"
|
||||||
|
when: ami_list.images
|
50
cleanup_ami_snapshots/test/deploy_test.yaml
Normal file
50
cleanup_ami_snapshots/test/deploy_test.yaml
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
- name: Create test AMI's (this might take some time)
|
||||||
|
hosts: localhost
|
||||||
|
connection: local
|
||||||
|
gather_facts: True
|
||||||
|
|
||||||
|
vars:
|
||||||
|
aws_profile: aws-ansible
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: Register the AWS_REGION environment variable.
|
||||||
|
set_fact:
|
||||||
|
aws_region_env_var: "{{ lookup('env', 'AWS_REGION') }}"
|
||||||
|
register: aws_region_env_var
|
||||||
|
|
||||||
|
- name: Fail if the AWs_REGION environemtn var is not set
|
||||||
|
fail:
|
||||||
|
msg: "The AWS_REGION environment variable is not set"
|
||||||
|
when: not aws_region_env_var
|
||||||
|
|
||||||
|
- name: Create ec2 instance to create AMI's from
|
||||||
|
ec2_instance:
|
||||||
|
profile: "{{ aws_profile }}"
|
||||||
|
state: present
|
||||||
|
name: "ansible-test-instance"
|
||||||
|
image_id: ami-ca0135b3
|
||||||
|
volumes:
|
||||||
|
- device_name: "/dev/sdb"
|
||||||
|
ebs:
|
||||||
|
volume_size: 8
|
||||||
|
network:
|
||||||
|
assign_public_ip: false
|
||||||
|
tags:
|
||||||
|
MakeImage: 'true'
|
||||||
|
register: test_instance
|
||||||
|
|
||||||
|
- name: Create AMI's from instance
|
||||||
|
ec2_ami:
|
||||||
|
profile: "{{ aws_profile }}"
|
||||||
|
state: present
|
||||||
|
name: "AMI-00{{ item }}"
|
||||||
|
instance_id: "{{ test_instance.instance_ids[0] }}"
|
||||||
|
wait: yes
|
||||||
|
with_sequence: start=1 end=3
|
||||||
|
|
||||||
|
- name: Cleanup temp instance
|
||||||
|
ec2_instance:
|
||||||
|
profile: "{{ aws_profile }}"
|
||||||
|
state: terminated
|
||||||
|
filters:
|
||||||
|
instance-id: "{{ test_instance.instance_ids[0] }}"
|
Loading…
Reference in a new issue