Saturday, January 10, 2015

Setting AWS EC2 Instance Attribute DeleteOnTermination from .NET (C#)

Amazon gives us a great SDK to manage their AWS platform but sometimes a lack of documentation can make certain things difficult to find.  This one was not easily found for me online so I thought that I would share.

Each EC2 instance can have one or more volumes and, when attached, each of those volumes has a DeleteOnTermination attribute which determines whether or not AWS will delete your EBS Volume when you terminate your instance.  You can set this attribute when you create an instance (instructions) but once it's been created, you must use CLI, Powershell, or the SDK to change it.

This post will only cover setting this flag via the SDK and I've chosen to use C#.  Here are the prerequisites for the code seen here:

  • Visual Studio (I'm using 2013)
  • Download the AWS SDK for .NET.  There are also many other SDKs here.
  • Create a project using the provided project templates (installed via the SDK) or set a reference to the AWS SDK DLL in your existing project.  By default, the .NET 4.5 version is here:  C:\Program Files (x86)\AWS SDK for .NET\bin\Net45\AWSSDK.dll
  • Get your AWS Access Key and Secret key.  When you login to the AWS console, go to Identity and Access Management (IAM) and you can generate keys for each user.  You can't retrieve the secret key after creation so make note of it in a safe place.
  • Find the EC2 endpoint for your region here 

The DeleteOnTermination flag actually isn't directly on the Instance or the Volume.  It's part of the Block Device Mapping for the instance.  However, these are accessible via an attribute on the Instance so we can still set it with ModifyInstanceAttribute.  Here's the code for a simple class which will set DeleteOnTermination to false for all volumes attached to an instance.


using System;
using System.Collections.Generic;
using Amazon;
using Amazon.EC2;
using Amazon.EC2.Model;

namespace AwsSamples
{
    public class Sample
    {
        /// <summary>
        /// Turn off "Delete on Termination" for all volumes attached to an instance
        /// </summary>
        /// <param name="instanceId">The Instance ID of your EC2 instance, such as i-a4db8e11</param>
        public static void RemoveDeleteOnTermination(string instanceId)
        {
            // Connect to the EC2 API
            AmazonEC2Config config = new AmazonEC2Config();
            config.ServiceURL = "https://ec2.us-east-1.amazonaws.com";
            IAmazonEC2 client = AWSClientFactory.CreateAmazonEC2Client("YOUR_ACCESS_KEY", 
                "YOUR_SECRET_KEY", config);

            // Retrieve the instance information for the request
            DescribeInstancesRequest ec2Request = new DescribeInstancesRequest();
            ec2Request.InstanceIds = new List<string>() { instanceId };
            DescribeInstancesResponse ec2Response = client.DescribeInstances(ec2Request);
            Instance instance = ec2Response.Reservations[0].Instances[0];

            // Build the request to change the instance attribute
            ModifyInstanceAttributeRequest req = new ModifyInstanceAttributeRequest();
            req.InstanceId = instance.InstanceId;

            // Identify which attribute to change
            req.Attribute = new InstanceAttributeName("blockDeviceMapping");

            // Loop through the Block Device Mappings for the instance
            // The way this is written, it will set the flag for all EBS volumes
            foreach (InstanceBlockDeviceMapping mapping in instance.BlockDeviceMappings)
            {
                // Build the BDM specification for the request
                InstanceBlockDeviceMappingSpecification spec = 
                    new InstanceBlockDeviceMappingSpecification();
                spec.DeviceName = mapping.DeviceName;

                // Initialize the EBS specification
                spec.Ebs = new EbsInstanceBlockDeviceSpecification();
                spec.Ebs.VolumeId = mapping.Ebs.VolumeId;

                // Set the new falue for the DeleteOnTermination flag (true/false)
                spec.Ebs.DeleteOnTermination = false;

                req.BlockDeviceMappings.Add(spec);
            }

            // Send the request.  This commits the changes
            ModifyInstanceAttributeResponse resp = client.ModifyInstanceAttribute(req);
            if (resp.HttpStatusCode != System.Net.HttpStatusCode.OK)
            {
                throw new ApplicationException("Unable to modify the instance");
            }
        }
    }
}

Hope this helps!