Ahmed Adel
Posted on September 4, 2021
✦ The AWS SDK
for .NET
supports Amazon EC2
, which is a web service that provides resizable computing capacity. You use this computing capacity to build and host your software systems.
First of all, let's have a brief about Amazon EC2
in AWS...
➽What is Amazon EC2 ?
☞ Amazon Elastic Compute Cloud (EC2)
is a web service that provides resizable computing capacity—literally, servers in Amazon's data centers—that you use to build and host your software systems.
☞ Read more about Amazon EC2
➽Installing AWSSDK.EC2 :
☞AWSSDK.EC2
is installed mainly from Nuget
☞There is 3 ways to install AWSSDK.EC2
, they are the same as installing AWSSDK.S3
from Part 1 of this series
☞let's use the easiest one, from Package Manager Console by using the Install-Package command.
PM> Install-Package AWSSDK.EC2
🌟 Second step is to connect to our AWS account using __ Access keys (Access Key ID and Secret Access Key)__, this was explained before briefly in the first article under (Get AWS Access keys)
Let's now check what we can do with this SDK :
☞ Working with Security Groups:
✦ A security group acts as a virtual firewall that controls the network traffic for one or more EC2 instances. By default, EC2 associates your instances with a security group that allows no inbound traffic. You can create a security group that allows your EC2 instances to accept certain traffic.
✦ Read more about security groups in the EC2 user guide for Linux and the EC2 user guide for Windows.
1- Creating security groups:
// Method to create a new security group (either EC2-Classic or EC2-VPC)
// If vpcID is empty, the security group will be for EC2-Classic
private static async Task<List<SecurityGroup>> CreateSecurityGroup(
IAmazonEC2 ec2Client, string groupName, string vpcID)
{
// See if one or more security groups with that name
// already exist in the given VPC. If so, return the list of them.
var securityGroups = await FindSecurityGroups(ec2Client, groupName, vpcID);
if (securityGroups.Count > 0)
{
Console.WriteLine($"\n Security groups with name {groupName} already exists.\n");
return securityGroups;
}
// If the security group doesn't already exists, create it.
var createRequest = new CreateSecurityGroupRequest{ GroupName = groupName };
if(string.IsNullOrEmpty(vpcID))
{
createRequest.Description = "My .NET example security group for EC2-Classic";
}
else
{
createRequest.VpcId = vpcID;
createRequest.Description = "My .NET example security group for EC2-VPC";
}
CreateSecurityGroupResponse createResponse = await ec2Client.CreateSecurityGroupAsync(createRequest);
// Return the new security group
DescribeSecurityGroupsResponse describeResponse =
await ec2Client.DescribeSecurityGroupsAsync(new DescribeSecurityGroupsRequest{
GroupIds = new List<string>() { createResponse.GroupId }
});
return describeResponse.SecurityGroups;
}
// Method to determine if a security group with the specified name
// already exists in the VPC
private static async Task<List<SecurityGroup>> FindSecurityGroups(
IAmazonEC2 ec2Client, string groupName, string vpcID)
{
var request = new DescribeSecurityGroupsRequest();
request.Filters.Add(new Filter{
Name = "group-name",
Values = new List<string>() { groupName }
});
if(!string.IsNullOrEmpty(vpcID))
request.Filters.Add(new Filter{
Name = "vpc-id",
Values = new List<string>() { vpcID }
});
var response = await ec2Client.DescribeSecurityGroupsAsync(request);
return response.SecurityGroups;
}
2- Loop through your security groups:
// Method to enumerate the security groups
private static async Task EnumerateGroups(IAmazonEC2 ec2Client, string vpcID)
{
// A request object, in case we need it.
var request = new DescribeSecurityGroupsRequest();
// Put together the properties, if needed
if(!string.IsNullOrEmpty(vpcID))
{
// We have a VPC ID. Find the security groups for just that VPC.
Console.WriteLine($"\nGetting security groups for VPC {vpcID}...\n");
request.Filters.Add(new Filter
{
Name = "vpc-id",
Values = new List<string>() { vpcID }
});
}
// Get the list of security groups
DescribeSecurityGroupsResponse response =
await ec2Client.DescribeSecurityGroupsAsync(request);
// Display the list of security groups.
foreach (SecurityGroup item in response.SecurityGroups)
{
Console.WriteLine("Security group: " + item.GroupId);
Console.WriteLine("\tGroupId: " + item.GroupId);
Console.WriteLine("\tGroupName: " + item.GroupName);
Console.WriteLine("\tVpcId: " + item.VpcId);
Console.WriteLine();
}
}
3- Update security group (Add inbound rule):
// Method that adds a TCP ingress rule to a security group
private static async Task AddIngressRule(
IAmazonEC2 eC2Client, string groupID, string ipAddress, int port)
{
// Create an object to hold the request information for the rule.
// It uses an IpPermission object to hold the IP information for the rule.
var ingressRequest = new AuthorizeSecurityGroupIngressRequest{
GroupId = groupID};
ingressRequest.IpPermissions.Add(new IpPermission{
IpProtocol = "tcp",
FromPort = port,
ToPort = port,
Ipv4Ranges = new List<IpRange>() { new IpRange { CidrIp = ipAddress } }
});
// Create the inbound rule for the security group
AuthorizeSecurityGroupIngressResponse responseIngress =
await eC2Client.AuthorizeSecurityGroupIngressAsync(ingressRequest);
Console.WriteLine($"\nNew RDP rule was written in {groupID} for {ipAddress}.");
Console.WriteLine($"Result: {responseIngress.HttpStatusCode}");
}
☞ Working with Amazon EC2 key pairs:
✦ Amazon EC2
uses public–key cryptography to encrypt and decrypt login information. Public–key cryptography uses a public key to encrypt data, and then the recipient uses the private key to decrypt the data. The public and private keys are known as a key pair.
✦ Read more about Amazon EC2 key pairs
in the EC2 user guide for Linux or the EC2 user guide for Windows.
1- Create the key pair:
// Method to create a key pair and save the key material in a PEM file
private static async Task CreateKeyPair(
IAmazonEC2 ec2Client, string keyPairName, string pemFileName)
{
// Create the key pair
CreateKeyPairResponse response =
await ec2Client.CreateKeyPairAsync(new CreateKeyPairRequest{
KeyName = keyPairName
});
Console.WriteLine($"\nCreated new key pair: {response.KeyPair.KeyName}");
// Save the private key in a PEM file
using (var s = new FileStream(pemFileName, FileMode.Create))
using (var writer = new StreamWriter(s))
{
writer.WriteLine(response.KeyPair.KeyMaterial);
}
}
2- Display available key pairs:
// Method to show the key pairs that are available
private static async Task EnumerateKeyPairs(IAmazonEC2 ec2Client)
{
DescribeKeyPairsResponse response = await ec2Client.DescribeKeyPairsAsync();
Console.WriteLine("Available key pairs:");
foreach (KeyPairInfo item in response.KeyPairs)
Console.WriteLine($" {item.KeyName}");
}
3- Delete the key pair:
// Method to delete a key pair
private static async Task DeleteKeyPair(IAmazonEC2 ec2Client, string keyName)
{
await ec2Client.DeleteKeyPairAsync(new DeleteKeyPairRequest{
KeyName = keyName});
Console.WriteLine($"\nKey pair {keyName} has been deleted (if it existed).");
}
☞ Seeing your Amazon EC2 Regions and Availability Zones:
✦ Amazon EC2
is hosted in multiple locations worldwide. These locations are composed of Regions and Availability Zones. Each Region is a separate geographic area that has multiple, isolated locations known as Availability Zones.
✦ Read more about Regions and Availability Zones in the EC2 user guide for Linux or the EC2 user guide for Windows.
using System;
using System.Threading.Tasks;
using Amazon.EC2;
using Amazon.EC2.Model;
namespace EC2RegionsAndZones
{
class Program
{
static async Task Main(string[] args)
{
// Create the EC2 client
var ec2Client = new AmazonEC2Client();
// Display the Regions and Availability Zones
await DescribeRegions(ec2Client);
await DescribeAvailabilityZones(ec2Client);
}
// Method to display Regions
private static async Task DescribeRegions(IAmazonEC2 ec2Client)
{
Console.WriteLine("\nRegions that are enabled for the EC2 client:");
DescribeRegionsResponse response = await ec2Client.DescribeRegionsAsync();
foreach (Region region in response.Regions)
Console.WriteLine(region.RegionName);
}
//
// Method to display Availability Zones
private static async Task DescribeAvailabilityZones(IAmazonEC2 ec2Client)
{
Console.WriteLine("\nAvailability Zones for the EC2 client's region:");
DescribeAvailabilityZonesResponse response = await ec2Client.DescribeAvailabilityZonesAsync();
foreach (AvailabilityZone az in response.AvailabilityZones)
Console.WriteLine(az.ZoneName);
}
}
}
☞ Working with Amazon EC2 instances:
1- Launch an instance:
// Method to launch the instances
// Returns a list with the launched instance IDs
private static async Task<List<string>> LaunchInstances(
IAmazonEC2 ec2Client, RunInstancesRequest requestLaunch)
{
var instanceIds = new List<string>();
RunInstancesResponse responseLaunch =
await ec2Client.RunInstancesAsync(requestLaunch);
Console.WriteLine("\nNew instances have been created.");
foreach (Instance item in responseLaunch.Reservation.Instances)
{
instanceIds.Add(item.InstanceId);
Console.WriteLine($" New instance: {item.InstanceId}");
}
return instanceIds;
}
2- Monitor the instance:
// Method to wait until the instances are running (or at least not pending)
private static async Task CheckState(IAmazonEC2 ec2Client, List<string> instanceIds)
{
Console.WriteLine(
"\nWaiting for the instances to start." +
"\nPress any key to stop waiting. (Response might be slightly delayed.)");
int numberRunning;
DescribeInstancesResponse responseDescribe;
var requestDescribe = new DescribeInstancesRequest{
InstanceIds = instanceIds};
// Check every couple of seconds
int wait = 2000;
while(true)
{
// Get and check the status for each of the instances to see if it's past pending.
// Once all instances are past pending, break out.
// (For this example, we are assuming that there is only one reservation.)
Console.Write(".");
numberRunning = 0;
responseDescribe = await ec2Client.DescribeInstancesAsync(requestDescribe);
foreach(Instance i in responseDescribe.Reservations[0].Instances)
{
// Check the lower byte of State.Code property
// Code == 0 is the pending state
if((i.State.Code & 255) > 0) numberRunning++;
}
if(numberRunning == responseDescribe.Reservations[0].Instances.Count)
break;
// Wait a bit and try again (unless the user wants to stop waiting)
Thread.Sleep(wait);
if(Console.KeyAvailable)
break;
}
Console.WriteLine("\nNo more instances are pending.");
foreach(Instance i in responseDescribe.Reservations[0].Instances)
{
Console.WriteLine($"For {i.InstanceId}:");
Console.WriteLine($" VPC ID: {i.VpcId}");
Console.WriteLine($" Instance state: {i.State.Name}");
Console.WriteLine($" Public IP address: {i.PublicIpAddress}");
Console.WriteLine($" Public DNS name: {i.PublicDnsName}");
Console.WriteLine($" Key pair name: {i.KeyName}");
}
}
3- Terminating an EC2 instance:
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Amazon.EC2;
using Amazon.EC2.Model;
namespace EC2TerminateInstance
{
class Program
{
static async Task Main(string[] args)
{
if((args.Length == 1) && (args[0].StartsWith("i-")))
{
// Terminate the instance
var ec2Client = new AmazonEC2Client();
await TerminateInstance(ec2Client, args[0]);
}
else
{
Console.WriteLine("\nCommand-line argument missing or incorrect.");
Console.WriteLine("\nUsage: EC2TerminateInstance instance-ID");
Console.WriteLine(" instance-ID - The EC2 instance you want to terminate.");
return;
}
}
// Method to terminate an EC2 instance
private static async Task TerminateInstance(IAmazonEC2 ec2Client, string instanceID)
{
var request = new TerminateInstancesRequest{
InstanceIds = new List<string>() { instanceID }};
TerminateInstancesResponse response =
await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{
InstanceIds = new List<string>() { instanceID }
});
foreach (InstanceStateChange item in response.TerminatingInstances)
{
Console.WriteLine("Terminated instance: " + item.InstanceId);
Console.WriteLine("Instance state: " + item.CurrentState.Name);
}
}
}
}
☞ Amazon EC2 Spot Instance tutorial:
✦ Spot Instances
enable you to request unused Amazon EC2 capacity for less than the On-Demand price. This can significantly lower your EC2 costs for applications that can be interrupted.
✦ Read more about Spot Instances
in the EC2 user guide for Linux or the EC2 user guide for Windows.
1- Creating a Spot Instance request:
// Method to create a Spot Instance request
private static async Task<SpotInstanceRequest> CreateSpotInstanceRequest(
IAmazonEC2 ec2Client, string amiId, string securityGroupName,
InstanceType instanceType, string spotPrice, int instanceCount)
{
var launchSpecification = new LaunchSpecification{
ImageId = amiId,
InstanceType = instanceType
};
launchSpecification.SecurityGroups.Add(securityGroupName);
var request = new RequestSpotInstancesRequest{
SpotPrice = spotPrice,
InstanceCount = instanceCount,
LaunchSpecification = launchSpecification
};
RequestSpotInstancesResponse result = await ec2Client.RequestSpotInstancesAsync(request);
return result.SpotInstanceRequests[0];
}
2- Get status of your Spot Instance request:
// Method to get information about a Spot Instance request, including the status,
// instance ID, etc.
// It gets the information for a specific request (as opposed to all requests).
private static async Task<SpotInstanceRequest> GetSpotInstanceRequestInfo(
IAmazonEC2 ec2Client, string requestId)
{
var describeRequest = new DescribeSpotInstanceRequestsRequest();
describeRequest.SpotInstanceRequestIds.Add(requestId);
DescribeSpotInstanceRequestsResponse describeResponse =
await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);
return describeResponse.SpotInstanceRequests[0];
}
3- Clean up your Spot Instance requests:
// Method to cancel a Spot Instance request
private static async Task CancelSpotInstanceRequest(
IAmazonEC2 ec2Client, string requestId)
{
var cancelRequest = new CancelSpotInstanceRequestsRequest();
cancelRequest.SpotInstanceRequestIds.Add(requestId);
await ec2Client.CancelSpotInstanceRequestsAsync(cancelRequest);
}
4- Clean up your Spot Instances:
✦ To avoid unnecessary costs, it's important that you terminate any instances that were started from Spot Instance requests; simply canceling Spot Instance requests will not terminate your instances, which means that you'll continue to be charged for them.
// Method to terminate a Spot Instance
private static async Task TerminateSpotInstance(
IAmazonEC2 ec2Client, string requestId)
{
var describeRequest = new DescribeSpotInstanceRequestsRequest();
describeRequest.SpotInstanceRequestIds.Add(requestId);
// Retrieve the Spot Instance request to check for running instances.
DescribeSpotInstanceRequestsResponse describeResponse =
await ec2Client.DescribeSpotInstanceRequestsAsync(describeRequest);
// If there are any running instances, terminate them
if( (describeResponse.SpotInstanceRequests[0].Status.Code
== "request-canceled-and-instance-running")
|| (describeResponse.SpotInstanceRequests[0].State == SpotInstanceState.Active))
{
TerminateInstancesResponse response =
await ec2Client.TerminateInstancesAsync(new TerminateInstancesRequest{
InstanceIds = new List<string>(){
describeResponse.SpotInstanceRequests[0].InstanceId } });
foreach (InstanceStateChange item in response.TerminatingInstances)
{
Console.WriteLine($"\n Terminated instance: {item.InstanceId}");
Console.WriteLine($" Instance state: {item.CurrentState.Name}\n");
}
}
}
References: AWS official Documentation
Posted on September 4, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.