Update 2016-04-28: I’ve written an updated version of the script below that offers a graphical interface for managing AMIs. Of course, the script below still works.
Recently, I wrote a PowerShell script that uses an EC2 instance’s Name tag to create an Amazon Machine Image (AMI) of that running instance. This post is about a bookend script to that one: the PowerShell script below deletes an EBS-backed AMI and all its associated S3 snapshots.
When you create an AMI, AWS creates a S3 snapshot of all of the instance’s EBS volumes. These snapshots (which are deltas of any previously existing snapshots, thereby saving on overall storage) are associated with the AMI that is created. When the AMI is launched as an instance, those snapshots are then used to re-create the EBS volumes of the original instance at that instance’s mount points and with all the data on the volume as of the date and time of the snapshot.
It’s all very cool. And I, like many AWS architects, live or die in my client engagements by how frequently I have an AMI to rollback to. At my current gig, I manage more than 35 EC2 instances, some containing terabytes of data. Just last week an AMI of a development environment I’d taken before an upgrade saved my bacon when the client suddenly decided to rollback that major upgrade.
But there’s a catch: when you delete (or as AWS calls it, “deregister”) an AMI, the snapshots are left behind. The AWS documentation describes this and recommends that you clean up after yourself. But they don’t make it easy. Their recommended procedure for removing leftover S3 snapshots has two really nasty flaws.
First, the AWS procedure for EBS-backed instance cleanup assumes you will do the cleanup right away. The problem is that if you do not record the name of the deregistered AMI and decide to come back later to cleanup the snapshots, you will have trouble finding them. The snapshots still have an ImageID set in their properties but the AMI itself has probably disappeared from the console. In any case, you are responsible for maintaining the link between the (now gone) AMI and the associated snapshots. IMO, this is very nasty and AWS should have fixed it a long time ago. It’s too manual and prone to error.
The second flaw is the one my other script corrects: when a snapshot is created for any given AMI its Name tag is left blank. That means if you deregister the AMI intending to come back later to delete the snapshots and you lose the AMI ID, you will have a hard time searching for them by anything other than the deleted AMIs ImageID. This is also something AWS should fix — or you can simply adapt my AMI-creation script to your needs to add tags to both the AMI itself and its associated snapshots. That way, if you delete the AMI but not the snapshots, you will have meaningful Name tags to search for snapshots to be deleted.
Unlike that script — which I struggled to write — the one below was a breeze. It’s actually just two simple AWS PowerShell cmdlet calls wrapped in a couple of foreach loops plus some ham-handed confirmation dialogs. This script is designed to be run from the command line and thus requires the AMI IDs to be passed as command line parameters.
The entire script is below. Use the controls at the top of the code window to expand the window, copy the code , open it in a separate window or wrap the code in the code window. One other thing: the script assumes you have set up your AWS credentials in a profile that’s accessible to your PowerShell environment.
I hope you find this script useful and look forward to your feedback. If you’re a PowerShell guru, you can probably tell I’m still a relative newbie so any comments on style would be very much appreciated.
<# .SYNOPSIS De-register AWS AMIs and cleanup (remove) S3 snapshots associated with the de-registered AMIs .DESCRIPTION Calls Get-EC2Image with supplied AMIs to obtain array of associated snapshots; de-registers (deletes) AMIs via Unregister-EC2Image and then removes snapshots via Remove-EC2Snapshot .USAGE .\RemoveAMIandCleanupAssociatedSnapshots.ps1 -$amis "ami-12345678", "ami-87654321", ... .NOTES A very simple script with little error checking but some "chattiness" with respect to confirmations. Note that if you wanted to avoid prompts confirming snapshot deletion, you could add -Force to Remove-EC2Snapshot .AUTHOR Alex Neihaus 2014-10-28 .LICENSE (c) Air11 Technology LLC 2014 Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. #> param( [Parameter(Mandatory=$true)][string[] ]$amis) # Insist on at least one AMI id $array = @($amis) Write-Host "The following AMIs will be deleted along with associated snapshots: $array" $title = 'Are you sure?' $prompt = '[C]ontinue or [E]xit?' $continue = New-Object System.Management.Automation.Host.ChoiceDescription '&Continue','Continues' $exit = New-Object System.Management.Automation.Host.ChoiceDescription '&Exit','Exits' $options = [System.Management.Automation.Host.ChoiceDescription[]] ($continue,$exit) $choice = $host.ui.PromptForChoice($title,$prompt,$options,0) If ($choice -eq 1) { Write-Host "Exited" Exit } # End if foreach ($ami in $array) { $ami = Get-EC2Image -ImageId $ami $snapshots = @($ami.BlockDeviceMapping.ebs.snapshotid) Unregister-EC2Image -ImageId $ami.ImageId # Snapshots of root volumes cannot be deleted unless the AMI is deregistered first Write-Host $ami.ImageId "Unregistered" foreach ($SnapshotID in $snapshots) { Remove-EC2Snapshot $SnapshotID # Delete leftover snapshots Write-Host $SnapshotID "Removed" } # End foreach $snapshots } # End foreach $ami
Leave a Reply