Get started with Amazon EC2 instances using an Amazon SDK - Amazon Elastic Compute Cloud
Services or capabilities described in Amazon Web Services documentation might vary by Region. To see the differences applicable to the China Regions, see Getting Started with Amazon Web Services in China (PDF).

Get started with Amazon EC2 instances using an Amazon SDK

The following code examples show how to:

  • Create a key pair and security group.

  • Select an Amazon Machine Image (AMI) and compatible instance type, then create an instance.

  • Stop and restart the instance.

  • Associate an Elastic IP address with your instance.

  • Connect to your instance with SSH, then clean up resources.

.NET
Amazon SDK for .NET
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Amazon Code Examples Repository.

Run a scenario at a command prompt.

/// <summary> /// Show Amazon Elastic Compute Cloud (Amazon EC2) Basics actions. /// </summary> public class EC2Basics { /// <summary> /// Perform the actions defined for the Amazon EC2 Basics scenario. /// </summary> /// <param name="args">Command line arguments.</param> /// <returns>A Task object.</returns> static async Task Main(string[] args) { // Set up dependency injection for Amazon EC2 and Amazon Simple Systems // Management Service. using var host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args) .ConfigureServices((_, services) => services.AddAWSService<IAmazonEC2>() .AddAWSService<IAmazonSimpleSystemsManagement>() .AddTransient<EC2Wrapper>() .AddTransient<SsmWrapper>() ) .Build(); // Now the client is available for injection. var ec2Client = host.Services.GetRequiredService<IAmazonEC2>(); var ec2Methods = new EC2Wrapper(ec2Client); var ssmClient = host.Services.GetRequiredService<IAmazonSimpleSystemsManagement>(); var ssmMethods = new SsmWrapper(ssmClient); var uiMethods = new UiMethods(); var uniqueName = Guid.NewGuid().ToString(); var keyPairName = "mvp-example-key-pair" + uniqueName; var groupName = "ec2-scenario-group" + uniqueName; var groupDescription = "A security group created for the EC2 Basics scenario."; // Start the scenario. uiMethods.DisplayOverview(); uiMethods.PressEnter(); // Create the key pair. uiMethods.DisplayTitle("Create RSA key pair"); Console.Write("Let's create an RSA key pair that you can be use to "); Console.WriteLine("securely connect to your EC2 instance."); var keyPair = await ec2Methods.CreateKeyPair(keyPairName); // Save key pair information to a temporary file. var tempFileName = ec2Methods.SaveKeyPair(keyPair); Console.WriteLine($"Created the key pair: {keyPair.KeyName} and saved it to: {tempFileName}"); string? answer; do { Console.Write("Would you like to list your existing key pairs? "); answer = Console.ReadLine(); } while (answer!.ToLower() != "y" && answer.ToLower() != "n"); if (answer == "y") { // List existing key pairs. uiMethods.DisplayTitle("Existing key pairs"); // Passing an empty string to the DescribeKeyPairs method will return // a list of all existing key pairs. var keyPairs = await ec2Methods.DescribeKeyPairs(""); keyPairs.ForEach(kp => { Console.WriteLine($"{kp.KeyName} created at: {kp.CreateTime} Fingerprint: {kp.KeyFingerprint}"); }); } uiMethods.PressEnter(); // Create the security group. Console.WriteLine("Let's create a security group to manage access to your instance."); var secGroupId = await ec2Methods.CreateSecurityGroup(groupName, groupDescription); Console.WriteLine("Let's add rules to allow all HTTP and HTTPS inbound traffic and to allow SSH only from your current IP address."); uiMethods.DisplayTitle("Security group information"); var secGroups = await ec2Methods.DescribeSecurityGroups(secGroupId); Console.WriteLine($"Created security group {groupName} in your default VPC."); secGroups.ForEach(group => { ec2Methods.DisplaySecurityGroupInfoAsync(group); }); uiMethods.PressEnter(); Console.WriteLine("Now we'll authorize the security group we just created so that it can"); Console.WriteLine("access the EC2 instances you create."); var success = await ec2Methods.AuthorizeSecurityGroupIngress(groupName); secGroups = await ec2Methods.DescribeSecurityGroups(secGroupId); Console.WriteLine($"Now let's look at the permissions again."); secGroups.ForEach(group => { ec2Methods.DisplaySecurityGroupInfoAsync(group); }); uiMethods.PressEnter(); // Get list of available Amazon Linux 2 Amazon Machine Images (AMIs). var parameters = await ssmMethods.GetParametersByPath("/aws/service/ami-amazon-linux-latest"); List<string> imageIds = parameters.Select(param => param.Value).ToList(); var images = await ec2Methods.DescribeImages(imageIds); var i = 1; images.ForEach(image => { Console.WriteLine($"\t{i++}\t{image.Description}"); }); int choice; bool validNumber = false; do { Console.Write("Please select an image: "); var selImage = Console.ReadLine(); validNumber = int.TryParse(selImage, out choice); } while (!validNumber); var selectedImage = images[choice - 1]; // Display available instance types. uiMethods.DisplayTitle("Instance Types"); var instanceTypes = await ec2Methods.DescribeInstanceTypes(selectedImage.Architecture); i = 1; instanceTypes.ForEach(instanceType => { Console.WriteLine($"\t{i++}\t{instanceType.InstanceType}"); }); do { Console.Write("Please select an instance type: "); var selImage = Console.ReadLine(); validNumber = int.TryParse(selImage, out choice); } while (!validNumber); var selectedInstanceType = instanceTypes[choice - 1].InstanceType; // Create an EC2 instance. uiMethods.DisplayTitle("Creating an EC2 Instance"); var instanceId = await ec2Methods.RunInstances(selectedImage.ImageId, selectedInstanceType, keyPairName, secGroupId); Console.Write("Waiting for the instance to start."); var isRunning = false; do { isRunning = await ec2Methods.WaitForInstanceState(instanceId, InstanceStateName.Running); } while (!isRunning); uiMethods.PressEnter(); var instance = await ec2Methods.DescribeInstance(instanceId); uiMethods.DisplayTitle("New Instance Information"); ec2Methods.DisplayInstanceInformation(instance); Console.WriteLine("\nYou can use SSH to connect to your instance. For example:"); Console.WriteLine($"\tssh -i {tempFileName} ec2-user@{instance.PublicIpAddress}"); uiMethods.PressEnter(); Console.WriteLine("Now we'll stop the instance and then start it again to see what's changed."); await ec2Methods.StopInstances(instanceId); var hasStopped = false; do { hasStopped = await ec2Methods.WaitForInstanceState(instanceId, InstanceStateName.Stopped); } while (!hasStopped); Console.WriteLine("\nThe instance has stopped."); Console.WriteLine("Now let's start it up again."); await ec2Methods.StartInstances(instanceId); Console.Write("Waiting for instance to start. "); isRunning = false; do { isRunning = await ec2Methods.WaitForInstanceState(instanceId, InstanceStateName.Running); } while (!isRunning); Console.WriteLine("\nLet's see what changed."); instance = await ec2Methods.DescribeInstance(instanceId); uiMethods.DisplayTitle("New Instance Information"); ec2Methods.DisplayInstanceInformation(instance); Console.WriteLine("\nNotice the change in the SSH information:"); Console.WriteLine($"\tssh -i {tempFileName} ec2-user@{instance.PublicIpAddress}"); uiMethods.PressEnter(); Console.WriteLine("Now we will stop the instance again. Then we will create and associate an"); Console.WriteLine("Elastic IP address to use with our instance."); await ec2Methods.StopInstances(instanceId); hasStopped = false; do { hasStopped = await ec2Methods.WaitForInstanceState(instanceId, InstanceStateName.Stopped); } while (!hasStopped); Console.WriteLine("\nThe instance has stopped."); uiMethods.PressEnter(); uiMethods.DisplayTitle("Allocate Elastic IP address"); Console.WriteLine("You can allocate an Elastic IP address and associate it with your instance\nto keep a consistent IP address even when your instance restarts."); var allocationId = await ec2Methods.AllocateAddress(); Console.WriteLine("Now we will associate the Elastic IP address with our instance."); var associationId = await ec2Methods.AssociateAddress(allocationId, instanceId); // Start the instance again. Console.WriteLine("Now let's start the instance again."); await ec2Methods.StartInstances(instanceId); Console.Write("Waiting for instance to start. "); isRunning = false; do { isRunning = await ec2Methods.WaitForInstanceState(instanceId, InstanceStateName.Running); } while (!isRunning); Console.WriteLine("\nLet's see what changed."); instance = await ec2Methods.DescribeInstance(instanceId); uiMethods.DisplayTitle("Instance information"); ec2Methods.DisplayInstanceInformation(instance); Console.WriteLine("\nHere is the SSH information:"); Console.WriteLine($"\tssh -i {tempFileName} ec2-user@{instance.PublicIpAddress}"); Console.WriteLine("Let's stop and start the instance again."); uiMethods.PressEnter(); await ec2Methods.StopInstances(instanceId); hasStopped = false; do { hasStopped = await ec2Methods.WaitForInstanceState(instanceId, InstanceStateName.Stopped); } while (!hasStopped); Console.WriteLine("\nThe instance has stopped."); Console.WriteLine("Now let's start it up again."); await ec2Methods.StartInstances(instanceId); Console.Write("Waiting for instance to start. "); isRunning = false; do { isRunning = await ec2Methods.WaitForInstanceState(instanceId, InstanceStateName.Running); } while (!isRunning); instance = await ec2Methods.DescribeInstance(instanceId); uiMethods.DisplayTitle("New Instance Information"); ec2Methods.DisplayInstanceInformation(instance); Console.WriteLine("Note that the IP address did not change this time."); uiMethods.PressEnter(); uiMethods.DisplayTitle("Clean up resources"); Console.WriteLine("Now let's clean up the resources we created."); // Terminate the instance. Console.WriteLine("Terminating the instance we created."); var stateChange = await ec2Methods.TerminateInstances(instanceId); // Wait for the instance state to be terminated. var hasTerminated = false; do { hasTerminated = await ec2Methods.WaitForInstanceState(instanceId, InstanceStateName.Terminated); } while (!hasTerminated); Console.WriteLine($"\nThe instance {instanceId} has been terminated."); Console.WriteLine("Now we can disassociate the Elastic IP address and release it."); // Disassociate the Elastic IP address. var disassociated = ec2Methods.DisassociateIp(associationId); // Delete the Elastic IP address. var released = ec2Methods.ReleaseAddress(allocationId); // Delete the security group. Console.WriteLine($"Deleting the Security Group: {groupName}."); success = await ec2Methods.DeleteSecurityGroup(secGroupId); if (success) { Console.WriteLine($"Successfully deleted {groupName}."); } // Delete the RSA key pair. Console.WriteLine($"Deleting the key pair: {keyPairName}"); await ec2Methods.DeleteKeyPair(keyPairName); Console.WriteLine("Deleting the temporary file with the key information."); ec2Methods.DeleteTempFile(tempFileName); uiMethods.PressEnter(); uiMethods.DisplayTitle("EC2 Basics Scenario completed."); uiMethods.PressEnter(); } }

Define a class that wraps EC2 actions.

/// <summary> /// Methods of this class perform Amazon Elastic Compute Cloud (Amazon EC2). /// </summary> public class EC2Wrapper { private readonly IAmazonEC2 _amazonEC2; public EC2Wrapper(IAmazonEC2 amazonService) { _amazonEC2 = amazonService; } /// <summary> /// Allocate an Elastic IP address. /// </summary> /// <returns>The allocation Id of the allocated address.</returns> public async Task<string> AllocateAddress() { var request = new AllocateAddressRequest(); var response = await _amazonEC2.AllocateAddressAsync(request); return response.AllocationId; } /// <summary> /// Associate an Elastic IP address to an EC2 instance. /// </summary> /// <param name="allocationId">The allocation Id of an Elastic IP address.</param> /// <param name="instanceId">The instance Id of the EC2 instance to /// associate the address with.</param> /// <returns>The association Id that represents /// the association of the Elastic IP address with an instance.</returns> public async Task<string> AssociateAddress(string allocationId, string instanceId) { var request = new AssociateAddressRequest { AllocationId = allocationId, InstanceId = instanceId }; var response = await _amazonEC2.AssociateAddressAsync(request); return response.AssociationId; } /// <summary> /// Authorize the local computer ingress to EC2 instances associated /// with the virtual private cloud (VPC) security group. /// </summary> /// <param name="groupName">The name of the security group.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> AuthorizeSecurityGroupIngress(string groupName) { // Get the IP address for the local computer. var ipAddress = await GetIpAddress(); Console.WriteLine($"Your IP address is: {ipAddress}"); var ipRanges = new List<IpRange> { new IpRange { CidrIp = $"{ipAddress}/32" } }; var permission = new IpPermission { Ipv4Ranges = ipRanges, IpProtocol = "tcp", FromPort = 22, ToPort = 22 }; var permissions = new List<IpPermission> { permission }; var response = await _amazonEC2.AuthorizeSecurityGroupIngressAsync( new AuthorizeSecurityGroupIngressRequest(groupName, permissions)); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Authorize the local computer for ingress to /// the Amazon EC2 SecurityGroup. /// </summary> /// <returns>The IPv4 address of the computer running the scenario.</returns> private static async Task<string> GetIpAddress() { var httpClient = new HttpClient(); var ipString = await httpClient.GetStringAsync("https://checkip.amazonaws.com"); // The IP address is returned with a new line // character on the end. Trim off the whitespace and // return the value to the caller. return ipString.Trim(); } /// <summary> /// Create an Amazon EC2 key pair. /// </summary> /// <param name="keyPairName">The name for the new key pair.</param> /// <returns>The Amazon EC2 key pair created.</returns> public async Task<KeyPair?> CreateKeyPair(string keyPairName) { var request = new CreateKeyPairRequest { KeyName = keyPairName, }; var response = await _amazonEC2.CreateKeyPairAsync(request); if (response.HttpStatusCode == HttpStatusCode.OK) { var kp = response.KeyPair; return kp; } else { Console.WriteLine("Could not create key pair."); return null; } } /// <summary> /// Save KeyPair information to a temporary file. /// </summary> /// <param name="keyPair">The name of the key pair.</param> /// <returns>The full path to the temporary file.</returns> public string SaveKeyPair(KeyPair keyPair) { var tempPath = Path.GetTempPath(); var tempFileName = $"{tempPath}\\{Path.GetRandomFileName()}"; var pemFileName = Path.ChangeExtension(tempFileName, "pem"); // Save the key pair to a file in a temporary folder. using var stream = new FileStream(pemFileName, FileMode.Create); using var writer = new StreamWriter(stream); writer.WriteLine(keyPair.KeyMaterial); return pemFileName; } /// <summary> /// Create an Amazon EC2 security group. /// </summary> /// <param name="groupName">The name for the new security group.</param> /// <param name="groupDescription">A description of the new security group.</param> /// <returns>The group Id of the new security group.</returns> public async Task<string> CreateSecurityGroup(string groupName, string groupDescription) { var response = await _amazonEC2.CreateSecurityGroupAsync( new CreateSecurityGroupRequest(groupName, groupDescription)); return response.GroupId; } /// <summary> /// Create a new Amazon EC2 VPC. /// </summary> /// <param name="cidrBlock">The CIDR block for the new security group.</param> /// <returns>The VPC Id of the new VPC.</returns> public async Task<string?> CreateVPC(string cidrBlock) { try { var response = await _amazonEC2.CreateVpcAsync(new CreateVpcRequest { CidrBlock = cidrBlock, }); Vpc vpc = response.Vpc; Console.WriteLine($"Created VPC with ID: {vpc.VpcId}."); return vpc.VpcId; } catch (AmazonEC2Exception ex) { Console.WriteLine($"Couldn't create VPC because: {ex.Message}"); return null; } } /// <summary> /// Delete an Amazon EC2 key pair. /// </summary> /// <param name="keyPairName">The name of the key pair to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteKeyPair(string keyPairName) { try { await _amazonEC2.DeleteKeyPairAsync(new DeleteKeyPairRequest(keyPairName)).ConfigureAwait(false); return true; } catch (Exception ex) { Console.WriteLine($"Couldn't delete the key pair because: {ex.Message}"); return false; } } /// <summary> /// Delete the temporary file where the key pair information was saved. /// </summary> /// <param name="tempFileName">The path to the temporary file.</param> public void DeleteTempFile(string tempFileName) { if (File.Exists(tempFileName)) { File.Delete(tempFileName); } } /// <summary> /// Delete an Amazon EC2 security group. /// </summary> /// <param name="groupName">The name of the group to delete.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteSecurityGroup(string groupId) { var response = await _amazonEC2.DeleteSecurityGroupAsync(new DeleteSecurityGroupRequest { GroupId = groupId }); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Delete an Amazon EC2 VPC. /// </summary> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DeleteVpc(string vpcId) { var request = new DeleteVpcRequest { VpcId = vpcId, }; var response = await _amazonEC2.DeleteVpcAsync(request); return response.HttpStatusCode == System.Net.HttpStatusCode.OK; } /// <summary> /// Get information about existing Amazon EC2 images. /// </summary> /// <returns>A list of image information.</returns> public async Task<List<Image>> DescribeImages(List<string>? imageIds) { var request = new DescribeImagesRequest(); if (imageIds is not null) { // If the imageIds list is not null, add the list // to the request object. request.ImageIds = imageIds; } var response = await _amazonEC2.DescribeImagesAsync(request); return response.Images; } /// <summary> /// Display the information returned by DescribeImages. /// </summary> /// <param name="images">The list of image information to display.</param> public void DisplayImageInfo(List<Image> images) { images.ForEach(image => { Console.WriteLine($"{image.Name} Created on: {image.CreationDate}"); }); } /// <summary> /// Get information about an Amazon EC2 instance. /// </summary> /// <param name="instanceId">The instance Id of the EC2 instance.</param> /// <returns>An EC2 instance.</returns> public async Task<Instance> DescribeInstance(string instanceId) { var response = await _amazonEC2.DescribeInstancesAsync( new DescribeInstancesRequest { InstanceIds = new List<string> { instanceId } }); return response.Reservations[0].Instances[0]; } /// <summary> /// Display EC2 instance information. /// </summary> /// <param name="instance">The instance Id of the EC2 instance.</param> public void DisplayInstanceInformation(Instance instance) { Console.WriteLine($"ID: {instance.InstanceId}"); Console.WriteLine($"Image ID: {instance.ImageId}"); Console.WriteLine($"{instance.InstanceType}"); Console.WriteLine($"Key Name: {instance.KeyName}"); Console.WriteLine($"VPC ID: {instance.VpcId}"); Console.WriteLine($"Public IP: {instance.PublicIpAddress}"); Console.WriteLine($"State: {instance.State.Name}"); } /// <summary> /// Get information about existing EC2 images. /// </summary> /// <returns>Async task.</returns> public async Task DescribeInstances() { // List all EC2 instances. await GetInstanceDescriptions(); string tagName = "IncludeInList"; string tagValue = "Yes"; await GetInstanceDescriptionsFiltered(tagName, tagValue); } /// <summary> /// Get information for all existing Amazon EC2 instances. /// </summary> /// <returns>Async task.</returns> public async Task GetInstanceDescriptions() { Console.WriteLine("Showing all instances:"); var paginator = _amazonEC2.Paginators.DescribeInstances(new DescribeInstancesRequest()); await foreach (var response in paginator.Responses) { foreach (var reservation in response.Reservations) { foreach (var instance in reservation.Instances) { Console.Write($"Instance ID: {instance.InstanceId}"); Console.WriteLine($"\tCurrent State: {instance.State.Name}"); } } } } /// <summary> /// Get information about EC2 instances filtered by a tag name and value. /// </summary> /// <param name="tagName">The name of the tag to filter on.</param> /// <param name="tagValue">The value of the tag to look for.</param> /// <returns>Async task.</returns> public async Task GetInstanceDescriptionsFiltered(string tagName, string tagValue) { // This tag filters the results of the instance list. var filters = new List<Filter> { new Filter { Name = $"tag:{tagName}", Values = new List<string> { tagValue, }, }, }; var request = new DescribeInstancesRequest { Filters = filters, }; Console.WriteLine("\nShowing instances with tag: \"IncludeInList\" set to \"Yes\"."); var paginator = _amazonEC2.Paginators.DescribeInstances(request); await foreach (var response in paginator.Responses) { foreach (var reservation in response.Reservations) { foreach (var instance in reservation.Instances) { Console.Write($"Instance ID: {instance.InstanceId} "); Console.WriteLine($"\tCurrent State: {instance.State.Name}"); } } } } /// <summary> /// Describe the instance types available. /// </summary> /// <returns>A list of instance type information.</returns> public async Task<List<InstanceTypeInfo>> DescribeInstanceTypes(ArchitectureValues architecture) { var request = new DescribeInstanceTypesRequest(); var filters = new List<Filter> { new Filter("processor-info.supported-architecture", new List<string> { architecture.ToString() }) }; filters.Add(new Filter("instance-type", new() { "*.micro", "*.small" })); request.Filters = filters; var instanceTypes = new List<InstanceTypeInfo>(); var paginator = _amazonEC2.Paginators.DescribeInstanceTypes(request); await foreach (var instanceType in paginator.InstanceTypes) { instanceTypes.Add(instanceType); } return instanceTypes; } /// <summary> /// Display the instance type information returned by DescribeInstanceTypesAsync. /// </summary> /// <param name="instanceTypes">The list of instance type information.</param> public void DisplayInstanceTypeInfo(List<InstanceTypeInfo> instanceTypes) { instanceTypes.ForEach(type => { Console.WriteLine($"{type.InstanceType}\t{type.MemoryInfo}"); }); } /// <summary> /// Get information about an Amazon EC2 key pair. /// </summary> /// <param name="keyPairName">The name of the key pair.</param> /// <returns>A list of key pair information.</returns> public async Task<List<KeyPairInfo>> DescribeKeyPairs(string keyPairName) { var request = new DescribeKeyPairsRequest(); if (!string.IsNullOrEmpty(keyPairName)) { request = new DescribeKeyPairsRequest { KeyNames = new List<string> { keyPairName } }; } var response = await _amazonEC2.DescribeKeyPairsAsync(request); return response.KeyPairs.ToList(); } /// <summary> /// Retrieve information for an Amazon EC2 security group. /// </summary> /// <param name="groupId">The Id of the Amazon EC2 security group.</param> /// <returns>A list of security group information.</returns> public async Task<List<SecurityGroup>> DescribeSecurityGroups(string groupId) { var request = new DescribeSecurityGroupsRequest(); var groupIds = new List<string> { groupId }; request.GroupIds = groupIds; var response = await _amazonEC2.DescribeSecurityGroupsAsync(request); return response.SecurityGroups; } /// <summary> /// Display the information returned by the call to /// DescribeSecurityGroupsAsync. /// </summary> /// <param name="securityGroup">A list of security group information.</param> public void DisplaySecurityGroupInfoAsync(SecurityGroup securityGroup) { Console.WriteLine($"{securityGroup.GroupName}"); Console.WriteLine("Ingress permissions:"); securityGroup.IpPermissions.ForEach(permission => { Console.WriteLine($"\tFromPort: {permission.FromPort}"); Console.WriteLine($"\tIpProtocol: {permission.IpProtocol}"); Console.Write($"\tIpv4Ranges: "); permission.Ipv4Ranges.ForEach(range => { Console.Write($"{range.CidrIp} "); }); Console.WriteLine($"\n\tIpv6Ranges:"); permission.Ipv6Ranges.ForEach(range => { Console.Write($"{range.CidrIpv6} "); }); Console.Write($"\n\tPrefixListIds: "); permission.PrefixListIds.ForEach(id => Console.Write($"{id.Id} ")); Console.WriteLine($"\n\tTo Port: {permission.ToPort}"); }); Console.WriteLine("Egress permissions:"); securityGroup.IpPermissionsEgress.ForEach(permission => { Console.WriteLine($"\tFromPort: {permission.FromPort}"); Console.WriteLine($"\tIpProtocol: {permission.IpProtocol}"); Console.Write($"\tIpv4Ranges: "); permission.Ipv4Ranges.ForEach(range => { Console.Write($"{range.CidrIp} "); }); Console.WriteLine($"\n\tIpv6Ranges:"); permission.Ipv6Ranges.ForEach(range => { Console.Write($"{range.CidrIpv6} "); }); Console.Write($"\n\tPrefixListIds: "); permission.PrefixListIds.ForEach(id => Console.Write($"{id.Id} ")); Console.WriteLine($"\n\tTo Port: {permission.ToPort}"); }); } /// <summary> /// Disassociate an Elastic IP address from an EC2 instance. /// </summary> /// <param name="associationId">The association Id.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> DisassociateIp(string associationId) { var response = await _amazonEC2.DisassociateAddressAsync( new DisassociateAddressRequest { AssociationId = associationId }); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Retrieve a list of available Amazon Linux images. /// </summary> /// <returns>A list of image information.</returns> public async Task<List<Image>> GetEC2AmiList() { var filter = new Filter { Name = "architecture", Values = new List<string> { "x86_64" } }; var filters = new List<Filter> { filter }; var response = await _amazonEC2.DescribeImagesAsync(new DescribeImagesRequest { Filters = filters }); return response.Images; } /// <summary> /// Reboot EC2 instances. /// </summary> /// <param name="ec2InstanceId">The instance Id of the instances that will be rebooted.</param> /// <returns>Async task.</returns> public async Task RebootInstances(string ec2InstanceId) { var request = new RebootInstancesRequest { InstanceIds = new List<string> { ec2InstanceId }, }; var response = await _amazonEC2.RebootInstancesAsync(request); if (response.HttpStatusCode == System.Net.HttpStatusCode.OK) { Console.WriteLine("Instances successfully rebooted."); } else { Console.WriteLine("Could not reboot one or more instances."); } } /// <summary> /// Release an Elastic IP address. /// </summary> /// <param name="allocationId">The allocation Id of the Elastic IP address.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> ReleaseAddress(string allocationId) { var request = new ReleaseAddressRequest { AllocationId = allocationId }; var response = await _amazonEC2.ReleaseAddressAsync(request); return response.HttpStatusCode == HttpStatusCode.OK; } /// <summary> /// Create and run an EC2 instance. /// </summary> /// <param name="ImageId">The image Id of the image used as a basis for the /// EC2 instance.</param> /// <param name="instanceType">The instance type of the EC2 instance to create.</param> /// <param name="keyName">The name of the key pair to associate with the /// instance.</param> /// <param name="groupId">The Id of the Amazon EC2 security group that will be /// allowed to interact with the new EC2 instance.</param> /// <returns>The instance Id of the new EC2 instance.</returns> public async Task<string> RunInstances(string imageId, string instanceType, string keyName, string groupId) { var request = new RunInstancesRequest { ImageId = imageId, InstanceType = instanceType, KeyName = keyName, MinCount = 1, MaxCount = 1, SecurityGroupIds = new List<string> { groupId } }; var response = await _amazonEC2.RunInstancesAsync(request); return response.Reservation.Instances[0].InstanceId; } /// <summary> /// Start an EC2 instance. /// </summary> /// <param name="ec2InstanceId">The instance Id of the Amazon EC2 instance /// to start.</param> /// <returns>Async task.</returns> public async Task StartInstances(string ec2InstanceId) { var request = new StartInstancesRequest { InstanceIds = new List<string> { ec2InstanceId }, }; var response = await _amazonEC2.StartInstancesAsync(request); if (response.StartingInstances.Count > 0) { var instances = response.StartingInstances; instances.ForEach(i => { Console.WriteLine($"Successfully started the EC2 instance with instance ID: {i.InstanceId}."); }); } } /// <summary> /// Stop an EC2 instance. /// </summary> /// <param name="ec2InstanceId">The instance Id of the EC2 instance to /// stop.</param> /// <returns>Async task.</returns> public async Task StopInstances(string ec2InstanceId) { // In addition to the list of instance Ids, the // request can also include the following properties: // Force When true, forces the instances to // stop but you must check the integrity // of the file system. Not recommended on // Windows instances. // Hibernate When true, hibernates the instance if the // instance was enabled for hibernation when // it was launched. var request = new StopInstancesRequest { InstanceIds = new List<string> { ec2InstanceId }, }; var response = await _amazonEC2.StopInstancesAsync(request); if (response.StoppingInstances.Count > 0) { var instances = response.StoppingInstances; instances.ForEach(i => { Console.WriteLine($"Successfully stopped the EC2 Instance " + $"with InstanceID: {i.InstanceId}."); }); } } /// <summary> /// Terminate an EC2 instance. /// </summary> /// <param name="ec2InstanceId">The instance Id of the EC2 instance /// to terminate.</param> /// <returns>Async task.</returns> public async Task<List<InstanceStateChange>> TerminateInstances(string ec2InstanceId) { var request = new TerminateInstancesRequest { InstanceIds = new List<string> { ec2InstanceId } }; var response = await _amazonEC2.TerminateInstancesAsync(request); return response.TerminatingInstances; } /// <summary> /// Wait until an EC2 instance is in a specified state. /// </summary> /// <param name="instanceId">The instance Id.</param> /// <param name="stateName">The state to wait for.</param> /// <returns>A Boolean value indicating the success of the action.</returns> public async Task<bool> WaitForInstanceState(string instanceId, InstanceStateName stateName) { var request = new DescribeInstancesRequest { InstanceIds = new List<string> { instanceId } }; // Wait until the instance is running. var hasState = false; do { // Wait 5 seconds. Thread.Sleep(5000); // Check for the desired state. var response = await _amazonEC2.DescribeInstancesAsync(request); var instance = response.Reservations[0].Instances[0]; hasState = instance.State.Name == stateName; Console.Write(". "); } while (!hasState); return hasState; } }
Bash
Amazon CLI with Bash script
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Amazon Code Examples Repository.

Run an interactive scenario at a command prompt.

############################################################################### # function get_started_with_ec2_instances # # Runs an interactive scenario that shows how to get started using EC2 instances. # # "EC2 access" permissions are needed to run this code. # # Returns: # 0 - If successful. # 1 - If an error occurred. ############################################################################### function get_started_with_ec2_instances() { # Requires version 4 for mapfile. local required_version=4.0 # Get the current Bash version # Check if BASH_VERSION is set local current_version if [[ -n "$BASH_VERSION" ]]; then # Convert BASH_VERSION to a number for comparison current_version=$BASH_VERSION else # Get the current Bash version using the bash command current_version=$(bash --version | head -n 1 | awk '{ print $4 }') fi # Convert version strings to numbers for comparison local required_version_num current_version_num required_version_num=$(echo "$required_version" | awk -F. '{ print ($1 * 10000) + ($2 * 100) + $3 }') current_version_num=$(echo "$current_version" | awk -F. '{ print ($1 * 10000) + ($2 * 100) + $3 }') # Compare versions if ((current_version_num < required_version_num)); then echo "Error: This script requires Bash version $required_version or higher." echo "Your current Bash version is number is $current_version." exit 1 fi { if [ "$EC2_OPERATIONS_SOURCED" != "True" ]; then source ./ec2_operations.sh fi } echo_repeat "*" 88 echo "Welcome to the Amazon Elastic Compute Cloud (Amazon EC2) get started with instances demo." echo_repeat "*" 88 echo echo "Let's create an RSA key pair that you can be use to securely connect to " echo "your EC2 instance." echo -n "Enter a unique name for your key: " get_input local key_name key_name=$get_input_result local temp_dir temp_dir=$(mktemp -d) local key_file_name="$temp_dir/${key_name}.pem" if ec2_create_keypair -n "${key_name}" -f "${key_file_name}"; then echo "Created a key pair $key_name and saved the private key to $key_file_name" echo else errecho "The key pair failed to create. This demo will exit." return 1 fi chmod 400 "${key_file_name}" if yes_no_input "Do you want to list some of your key pairs? (y/n) "; then local keys_and_fingerprints keys_and_fingerprints="$(ec2_describe_key_pairs)" && { local image_name_and_id while IFS=$'\n' read -r image_name_and_id; do local entries IFS=$'\t' read -ra entries <<<"$image_name_and_id" echo "Found rsa key ${entries[0]} with fingerprint:" echo " ${entries[1]}" done <<<"$keys_and_fingerprints" } fi echo_repeat "*" 88 echo_repeat "*" 88 echo "Let's create a security group to manage access to your instance." echo -n "Enter a unique name for your security group: " get_input local security_group_name security_group_name=$get_input_result local security_group_id security_group_id=$(ec2_create_security_group -n "$security_group_name" \ -d "Security group for EC2 instance") || { errecho "The security failed to create. This demo will exit." clean_up "$key_name" "$key_file_name" return 1 } echo "Security group created with ID $security_group_id" echo local public_ip public_ip=$(curl -s http://checkip.amazonaws.com) echo "Let's add a rule to allow SSH only from your current IP address." echo "Your public IP address is $public_ip" echo -n "press return to add this rule to your security group." get_input if ! ec2_authorize_security_group_ingress -g "$security_group_id" -i "$public_ip" -p tcp -f 22 -t 22; then errecho "The security group rules failed to update. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" return 1 fi echo "Security group rules updated" local security_group_description security_group_description="$(ec2_describe_security_groups -g "${security_group_id}")" || { errecho "Failed to describe security groups. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" return 1 } mapfile -t parameters <<<"$security_group_description" IFS=$'\t' read -ra entries <<<"${parameters[0]}" echo "Security group: ${entries[0]}" echo " ID: ${entries[1]}" echo " VPC: ${entries[2]}" echo "Inbound permissions:" IFS=$'\t' read -ra entries <<<"${parameters[1]}" echo " IpProtocol: ${entries[0]}" echo " FromPort: ${entries[1]}" echo " ToPort: ${entries[2]}" echo " CidrIp: ${parameters[2]}" local parameters parameters="$(ssm_get_parameters_by_path -p "/aws/service/ami-amazon-linux-latest")" || { errecho "Failed to get parameters. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" return 1 } local image_ids="" mapfile -t parameters <<<"$parameters" for image_name_and_id in "${parameters[@]}"; do IFS=$'\t' read -ra values <<<"$image_name_and_id" if [[ "${values[0]}" == *"amzn2"* ]]; then image_ids+="${values[1]} " fi done local images images="$(ec2_describe_images -i "$image_ids")" || { errecho "Failed to describe images. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" return 1 } new_line_and_tab_to_list "$images" local images=("${list_result[@]}") # Get the size of the array local images_count=${#images[@]} if ((images_count == 0)); then errecho "No images found. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" return 1 fi echo_repeat "*" 88 echo_repeat "*" 88 echo "Let's create an instance from an Amazon Linux 2 AMI. Here are some options:" for ((i = 0; i < images_count; i += 3)); do echo "$(((i / 3) + 1)) - ${images[$i]}" done integer_input "Please enter the number of the AMI you want to use: " 1 "$((images_count / 3))" local choice=$get_input_result choice=$(((choice - 1) * 3)) echo "Great choice." echo local architecture=${images[$((choice + 1))]} local image_id=${images[$((choice + 2))]} echo "Here are some instance types that support the ${architecture} architecture of the image:" response="$(ec2_describe_instance_types -a "${architecture}" -t "*.micro,*.small")" || { errecho "Failed to describe instance types. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" return 1 } local instance_types mapfile -t instance_types <<<"$response" # Get the size of the array local instance_types_count=${#instance_types[@]} echo "Here are some options:" for ((i = 0; i < instance_types_count; i++)); do echo "$((i + 1)) - ${instance_types[$i]}" done integer_input "Which one do you want to use? " 1 "${#instance_types[@]} " choice=$get_input_result local instance_type=${instance_types[$((choice - 1))]} echo "Another great choice." echo echo "Creating your instance and waiting for it to start..." local instance_id instance_id=$(ec2_run_instances -i "$image_id" -t "$instance_type" -k "$key_name" -s "$security_group_id") || { errecho "Failed to run instance. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" return 1 } ec2_wait_for_instance_running -i "$instance_id" echo "Your instance is ready:" echo local instance_details instance_details="$(ec2_describe_instances -i "${instance_id}")" echo print_instance_details "${instance_details}" local public_ip public_ip=$(echo "${instance_details}" | awk '{print $6}') echo echo "You can use SSH to connect to your instance" echo "If the connection attempt times out, you might have to manually update the SSH ingress rule" echo "for your IP address in the AWS Management Console." connect_to_instance "$key_file_name" "$public_ip" echo -n "Press Enter when you're ready to continue the demo: " get_input echo_repeat "*" 88 echo_repeat "*" 88 echo "Let's stop and start your instance to see what changes." echo "Stopping your instance and waiting until it's stopped..." ec2_stop_instances -i "$instance_id" ec2_wait_for_instance_stopped -i "$instance_id" echo "Your instance is stopped. Restarting..." ec2_start_instances -i "$instance_id" ec2_wait_for_instance_running -i "$instance_id" echo "Your instance is running again." local instance_details instance_details="$(ec2_describe_instances -i "${instance_id}")" print_instance_details "${instance_details}" public_ip=$(echo "${instance_details}" | awk '{print $6}') echo "Every time your instance is restarted, its public IP address changes" connect_to_instance "$key_file_name" "$public_ip" echo -n "Press Enter when you're ready to continue the demo: " get_input echo_repeat "*" 88 echo_repeat "*" 88 echo "You can allocate an Elastic IP address and associate it with your instance" echo "to keep a consistent IP address even when your instance restarts." local result result=$(ec2_allocate_address -d vpc) || { errecho "Failed to allocate an address. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" "$instance_id" return 1 } local elastic_ip allocation_id elastic_ip=$(echo "$result" | awk '{print $1}') allocation_id=$(echo "$result" | awk '{print $2}') echo "Allocated static Elastic IP address: $elastic_ip" local association_id association_id=$(ec2_associate_address -i "$instance_id" -a "$allocation_id") || { errecho "Failed to associate an address. This demo will exit." clean_up "$key_name" "$key_file_name" "$security_group_id" "$instance_id" "$allocation_id" return 1 } echo "Associated your Elastic IP with your instance." echo "You can now use SSH to connect to your instance by using the Elastic IP." connect_to_instance "$key_file_name" "$elastic_ip" echo -n "Press Enter when you're ready to continue the demo: " get_input echo_repeat "*" 88 echo_repeat "*" 88 echo "Let's stop and start your instance to see what changes." echo "Stopping your instance and waiting until it's stopped..." ec2_stop_instances -i "$instance_id" ec2_wait_for_instance_stopped -i "$instance_id" echo "Your instance is stopped. Restarting..." ec2_start_instances -i "$instance_id" ec2_wait_for_instance_running -i "$instance_id" echo "Your instance is running again." local instance_details instance_details="$(ec2_describe_instances -i "${instance_id}")" print_instance_details "${instance_details}" echo "Because you have associated an Elastic IP with your instance, you can" echo "connect by using a consistent IP address after the instance restarts." connect_to_instance "$key_file_name" "$elastic_ip" echo -n "Press Enter when you're ready to continue the demo: " get_input echo_repeat "*" 88 echo_repeat "*" 88 if yes_no_input "Do you want to delete the resources created in this demo: (y/n) "; then clean_up "$key_name" "$key_file_name" "$security_group_id" "$instance_id" \ "$allocation_id" "$association_id" else echo "The following resources were not deleted." echo "Key pair: $key_name" echo "Key file: $key_file_name" echo "Security group: $security_group_id" echo "Instance: $instance_id" echo "Elastic IP address: $elastic_ip" fi } ############################################################################### # function clean_up # # This function cleans up the created resources. # $1 - The name of the ec2 key pair to delete. # $2 - The name of the key file to delete. # $3 - The ID of the security group to delete. # $4 - The ID of the instance to terminate. # $5 - The ID of the elastic IP address to release. # $6 - The ID of the elastic IP address to disassociate. # # Returns: # 0 - If successful. # 1 - If an error occurred. ############################################################################### function clean_up() { local result=0 local key_pair_name=$1 local key_file_name=$2 local security_group_id=$3 local instance_id=$4 local allocation_id=$5 local association_id=$6 if [ -n "$association_id" ]; then # bashsupport disable=BP2002 if (ec2_disassociate_address -a "$association_id"); then echo "Disassociated elastic IP address with ID $association_id" else errecho "The elastic IP address disassociation failed." result=1 fi fi if [ -n "$allocation_id" ]; then # bashsupport disable=BP2002 if (ec2_release_address -a "$allocation_id"); then echo "Released elastic IP address with ID $allocation_id" else errecho "The elastic IP address release failed." result=1 fi fi if [ -n "$instance_id" ]; then # bashsupport disable=BP2002 if (ec2_terminate_instances -i "$instance_id"); then echo "Started terminating instance with ID $instance_id" ec2_wait_for_instance_terminated -i "$instance_id" else errecho "The instance terminate failed." result=1 fi fi if [ -n "$security_group_id" ]; then # bashsupport disable=BP2002 if (ec2_delete_security_group -i "$security_group_id"); then echo "Deleted security group with ID $security_group_id" else errecho "The security group delete failed." result=1 fi fi if [ -n "$key_pair_name" ]; then # bashsupport disable=BP2002 if (ec2_delete_keypair -n "$key_pair_name"); then echo "Deleted key pair named $key_pair_name" else errecho "The key pair delete failed." result=1 fi fi if [ -n "$key_file_name" ]; then rm -f "$key_file_name" fi return $result } ############################################################################### # function ssm_get_parameters_by_path # # This function retrieves one or more parameters from the AWS Systems Manager Parameter Store # by specifying a parameter path. # # Parameters: # -p parameter_path - The path of the parameter(s) to retrieve. # # And: # 0 - If successful. # 1 - If it fails. ############################################################################### function ssm_get_parameters_by_path() { local parameter_path response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ssm_get_parameters_by_path" echo "Retrieves one or more parameters from the AWS Systems Manager Parameter Store by specifying a parameter path." echo " -p parameter_path - The path of the parameter(s) to retrieve." echo "" } # Retrieve the calling parameters. while getopts "p:h" option; do case "${option}" in p) parameter_path="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 if [[ -z "$parameter_path" ]]; then errecho "ERROR: You must provide a parameter path with the -p parameter." usage return 1 fi response=$(aws ssm get-parameters-by-path \ --path "$parameter_path" \ --query "Parameters[*].[Name, Value]" \ --output text) || { aws_cli_error_log $? errecho "ERROR: AWS reports get-parameters-by-path operation failed.$response" return 1 } echo "$response" return 0 } ############################################################################### # function print_instance_details # # This function prints the details of an Amazon Elastic Compute Cloud (Amazon EC2) instance. # # Parameters: # instance_details - The instance details in the format "InstanceId ImageId InstanceType KeyName VpcId PublicIpAddress State.Name". # # Returns: # 0 - If successful. # 1 - If it fails. ############################################################################### function print_instance_details() { local instance_details="$1" if [[ -z "${instance_details}" ]]; then echo "Error: Missing required instance details argument." return 1 fi local instance_id image_id instance_type key_name vpc_id public_ip state instance_id=$(echo "${instance_details}" | awk '{print $1}') image_id=$(echo "${instance_details}" | awk '{print $2}') instance_type=$(echo "${instance_details}" | awk '{print $3}') key_name=$(echo "${instance_details}" | awk '{print $4}') vpc_id=$(echo "${instance_details}" | awk '{print $5}') public_ip=$(echo "${instance_details}" | awk '{print $6}') state=$(echo "${instance_details}" | awk '{print $7}') echo " ID: ${instance_id}" echo " Image ID: ${image_id}" echo " Instance type: ${instance_type}" echo " Key name: ${key_name}" echo " VPC ID: ${vpc_id}" echo " Public IP: ${public_ip}" echo " State: ${state}" return 0 } ############################################################################### # function connect_to_instance # # This function displays the public IP address of an Amazon Elastic Compute Cloud (Amazon EC2) instance and prompts the user to connect to the instance via SSH. # # Parameters: # $1 - The name of the key file used to connect to the instance. # $2 - The public IP address of the instance. # # Returns: # None ############################################################################### function connect_to_instance() { local key_file_name="$1" local public_ip="$2" # Validate the input parameters if [[ -z "$key_file_name" ]]; then echo "ERROR: You must provide a key file name as the first argument." >&2 return 1 fi if [[ -z "$public_ip" ]]; then echo "ERROR: You must provide a public IP address as the second argument." >&2 return 1 fi # Display the public IP address and connection command echo "To connect, run the following command:" echo " ssh -i ${key_file_name} ec2-user@${public_ip}" # Prompt the user to connect to the instance if yes_no_input "Do you want to connect now? (y/n) "; then echo "After you have connected, you can return to this example by typing 'exit'" ssh -i "${key_file_name}" ec2-user@"${public_ip}" fi } ############################################################################### # function get_input # # This function gets user input from the command line. # # Outputs: # User input to stdout. # # Returns: # 0 ############################################################################### function get_input() { if [ -z "${mock_input+x}" ]; then read -r get_input_result else if [ "$mock_input_array_index" -lt ${#mock_input_array[@]} ]; then get_input_result="${mock_input_array[$mock_input_array_index]}" # bashsupport disable=BP2001 # shellcheck disable=SC2206 ((mock_input_array_index++)) echo -n "$get_input_result" else echo "MOCK_INPUT_ARRAY has no more elements" 1>&2 return 1 fi fi return 0 } ############################################################################### # function yes_no_input # # This function requests a yes/no answer from the user, following to a prompt. # # Parameters: # $1 - The prompt. # # Returns: # 0 - If yes. # 1 - If no. ############################################################################### function yes_no_input() { if [ -z "$1" ]; then echo "Internal error yes_no_input" return 1 fi local index=0 local response="N" while [[ $index -lt 10 ]]; do index=$((index + 1)) echo -n "$1" if ! get_input; then return 1 fi response=$(echo "$get_input_result" | tr '[:upper:]' '[:lower:]') if [ "$response" = "y" ] || [ "$response" = "n" ]; then break else echo -e "\nPlease enter or 'y' or 'n'." fi done echo if [ "$response" = "y" ]; then return 0 else return 1 fi } ############################################################################### # function integer_input # # This function prompts the user to enter an integer within a specified range # and validates the input. # # Parameters: # $1 - The prompt message to display to the user. # $2 - The minimum value of the accepted range. # $3 - The maximum value of the accepted range. # # Returns: # The valid integer input from the user. # If the input is invalid or out of range, the function will continue # prompting the user until a valid input is provided. ############################################################################### function integer_input() { local prompt="$1" local min_value="$2" local max_value="$3" local input="" while true; do # Display the prompt message and wait for user input echo -n "$prompt" if ! get_input; then return 1 fi input="$get_input_result" # Check if the input is a valid integer if [[ "$input" =~ ^-?[0-9]+$ ]]; then # Check if the input is within the specified range if ((input >= min_value && input <= max_value)); then return 0 else echo "Error: Input, $input, must be between $min_value and $max_value." fi else echo "Error: Invalid input- $input. Please enter an integer." fi done } ############################################################################### # function new_line_and_tab_to_list # # This function takes a string input containing newlines and tabs, and # converts it into a list (array) of elements. # # Parameters: # $1 - The input string containing newlines and tabs. # # Returns: # The resulting list (array) is stored in the global variable # 'list_result'. ############################################################################### function new_line_and_tab_to_list() { local input=$1 export list_result list_result=() mapfile -t lines <<<"$input" local line for line in "${lines[@]}"; do IFS=$'\t' read -ra parameters <<<"$line" list_result+=("${parameters[@]}") done } ############################################################################### # function echo_repeat # # This function prints a string 'n' times to stdout. # # Parameters: # $1 - The string. # $2 - Number of times to print the string. # # Outputs: # String 'n' times to stdout. # # Returns: # 0 ############################################################################### function echo_repeat() { local end=$2 for ((i = 0; i < end; i++)); do echo -n "$1" done echo }

The DynamoDB functions used in this scenario.

############################################################################### # function ec2_create_keypair # # This function creates an Amazon Elastic Compute Cloud (Amazon EC2) ED25519 or 2048-bit RSA key pair # and writes it to a file. # # Parameters: # -n key_pair_name - A key pair name. # -f file_path - File to store the key pair. # # And: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_create_keypair() { local key_pair_name file_path response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_create_keypair" echo "Creates an Amazon Elastic Compute Cloud (Amazon EC2) ED25519 or 2048-bit RSA key pair" echo " and writes it to a file." echo " -n key_pair_name - A key pair name." echo " -f file_path - File to store the key pair." echo "" } # Retrieve the calling parameters. while getopts "n:f:h" option; do case "${option}" in n) key_pair_name="${OPTARG}" ;; f) file_path="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 if [[ -z "$key_pair_name" ]]; then errecho "ERROR: You must provide a key name with the -n parameter." usage return 1 fi if [[ -z "$file_path" ]]; then errecho "ERROR: You must provide a file path with the -f parameter." usage return 1 fi response=$(aws ec2 create-key-pair \ --key-name "$key_pair_name" \ --query 'KeyMaterial' \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports create-access-key operation failed.$response" return 1 } if [[ -n "$file_path" ]]; then echo "$response" >"$file_path" fi return 0 } ############################################################################### # function ec2_describe_key_pairs # # This function describes one or more Amazon Elastic Compute Cloud (Amazon EC2) key pairs. # # Parameters: # -h - Display help. # # And: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_describe_key_pairs() { local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_describe_key_pairs" echo "Describes one or more Amazon Elastic Compute Cloud (Amazon EC2) key pairs." echo " -h - Display help." echo "" } # Retrieve the calling parameters. while getopts "h" option; do case "${option}" in h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 local response response=$(aws ec2 describe-key-pairs \ --query 'KeyPairs[*].[KeyName, KeyFingerprint]' \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports describe-key-pairs operation failed.$response" return 1 } echo "$response" return 0 } ############################################################################### # function ec2_create_security_group # # This function creates an Amazon Elastic Compute Cloud (Amazon EC2) security group. # # Parameters: # -n security_group_name - The name of the security group. # -d security_group_description - The description of the security group. # # Returns: # The ID of the created security group, or an error message if the operation fails. # And: # 0 - If successful. # 1 - If it fails. # ############################################################################### function ec2_create_security_group() { local security_group_name security_group_description response # Function to display usage information function usage() { echo "function ec2_create_security_group" echo "Creates an Amazon Elastic Compute Cloud (Amazon EC2) security group." echo " -n security_group_name - The name of the security group." echo " -d security_group_description - The description of the security group." echo "" } # Parse the command-line arguments while getopts "n:d:h" option; do case "${option}" in n) security_group_name="${OPTARG}" ;; d) security_group_description="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 # Validate the input parameters if [[ -z "$security_group_name" ]]; then errecho "ERROR: You must provide a security group name with the -n parameter." return 1 fi if [[ -z "$security_group_description" ]]; then errecho "ERROR: You must provide a security group description with the -d parameter." return 1 fi # Create the security group response=$(aws ec2 create-security-group \ --group-name "$security_group_name" \ --description "$security_group_description" \ --query "GroupId" \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports create-security-group operation failed." errecho "$response" return 1 } echo "$response" return 0 } ############################################################################### # function ec2_describe_security_groups # # This function describes one or more Amazon Elastic Compute Cloud (Amazon EC2) security groups. # # Parameters: # -g security_group_id - The ID of the security group to describe (optional). # # And: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_describe_security_groups() { local security_group_id response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_describe_security_groups" echo "Describes one or more Amazon Elastic Compute Cloud (Amazon EC2) security groups." echo " -g security_group_id - The ID of the security group to describe (optional)." echo "" } # Retrieve the calling parameters. while getopts "g:h" option; do case "${option}" in g) security_group_id="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 local query="SecurityGroups[*].[GroupName, GroupId, VpcId, IpPermissions[*].[IpProtocol, FromPort, ToPort, IpRanges[*].CidrIp]]" if [[ -n "$security_group_id" ]]; then response=$(aws ec2 describe-security-groups --group-ids "$security_group_id" --query "${query}" --output text) else response=$(aws ec2 describe-security-groups --query "${query}" --output text) fi local error_code=${?} if [[ $error_code -ne 0 ]]; then aws_cli_error_log $error_code errecho "ERROR: AWS reports describe-security-groups operation failed.$response" return 1 fi echo "$response" return 0 } ############################################################################### # function ec2_authorize_security_group_ingress # # This function authorizes an ingress rule for an Amazon Elastic Compute Cloud (Amazon EC2) security group. # # Parameters: # -g security_group_id - The ID of the security group. # -i ip_address - The IP address or CIDR block to authorize. # -p protocol - The protocol to authorize (e.g., tcp, udp, icmp). # -f from_port - The start of the port range to authorize. # -t to_port - The end of the port range to authorize. # # And: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_authorize_security_group_ingress() { local security_group_id ip_address protocol from_port to_port response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_authorize_security_group_ingress" echo "Authorizes an ingress rule for an Amazon Elastic Compute Cloud (Amazon EC2) security group." echo " -g security_group_id - The ID of the security group." echo " -i ip_address - The IP address or CIDR block to authorize." echo " -p protocol - The protocol to authorize (e.g., tcp, udp, icmp)." echo " -f from_port - The start of the port range to authorize." echo " -t to_port - The end of the port range to authorize." echo "" } # Retrieve the calling parameters. while getopts "g:i:p:f:t:h" option; do case "${option}" in g) security_group_id="${OPTARG}" ;; i) ip_address="${OPTARG}" ;; p) protocol="${OPTARG}" ;; f) from_port="${OPTARG}" ;; t) to_port="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 if [[ -z "$security_group_id" ]]; then errecho "ERROR: You must provide a security group ID with the -g parameter." usage return 1 fi if [[ -z "$ip_address" ]]; then errecho "ERROR: You must provide an IP address or CIDR block with the -i parameter." usage return 1 fi if [[ -z "$protocol" ]]; then errecho "ERROR: You must provide a protocol with the -p parameter." usage return 1 fi if [[ -z "$from_port" ]]; then errecho "ERROR: You must provide a start port with the -f parameter." usage return 1 fi if [[ -z "$to_port" ]]; then errecho "ERROR: You must provide an end port with the -t parameter." usage return 1 fi response=$(aws ec2 authorize-security-group-ingress \ --group-id "$security_group_id" \ --cidr "${ip_address}/32" \ --protocol "$protocol" \ --port "$from_port-$to_port" \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports authorize-security-group-ingress operation failed.$response" return 1 } return 0 } ############################################################################### # function ec2_describe_images # # This function describes one or more Amazon Elastic Compute Cloud (Amazon EC2) images. # # Parameters: # -i image_ids - A space-separated list of image IDs (optional). # -h - Display help. # # And: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_describe_images() { local image_ids response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_describe_images" echo "Describes one or more Amazon Elastic Compute Cloud (Amazon EC2) images." echo " -i image_ids - A space-separated list of image IDs (optional)." echo " -h - Display help." echo "" } # Retrieve the calling parameters. while getopts "i:h" option; do case "${option}" in i) image_ids="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 local aws_cli_args=() if [[ -n "$image_ids" ]]; then # shellcheck disable=SC2206 aws_cli_args+=("--image-ids" $image_ids) fi response=$(aws ec2 describe-images \ "${aws_cli_args[@]}" \ --query 'Images[*].[Description,Architecture,ImageId]' \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports describe-images operation failed.$response" return 1 } echo "$response" return 0 } ############################################################################### # ec2_describe_instance_types # # This function describes EC2 instance types filtered by processor architecture # and optionally by instance type. It takes the following arguments: # # -a, --architecture ARCHITECTURE Specify the processor architecture (e.g., x86_64) # -t, --type INSTANCE_TYPE Comma-separated list of instance types (e.g., t2.micro) # -h, --help Show the usage help # # The function prints the instance type and supported architecture for each # matching instance type. ############################################################################### function ec2_describe_instance_types() { local architecture="" local instance_types="" # bashsupport disable=BP5008 function usage() { echo "Usage: ec2_describe_instance_types [-a|--architecture ARCHITECTURE] [-t|--type INSTANCE_TYPE] [-h|--help]" echo " -a, --architecture ARCHITECTURE Specify the processor architecture (e.g., x86_64)" echo " -t, --type INSTANCE_TYPE Comma-separated list of instance types (e.g., t2.micro)" echo " -h, --help Show this help message" } while [[ $# -gt 0 ]]; do case "$1" in -a | --architecture) architecture="$2" shift 2 ;; -t | --type) instance_types="$2" shift 2 ;; -h | --help) usage return 0 ;; *) echo "Unknown argument: $1" return 1 ;; esac done if [[ -z "$architecture" ]]; then errecho "Error: Architecture not specified." usage return 1 fi if [[ -z "$instance_types" ]]; then errecho "Error: Instance type not specified." usage return 1 fi local tmp_json_file="temp_ec2.json" echo -n '[ { "Name": "processor-info.supported-architecture", "Values": [' >"$tmp_json_file" local items IFS=',' read -ra items <<<"$architecture" local array_size array_size=${#items[@]} for i in $(seq 0 $((array_size - 1))); do echo -n '"'"${items[$i]}"'"' >>"$tmp_json_file" if [[ $i -lt $((array_size - 1)) ]]; then echo -n ',' >>"$tmp_json_file" fi done echo -n ']}, { "Name": "instance-type", "Values": [' >>"$tmp_json_file" IFS=',' read -ra items <<<"$instance_types" local array_size array_size=${#items[@]} for i in $(seq 0 $((array_size - 1))); do echo -n '"'"${items[$i]}"'"' >>"$tmp_json_file" if [[ $i -lt $((array_size - 1)) ]]; then echo -n ',' >>"$tmp_json_file" fi done echo -n ']}]' >>"$tmp_json_file" local response response=$(aws ec2 describe-instance-types --filters file://"$tmp_json_file" \ --query 'InstanceTypes[*].[InstanceType]' --output text) local error_code=$? rm "$tmp_json_file" if [[ $error_code -ne 0 ]]; then aws_cli_error_log $error_code echo "ERROR: AWS reports describe-instance-types operation failed." return 1 fi echo "$response" return 0 } ############################################################################### # function ec2_run_instances # # This function launches one or more Amazon Elastic Compute Cloud (Amazon EC2) instances. # # Parameters: # -i image_id - The ID of the Amazon Machine Image (AMI) to use. # -t instance_type - The instance type to use (e.g., t2.micro). # -k key_pair_name - The name of the key pair to use. # -s security_group_id - The ID of the security group to use. # -c count - The number of instances to launch (default: 1). # -h - Display help. # # Returns: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_run_instances() { local image_id instance_type key_pair_name security_group_id count response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_run_instances" echo "Launches one or more Amazon Elastic Compute Cloud (Amazon EC2) instances." echo " -i image_id - The ID of the Amazon Machine Image (AMI) to use." echo " -t instance_type - The instance type to use (e.g., t2.micro)." echo " -k key_pair_name - The name of the key pair to use." echo " -s security_group_id - The ID of the security group to use." echo " -c count - The number of instances to launch (default: 1)." echo " -h - Display help." echo "" } # Retrieve the calling parameters. while getopts "i:t:k:s:c:h" option; do case "${option}" in i) image_id="${OPTARG}" ;; t) instance_type="${OPTARG}" ;; k) key_pair_name="${OPTARG}" ;; s) security_group_id="${OPTARG}" ;; c) count="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 if [[ -z "$image_id" ]]; then errecho "ERROR: You must provide an Amazon Machine Image (AMI) ID with the -i parameter." usage return 1 fi if [[ -z "$instance_type" ]]; then errecho "ERROR: You must provide an instance type with the -t parameter." usage return 1 fi if [[ -z "$key_pair_name" ]]; then errecho "ERROR: You must provide a key pair name with the -k parameter." usage return 1 fi if [[ -z "$security_group_id" ]]; then errecho "ERROR: You must provide a security group ID with the -s parameter." usage return 1 fi if [[ -z "$count" ]]; then count=1 fi response=$(aws ec2 run-instances \ --image-id "$image_id" \ --instance-type "$instance_type" \ --key-name "$key_pair_name" \ --security-group-ids "$security_group_id" \ --count "$count" \ --query 'Instances[*].[InstanceId]' \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports run-instances operation failed.$response" return 1 } echo "$response" return 0 } ############################################################################### # function ec2_describe_instances # # This function describes one or more Amazon Elastic Compute Cloud (Amazon EC2) instances. # # Parameters: # -i instance_id - The ID of the instance to describe (optional). # -q query - The query to filter the response (optional). # -h - Display help. # # Returns: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_describe_instances() { local instance_id query response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_describe_instances" echo "Describes one or more Amazon Elastic Compute Cloud (Amazon EC2) instances." echo " -i instance_id - The ID of the instance to describe (optional)." echo " -q query - The query to filter the response (optional)." echo " -h - Display help." echo "" } # Retrieve the calling parameters. while getopts "i:q:h" option; do case "${option}" in i) instance_id="${OPTARG}" ;; q) query="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 local aws_cli_args=() if [[ -n "$instance_id" ]]; then # shellcheck disable=SC2206 aws_cli_args+=("--instance-ids" $instance_id) fi local query_arg="" if [[ -n "$query" ]]; then query_arg="--query '$query'" else query_arg="--query Reservations[*].Instances[*].[InstanceId,ImageId,InstanceType,KeyName,VpcId,PublicIpAddress,State.Name]" fi # shellcheck disable=SC2086 response=$(aws ec2 describe-instances \ "${aws_cli_args[@]}" \ $query_arg \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports describe-instances operation failed.$response" return 1 } echo "$response" return 0 } ############################################################################### # function ec2_stop_instances # # This function stops one or more Amazon Elastic Compute Cloud (Amazon EC2) instances. # # Parameters: # -i instance_id - The ID(s) of the instance(s) to stop (comma-separated). # -h - Display help. # # Returns: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_stop_instances() { local instance_ids local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_stop_instances" echo "Stops one or more Amazon Elastic Compute Cloud (Amazon EC2) instances." echo " -i instance_id - The ID(s) of the instance(s) to stop (comma-separated)." echo " -h - Display help." echo "" } # Retrieve the calling parameters. while getopts "i:h" option; do case "${option}" in i) instance_ids="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 if [[ -z "$instance_ids" ]]; then errecho "ERROR: You must provide one or more instance IDs with the -i parameter." usage return 1 fi response=$(aws ec2 stop-instances \ --instance-ids "${instance_ids}") || { aws_cli_error_log ${?} errecho "ERROR: AWS reports stop-instances operation failed with $response." return 1 } return 0 } ############################################################################### # function ec2_start_instances # # This function starts one or more Amazon Elastic Compute Cloud (Amazon EC2) instances. # # Parameters: # -i instance_id - The ID(s) of the instance(s) to start (comma-separated). # -h - Display help. # # Returns: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_start_instances() { local instance_ids local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_start_instances" echo "Starts one or more Amazon Elastic Compute Cloud (Amazon EC2) instances." echo " -i instance_id - The ID(s) of the instance(s) to start (comma-separated)." echo " -h - Display help." echo "" } # Retrieve the calling parameters. while getopts "i:h" option; do case "${option}" in i) instance_ids="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 if [[ -z "$instance_ids" ]]; then errecho "ERROR: You must provide one or more instance IDs with the -i parameter." usage return 1 fi response=$(aws ec2 start-instances \ --instance-ids "${instance_ids}") || { aws_cli_error_log ${?} errecho "ERROR: AWS reports start-instances operation failed with $response." return 1 } return 0 } ############################################################################### # function ec2_allocate_address # # This function allocates an Elastic IP address for use with Amazon Elastic Compute Cloud (Amazon EC2) instances in a specific AWS Region. # # Parameters: # -d domain - The domain for the Elastic IP address (either 'vpc' or 'standard'). # # Returns: # The allocated Elastic IP address, or an error message if the operation fails. # And: # 0 - If successful. # 1 - If it fails. # ############################################################################### function ec2_allocate_address() { local domain response # Function to display usage information function usage() { echo "function ec2_allocate_address" echo "Allocates an Elastic IP address for use with Amazon Elastic Compute Cloud (Amazon EC2) instances in a specific AWS Region." echo " -d domain - The domain for the Elastic IP address (either 'vpc' or 'standard')." echo "" } # Parse the command-line arguments while getopts "d:h" option; do case "${option}" in d) domain="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 # Validate the input parameters if [[ -z "$domain" ]]; then errecho "ERROR: You must provide a domain with the -d parameter (either 'vpc' or 'standard')." return 1 fi if [[ "$domain" != "vpc" && "$domain" != "standard" ]]; then errecho "ERROR: Invalid domain value. Must be either 'vpc' or 'standard'." return 1 fi # Allocate the Elastic IP address response=$(aws ec2 allocate-address \ --domain "$domain" \ --query "[PublicIp,AllocationId]" \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports allocate-address operation failed." errecho "$response" return 1 } echo "$response" return 0 } ############################################################################### # function ec2_associate_address # # This function associates an Elastic IP address with an Amazon Elastic Compute Cloud (Amazon EC2) instance. # # Parameters: # -a allocation_id - The allocation ID of the Elastic IP address to associate. # -i instance_id - The ID of the EC2 instance to associate the Elastic IP address with. # # Returns: # 0 - If successful. # 1 - If it fails. # ############################################################################### function ec2_associate_address() { local allocation_id instance_id response # Function to display usage information function usage() { echo "function ec2_associate_address" echo "Associates an Elastic IP address with an Amazon Elastic Compute Cloud (Amazon EC2) instance." echo " -a allocation_id - The allocation ID of the Elastic IP address to associate." echo " -i instance_id - The ID of the EC2 instance to associate the Elastic IP address with." echo "" } # Parse the command-line arguments while getopts "a:i:h" option; do case "${option}" in a) allocation_id="${OPTARG}" ;; i) instance_id="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 # Validate the input parameters if [[ -z "$allocation_id" ]]; then errecho "ERROR: You must provide an allocation ID with the -a parameter." return 1 fi if [[ -z "$instance_id" ]]; then errecho "ERROR: You must provide an instance ID with the -i parameter." return 1 fi # Associate the Elastic IP address response=$(aws ec2 associate-address \ --allocation-id "$allocation_id" \ --instance-id "$instance_id" \ --query "AssociationId" \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports associate-address operation failed." errecho "$response" return 1 } echo "$response" return 0 } ############################################################################### # function ec2_disassociate_address # # This function disassociates an Elastic IP address from an Amazon Elastic Compute Cloud (Amazon EC2) instance. # # Parameters: # -a association_id - The association ID that represents the association of the Elastic IP address with an instance. # # And: # 0 - If successful. # 1 - If it fails. # ############################################################################### function ec2_disassociate_address() { local association_id response # Function to display usage information function usage() { echo "function ec2_disassociate_address" echo "Disassociates an Elastic IP address from an Amazon Elastic Compute Cloud (Amazon EC2) instance." echo " -a association_id - The association ID that represents the association of the Elastic IP address with an instance." echo "" } # Parse the command-line arguments while getopts "a:h" option; do case "${option}" in a) association_id="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 # Validate the input parameters if [[ -z "$association_id" ]]; then errecho "ERROR: You must provide an association ID with the -a parameter." return 1 fi response=$(aws ec2 disassociate-address \ --association-id "$association_id") || { aws_cli_error_log ${?} errecho "ERROR: AWS reports disassociate-address operation failed." errecho "$response" return 1 } return 0 } ############################################################################### # function ec2_release_address # # This function releases an Elastic IP address from an Amazon Elastic Compute Cloud (Amazon EC2) instance. # # Parameters: # -a allocation_id - The allocation ID of the Elastic IP address to release. # # Returns: # 0 - If successful. # 1 - If it fails. # ############################################################################### function ec2_release_address() { local allocation_id response # Function to display usage information function usage() { echo "function ec2_release_address" echo "Releases an Elastic IP address from an Amazon Elastic Compute Cloud (Amazon EC2) instance." echo " -a allocation_id - The allocation ID of the Elastic IP address to release." echo "" } # Parse the command-line arguments while getopts "a:h" option; do case "${option}" in a) allocation_id="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 # Validate the input parameters if [[ -z "$allocation_id" ]]; then errecho "ERROR: You must provide an allocation ID with the -a parameter." return 1 fi response=$(aws ec2 release-address \ --allocation-id "$allocation_id") || { aws_cli_error_log ${?} errecho "ERROR: AWS reports release-address operation failed." errecho "$response" return 1 } return 0 } ############################################################################### # function ec2_terminate_instances # # This function terminates one or more Amazon Elastic Compute Cloud (Amazon EC2) # instances using the AWS CLI. # # Parameters: # -i instance_ids - A space-separated list of instance IDs. # -h - Display help. # # Returns: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_terminate_instances() { local instance_ids response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_terminate_instances" echo "Terminates one or more Amazon Elastic Compute Cloud (Amazon EC2) instances." echo " -i instance_ids - A space-separated list of instance IDs." echo " -h - Display help." echo "" } # Retrieve the calling parameters. while getopts "i:h" option; do case "${option}" in i) instance_ids="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 # Check if instance ID is provided if [[ -z "${instance_ids}" ]]; then echo "Error: Missing required instance IDs parameter." usage return 1 fi # shellcheck disable=SC2086 response=$(aws ec2 terminate-instances \ "--instance-ids" $instance_ids \ --query 'TerminatingInstances[*].[InstanceId,CurrentState.Name]' \ --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports terminate-instances operation failed.$response" return 1 } return 0 } ############################################################################### # function ec2_delete_security_group # # This function deletes an Amazon Elastic Compute Cloud (Amazon EC2) security group. # # Parameters: # -i security_group_id - The ID of the security group to delete. # # And: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_delete_security_group() { local security_group_id response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_delete_security_group" echo "Deletes an Amazon Elastic Compute Cloud (Amazon EC2) security group." echo " -i security_group_id - The ID of the security group to delete." echo "" } # Retrieve the calling parameters. while getopts "i:h" option; do case "${option}" in i) security_group_id="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 if [[ -z "$security_group_id" ]]; then errecho "ERROR: You must provide a security group ID with the -i parameter." usage return 1 fi response=$(aws ec2 delete-security-group --group-id "$security_group_id" --output text) || { aws_cli_error_log ${?} errecho "ERROR: AWS reports delete-security-group operation failed.$response" return 1 } return 0 } ############################################################################### # function ec2_delete_keypair # # This function deletes an Amazon EC2 ED25519 or 2048-bit RSA key pair. # # Parameters: # -n key_pair_name - A key pair name. # # And: # 0 - If successful. # 1 - If it fails. ############################################################################### function ec2_delete_keypair() { local key_pair_name response local option OPTARG # Required to use getopts command in a function. # bashsupport disable=BP5008 function usage() { echo "function ec2_delete_keypair" echo "Deletes an Amazon EC2 ED25519 or 2048-bit RSA key pair." echo " -n key_pair_name - A key pair name." echo "" } # Retrieve the calling parameters. while getopts "n:h" option; do case "${option}" in n) key_pair_name="${OPTARG}" ;; h) usage return 0 ;; \?) echo "Invalid parameter" usage return 1 ;; esac done export OPTIND=1 if [[ -z "$key_pair_name" ]]; then errecho "ERROR: You must provide a key pair name with the -n parameter." usage return 1 fi response=$(aws ec2 delete-key-pair \ --key-name "$key_pair_name") || { aws_cli_error_log ${?} errecho "ERROR: AWS reports delete-key-pair operation failed.$response" return 1 } return 0 }

The utility functions used in this scenario.

############################################################################### # function errecho # # This function outputs everything sent to it to STDERR (standard error output). ############################################################################### function errecho() { printf "%s\n" "$*" 1>&2 } ############################################################################## # function aws_cli_error_log() # # This function is used to log the error messages from the AWS CLI. # # The function expects the following argument: # $1 - The error code returned by the AWS CLI. # # Returns: # 0: - Success. # ############################################################################## function aws_cli_error_log() { local err_code=$1 errecho "Error code : $err_code" if [ "$err_code" == 1 ]; then errecho " One or more S3 transfers failed." elif [ "$err_code" == 2 ]; then errecho " Command line failed to parse." elif [ "$err_code" == 130 ]; then errecho " Process received SIGINT." elif [ "$err_code" == 252 ]; then errecho " Command syntax invalid." elif [ "$err_code" == 253 ]; then errecho " The system environment or configuration was invalid." elif [ "$err_code" == 254 ]; then errecho " The service returned an error." elif [ "$err_code" == 255 ]; then errecho " 255 is a catch-all error." fi return 0 }
Java
SDK for Java 2.x
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Amazon Code Examples Repository.

/** * Before running this Java (v2) code example, set up your development * environment, including your credentials. * * For more information, see the following documentation topic: * * https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html * * This Java example performs the following tasks: * * 1. Creates an RSA key pair and saves the private key data as a .pem file. * 2. Lists key pairs. * 3. Creates a security group for the default VPC. * 4. Displays security group information. * 5. Gets a list of Amazon Linux 2 AMIs and selects one. * 6. Gets more information about the image. * 7. Gets a list of instance types that are compatible with the selected AMI’s * architecture. * 8. Creates an instance with the key pair, security group, AMI, and an * instance type. * 9. Displays information about the instance. * 10. Stops the instance and waits for it to stop. * 11. Starts the instance and waits for it to start. * 12. Allocates an Elastic IP address and associates it with the instance. * 13. Displays SSH connection info for the instance. * 14. Disassociates and deletes the Elastic IP address. * 15. Terminates the instance and waits for it to terminate. * 16. Deletes the security group. * 17. Deletes the key pair. */ public class EC2Scenario { public static final String DASHES = new String(new char[80]).replace("\0", "-"); public static void main(String[] args) throws InterruptedException { final String usage = """ Usage: <keyName> <fileName> <groupName> <groupDesc> <vpcId> Where: keyName - A key pair name (for example, TestKeyPair).\s fileName - A file name where the key information is written to.\s groupName - The name of the security group.\s groupDesc - The description of the security group.\s vpcId - A VPC Id value. You can get this value from the AWS Management Console.\s myIpAddress - The IP address of your development machine.\s """; if (args.length != 6) { System.out.println(usage); System.exit(1); } String keyName = args[0]; String fileName = args[1]; String groupName = args[2]; String groupDesc = args[3]; String vpcId = args[4]; String myIpAddress = args[5]; Region region = Region.US_WEST_2; Ec2Client ec2 = Ec2Client.builder() .region(region) .build(); SsmClient ssmClient = SsmClient.builder() .region(region) .build(); System.out.println(DASHES); System.out.println("Welcome to the Amazon EC2 example scenario."); System.out.println(DASHES); System.out.println(DASHES); System.out.println("1. Create an RSA key pair and save the private key material as a .pem file."); createKeyPair(ec2, keyName, fileName); System.out.println(DASHES); System.out.println(DASHES); System.out.println("2. List key pairs."); describeKeys(ec2); System.out.println(DASHES); System.out.println(DASHES); System.out.println("3. Create a security group."); String groupId = createSecurityGroup(ec2, groupName, groupDesc, vpcId, myIpAddress); System.out.println(DASHES); System.out.println(DASHES); System.out.println("4. Display security group info for the newly created security group."); describeSecurityGroups(ec2, groupId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("5. Get a list of Amazon Linux 2 AMIs and selects one with amzn2 in the name."); String instanceId = getParaValues(ssmClient); System.out.println("The instance Id is " + instanceId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("6. Get more information about an amzn2 image."); String amiValue = describeImage(ec2, instanceId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("7. Get a list of instance types."); String instanceType = getInstanceTypes(ec2); System.out.println("The instance type is " + instanceType); System.out.println(DASHES); System.out.println(DASHES); System.out.println("8. Create an instance."); String newInstanceId = runInstance(ec2, instanceType, keyName, groupName, amiValue); System.out.println("The instance Id is " + newInstanceId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("9. Display information about the running instance. "); String ipAddress = describeEC2Instances(ec2, newInstanceId); System.out.println("You can SSH to the instance using this command:"); System.out.println("ssh -i " + fileName + "ec2-user@" + ipAddress); System.out.println(DASHES); System.out.println(DASHES); System.out.println("10. Stop the instance and use a waiter."); stopInstance(ec2, newInstanceId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("11. Start the instance and use a waiter."); startInstance(ec2, newInstanceId); ipAddress = describeEC2Instances(ec2, newInstanceId); System.out.println("You can SSH to the instance using this command:"); System.out.println("ssh -i " + fileName + "ec2-user@" + ipAddress); System.out.println(DASHES); System.out.println(DASHES); System.out.println("12. Allocate an Elastic IP address and associate it with the instance."); String allocationId = allocateAddress(ec2); System.out.println("The allocation Id value is " + allocationId); String associationId = associateAddress(ec2, newInstanceId, allocationId); System.out.println("The associate Id value is " + associationId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("13. Describe the instance again."); ipAddress = describeEC2Instances(ec2, newInstanceId); System.out.println("You can SSH to the instance using this command:"); System.out.println("ssh -i " + fileName + "ec2-user@" + ipAddress); System.out.println(DASHES); System.out.println(DASHES); System.out.println("14. Disassociate and release the Elastic IP address."); disassociateAddress(ec2, associationId); releaseEC2Address(ec2, allocationId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("15. Terminate the instance and use a waiter."); terminateEC2(ec2, newInstanceId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("16. Delete the security group."); deleteEC2SecGroup(ec2, groupId); System.out.println(DASHES); System.out.println(DASHES); System.out.println("17. Delete the key."); deleteKeys(ec2, keyName); System.out.println(DASHES); System.out.println(DASHES); System.out.println("You successfully completed the Amazon EC2 scenario."); System.out.println(DASHES); ec2.close(); } public static void deleteEC2SecGroup(Ec2Client ec2, String groupId) { try { DeleteSecurityGroupRequest request = DeleteSecurityGroupRequest.builder() .groupId(groupId) .build(); ec2.deleteSecurityGroup(request); System.out.println("Successfully deleted security group with Id " + groupId); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } public static void terminateEC2(Ec2Client ec2, String instanceId) { try { Ec2Waiter ec2Waiter = Ec2Waiter.builder() .overrideConfiguration(b -> b.maxAttempts(100)) .client(ec2) .build(); TerminateInstancesRequest ti = TerminateInstancesRequest.builder() .instanceIds(instanceId) .build(); System.out.println("Use an Ec2Waiter to wait for the instance to terminate. This will take a few minutes."); ec2.terminateInstances(ti); DescribeInstancesRequest instanceRequest = DescribeInstancesRequest.builder() .instanceIds(instanceId) .build(); WaiterResponse<DescribeInstancesResponse> waiterResponse = ec2Waiter .waitUntilInstanceTerminated(instanceRequest); waiterResponse.matched().response().ifPresent(System.out::println); System.out.println("Successfully started instance " + instanceId); System.out.println(instanceId + " is terminated!"); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } public static void deleteKeys(Ec2Client ec2, String keyPair) { try { DeleteKeyPairRequest request = DeleteKeyPairRequest.builder() .keyName(keyPair) .build(); ec2.deleteKeyPair(request); System.out.println("Successfully deleted key pair named " + keyPair); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } public static void releaseEC2Address(Ec2Client ec2, String allocId) { try { ReleaseAddressRequest request = ReleaseAddressRequest.builder() .allocationId(allocId) .build(); ec2.releaseAddress(request); System.out.println("Successfully released Elastic IP address " + allocId); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } public static void disassociateAddress(Ec2Client ec2, String associationId) { try { DisassociateAddressRequest addressRequest = DisassociateAddressRequest.builder() .associationId(associationId) .build(); ec2.disassociateAddress(addressRequest); System.out.println("You successfully disassociated the address!"); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } public static String associateAddress(Ec2Client ec2, String instanceId, String allocationId) { try { AssociateAddressRequest associateRequest = AssociateAddressRequest.builder() .instanceId(instanceId) .allocationId(allocationId) .build(); AssociateAddressResponse associateResponse = ec2.associateAddress(associateRequest); return associateResponse.associationId(); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } return ""; } public static String allocateAddress(Ec2Client ec2) { try { AllocateAddressRequest allocateRequest = AllocateAddressRequest.builder() .domain(DomainType.VPC) .build(); AllocateAddressResponse allocateResponse = ec2.allocateAddress(allocateRequest); return allocateResponse.allocationId(); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } return ""; } public static void startInstance(Ec2Client ec2, String instanceId) { Ec2Waiter ec2Waiter = Ec2Waiter.builder() .overrideConfiguration(b -> b.maxAttempts(100)) .client(ec2) .build(); StartInstancesRequest request = StartInstancesRequest.builder() .instanceIds(instanceId) .build(); System.out.println("Use an Ec2Waiter to wait for the instance to run. This will take a few minutes."); ec2.startInstances(request); DescribeInstancesRequest instanceRequest = DescribeInstancesRequest.builder() .instanceIds(instanceId) .build(); WaiterResponse<DescribeInstancesResponse> waiterResponse = ec2Waiter.waitUntilInstanceRunning(instanceRequest); waiterResponse.matched().response().ifPresent(System.out::println); System.out.println("Successfully started instance " + instanceId); } public static void stopInstance(Ec2Client ec2, String instanceId) { Ec2Waiter ec2Waiter = Ec2Waiter.builder() .overrideConfiguration(b -> b.maxAttempts(100)) .client(ec2) .build(); StopInstancesRequest request = StopInstancesRequest.builder() .instanceIds(instanceId) .build(); System.out.println("Use an Ec2Waiter to wait for the instance to stop. This will take a few minutes."); ec2.stopInstances(request); DescribeInstancesRequest instanceRequest = DescribeInstancesRequest.builder() .instanceIds(instanceId) .build(); WaiterResponse<DescribeInstancesResponse> waiterResponse = ec2Waiter.waitUntilInstanceStopped(instanceRequest); waiterResponse.matched().response().ifPresent(System.out::println); System.out.println("Successfully stopped instance " + instanceId); } public static String describeEC2Instances(Ec2Client ec2, String newInstanceId) { try { String pubAddress = ""; boolean isRunning = false; DescribeInstancesRequest request = DescribeInstancesRequest.builder() .instanceIds(newInstanceId) .build(); while (!isRunning) { DescribeInstancesResponse response = ec2.describeInstances(request); String state = response.reservations().get(0).instances().get(0).state().name().name(); if (state.compareTo("RUNNING") == 0) { System.out.println("Image id is " + response.reservations().get(0).instances().get(0).imageId()); System.out.println( "Instance type is " + response.reservations().get(0).instances().get(0).instanceType()); System.out.println( "Instance state is " + response.reservations().get(0).instances().get(0).state().name()); pubAddress = response.reservations().get(0).instances().get(0).publicIpAddress(); System.out.println("Instance address is " + pubAddress); isRunning = true; } } return pubAddress; } catch (SsmException e) { System.err.println(e.getMessage()); System.exit(1); } return ""; } public static String runInstance(Ec2Client ec2, String instanceType, String keyName, String groupName, String amiId) { try { RunInstancesRequest runRequest = RunInstancesRequest.builder() .instanceType(instanceType) .keyName(keyName) .securityGroups(groupName) .maxCount(1) .minCount(1) .imageId(amiId) .build(); System.out.println("Going to start an EC2 instance using a waiter"); RunInstancesResponse response = ec2.runInstances(runRequest); String instanceIdVal = response.instances().get(0).instanceId(); ec2.waiter().waitUntilInstanceRunning(r -> r.instanceIds(instanceIdVal)); System.out.println("Successfully started EC2 instance " + instanceIdVal + " based on AMI " + amiId); return instanceIdVal; } catch (SsmException e) { System.err.println(e.getMessage()); System.exit(1); } return ""; } // Get a list of instance types. public static String getInstanceTypes(Ec2Client ec2) { String instanceType; try { DescribeInstanceTypesRequest typesRequest = DescribeInstanceTypesRequest.builder() .maxResults(10) .build(); DescribeInstanceTypesResponse response = ec2.describeInstanceTypes(typesRequest); List<InstanceTypeInfo> instanceTypes = response.instanceTypes(); for (InstanceTypeInfo type : instanceTypes) { System.out.println("The memory information of this type is " + type.memoryInfo().sizeInMiB()); System.out.println("Network information is " + type.networkInfo().toString()); System.out.println("Instance type is " + type.instanceType().toString()); instanceType = type.instanceType().toString(); if (instanceType.compareTo("t2.2xlarge") == 0){ return instanceType; } } } catch (SsmException e) { System.err.println(e.getMessage()); System.exit(1); } return ""; } // Display the Description field that corresponds to the instance Id value. public static String describeImage(Ec2Client ec2, String instanceId) { try { DescribeImagesRequest imagesRequest = DescribeImagesRequest.builder() .imageIds(instanceId) .build(); DescribeImagesResponse response = ec2.describeImages(imagesRequest); System.out.println("The description of the first image is " + response.images().get(0).description()); System.out.println("The name of the first image is " + response.images().get(0).name()); // Return the image Id value. return response.images().get(0).imageId(); } catch (SsmException e) { System.err.println(e.getMessage()); System.exit(1); } return ""; } // Get the Id value of an instance with amzn2 in the name. public static String getParaValues(SsmClient ssmClient) { try { GetParametersByPathRequest parameterRequest = GetParametersByPathRequest.builder() .path("/aws/service/ami-amazon-linux-latest") .build(); GetParametersByPathIterable responses = ssmClient.getParametersByPathPaginator(parameterRequest); for (software.amazon.awssdk.services.ssm.model.GetParametersByPathResponse response : responses) { System.out.println("Test " + response.nextToken()); List<Parameter> parameterList = response.parameters(); for (Parameter para : parameterList) { System.out.println("The name of the para is: " + para.name()); System.out.println("The type of the para is: " + para.type()); if (filterName(para.name())) { return para.value(); } } } } catch (SsmException e) { System.err.println(e.getMessage()); System.exit(1); } return ""; } // Return true if the name has amzn2 in it. For example: // /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-arm64-gp2 private static boolean filterName(String name) { String[] parts = name.split("/"); String myValue = parts[4]; return myValue.contains("amzn2"); } public static void describeSecurityGroups(Ec2Client ec2, String groupId) { try { DescribeSecurityGroupsRequest request = DescribeSecurityGroupsRequest.builder() .groupIds(groupId) .build(); // Use a paginator. DescribeSecurityGroupsIterable listGroups = ec2.describeSecurityGroupsPaginator(request); listGroups.stream() .flatMap(r -> r.securityGroups().stream()) .forEach(group -> System.out .println(" Group id: " +group.groupId() + " group name = " + group.groupName())); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } public static String createSecurityGroup(Ec2Client ec2, String groupName, String groupDesc, String vpcId, String myIpAddress) { try { CreateSecurityGroupRequest createRequest = CreateSecurityGroupRequest.builder() .groupName(groupName) .description(groupDesc) .vpcId(vpcId) .build(); CreateSecurityGroupResponse resp = ec2.createSecurityGroup(createRequest); IpRange ipRange = IpRange.builder() .cidrIp(myIpAddress + "/0") .build(); IpPermission ipPerm = IpPermission.builder() .ipProtocol("tcp") .toPort(80) .fromPort(80) .ipRanges(ipRange) .build(); IpPermission ipPerm2 = IpPermission.builder() .ipProtocol("tcp") .toPort(22) .fromPort(22) .ipRanges(ipRange) .build(); AuthorizeSecurityGroupIngressRequest authRequest = AuthorizeSecurityGroupIngressRequest.builder() .groupName(groupName) .ipPermissions(ipPerm, ipPerm2) .build(); ec2.authorizeSecurityGroupIngress(authRequest); System.out.println("Successfully added ingress policy to security group " + groupName); return resp.groupId(); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } return ""; } public static void describeKeys(Ec2Client ec2) { try { DescribeKeyPairsResponse response = ec2.describeKeyPairs(); response.keyPairs().forEach(keyPair -> System.out.printf( "Found key pair with name %s " + "and fingerprint %s", keyPair.keyName(), keyPair.keyFingerprint())); } catch (Ec2Exception e) { System.err.println(e.awsErrorDetails().errorMessage()); System.exit(1); } } public static void createKeyPair(Ec2Client ec2, String keyName, String fileName) { try { CreateKeyPairRequest request = CreateKeyPairRequest.builder() .keyName(keyName) .build(); CreateKeyPairResponse response = ec2.createKeyPair(request); String content = response.keyMaterial(); BufferedWriter writer = new BufferedWriter(new FileWriter(fileName)); writer.write(content); writer.close(); System.out.println("Successfully created key pair named " + keyName); } catch (Ec2Exception | IOException e) { System.err.println(e.getMessage()); System.exit(1); } } }
JavaScript
SDK for JavaScript (v3)
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Amazon Code Examples Repository.

Run an interactive scenario at a command prompt.

import { mkdtempSync, writeFileSync, rmSync } from "fs"; import { tmpdir } from "os"; import { join } from "path"; import { get } from "http"; import { AllocateAddressCommand, AssociateAddressCommand, AuthorizeSecurityGroupIngressCommand, CreateKeyPairCommand, CreateSecurityGroupCommand, DeleteKeyPairCommand, DeleteSecurityGroupCommand, DescribeInstancesCommand, DescribeKeyPairsCommand, DescribeSecurityGroupsCommand, DisassociateAddressCommand, EC2Client, paginateDescribeImages, paginateDescribeInstanceTypes, ReleaseAddressCommand, RunInstancesCommand, StartInstancesCommand, StopInstancesCommand, TerminateInstancesCommand, waitUntilInstanceStatusOk, waitUntilInstanceStopped, waitUntilInstanceTerminated, } from "@aws-sdk/client-ec2"; import { paginateGetParametersByPath, SSMClient } from "@aws-sdk/client-ssm"; import { wrapText } from "@aws-doc-sdk-examples/lib/utils/util-string.js"; import { Prompter } from "@aws-doc-sdk-examples/lib/prompter.js"; const ec2Client = new EC2Client(); const ssmClient = new SSMClient(); const prompter = new Prompter(); const confirmMessage = "Continue?"; const tmpDirectory = mkdtempSync(join(tmpdir(), "ec2-scenario-tmp")); const createKeyPair = async (keyPairName) => { // Create a key pair in Amazon EC2. const { KeyMaterial, KeyPairId } = await ec2Client.send( // A unique name for the key pair. Up to 255 ASCII characters. new CreateKeyPairCommand({ KeyName: keyPairName }), ); // Save the private key in a temporary location. writeFileSync(`${tmpDirectory}/${keyPairName}.pem`, KeyMaterial, { mode: 0o400, }); return KeyPairId; }; const describeKeyPair = async (keyPairName) => { const command = new DescribeKeyPairsCommand({ KeyNames: [keyPairName], }); const { KeyPairs } = await ec2Client.send(command); return KeyPairs[0]; }; const createSecurityGroup = async (securityGroupName) => { const command = new CreateSecurityGroupCommand({ GroupName: securityGroupName, Description: "A security group for the Amazon EC2 example.", }); const { GroupId } = await ec2Client.send(command); return GroupId; }; const allocateIpAddress = async () => { const command = new AllocateAddressCommand({}); const { PublicIp, AllocationId } = await ec2Client.send(command); return { PublicIp, AllocationId }; }; const getLocalIpAddress = () => { return new Promise((res, rej) => { get("http://checkip.amazonaws.com", (response) => { let data = ""; response.on("data", (chunk) => (data += chunk)); response.on("end", () => res(data.trim())); }).on("error", (err) => { rej(err); }); }); }; const authorizeSecurityGroupIngress = async (securityGroupId) => { const ipAddress = await getLocalIpAddress(); const command = new AuthorizeSecurityGroupIngressCommand({ GroupId: securityGroupId, IpPermissions: [ { IpProtocol: "tcp", FromPort: 22, ToPort: 22, IpRanges: [{ CidrIp: `${ipAddress}/32` }], }, ], }); await ec2Client.send(command); return ipAddress; }; const describeSecurityGroup = async (securityGroupName) => { const command = new DescribeSecurityGroupsCommand({ GroupNames: [securityGroupName], }); const { SecurityGroups } = await ec2Client.send(command); return SecurityGroups[0]; }; const getAmznLinux2AMIs = async () => { const AMIs = []; for await (const page of paginateGetParametersByPath( { client: ssmClient, }, { Path: "/aws/service/ami-amazon-linux-latest" }, )) { page.Parameters.forEach((param) => { if (param.Name.includes("amzn2")) { AMIs.push(param.Value); } }); } const imageDetails = []; for await (const page of paginateDescribeImages( { client: ec2Client }, { ImageIds: AMIs }, )) { imageDetails.push(...(page.Images || [])); } const choices = imageDetails.map((image, index) => ({ name: `${image.ImageId} - ${image.Description}`, value: index, })); /** * @type {number} */ const selectedIndex = await prompter.select({ message: "Select an image.", choices, }); return imageDetails[selectedIndex]; }; /** * @param {import('@aws-sdk/client-ec2').Image} imageDetails */ const getCompatibleInstanceTypes = async (imageDetails) => { const paginator = paginateDescribeInstanceTypes( { client: ec2Client, pageSize: 25 }, { Filters: [ { Name: "processor-info.supported-architecture", Values: [imageDetails.Architecture], }, { Name: "instance-type", Values: ["*.micro", "*.small"] }, ], }, ); const instanceTypes = []; for await (const page of paginator) { if (page.InstanceTypes.length) { instanceTypes.push(...(page.InstanceTypes || [])); } } const choices = instanceTypes.map((type, index) => ({ name: `${type.InstanceType} - Memory:${type.MemoryInfo.SizeInMiB}`, value: index, })); /** * @type {number} */ const selectedIndex = await prompter.select({ message: "Select an instance type.", choices, }); return instanceTypes[selectedIndex]; }; const runInstance = async ({ keyPairName, securityGroupId, imageId, instanceType, }) => { const command = new RunInstancesCommand({ KeyName: keyPairName, SecurityGroupIds: [securityGroupId], ImageId: imageId, InstanceType: instanceType, MinCount: 1, MaxCount: 1, }); const { Instances } = await ec2Client.send(command); await waitUntilInstanceStatusOk( { client: ec2Client }, { InstanceIds: [Instances[0].InstanceId] }, ); return Instances[0].InstanceId; }; const describeInstance = async (instanceId) => { const command = new DescribeInstancesCommand({ InstanceIds: [instanceId], }); const { Reservations } = await ec2Client.send(command); return Reservations[0].Instances[0]; }; const displaySSHConnectionInfo = ({ publicIp, keyPairName }) => { return `ssh -i ${tmpDirectory}/${keyPairName}.pem ec2-user@${publicIp}`; }; const stopInstance = async (instanceId) => { const command = new StopInstancesCommand({ InstanceIds: [instanceId] }); await ec2Client.send(command); await waitUntilInstanceStopped( { client: ec2Client }, { InstanceIds: [instanceId] }, ); }; const startInstance = async (instanceId) => { const startCommand = new StartInstancesCommand({ InstanceIds: [instanceId] }); await ec2Client.send(startCommand); await waitUntilInstanceStatusOk( { client: ec2Client }, { InstanceIds: [instanceId] }, ); return await describeInstance(instanceId); }; const associateAddress = async ({ allocationId, instanceId }) => { const command = new AssociateAddressCommand({ AllocationId: allocationId, InstanceId: instanceId, }); const { AssociationId } = await ec2Client.send(command); return AssociationId; }; const disassociateAddress = async (associationId) => { const command = new DisassociateAddressCommand({ AssociationId: associationId, }); try { await ec2Client.send(command); } catch (err) { console.warn( `Failed to disassociated address with association id: ${associationId}`, err, ); } }; const releaseAddress = async (allocationId) => { const command = new ReleaseAddressCommand({ AllocationId: allocationId, }); try { await ec2Client.send(command); console.log(`Address with allocation ID ${allocationId} released.\n`); } catch (err) { console.log( `Failed to release address with allocation id: ${allocationId}.`, err, ); } }; const restartInstance = async (instanceId) => { console.log("Stopping instance."); await stopInstance(instanceId); console.log("Instance stopped."); console.log("Starting instance."); const { PublicIpAddress } = await startInstance(instanceId); return PublicIpAddress; }; const terminateInstance = async (instanceId) => { const command = new TerminateInstancesCommand({ InstanceIds: [instanceId], }); try { await ec2Client.send(command); await waitUntilInstanceTerminated( { client: ec2Client }, { InstanceIds: [instanceId] }, ); console.log(`Instance with ID ${instanceId} terminated.\n`); } catch (err) { console.warn(`Failed to terminate instance ${instanceId}.`, err); } }; const deleteSecurityGroup = async (securityGroupId) => { const command = new DeleteSecurityGroupCommand({ GroupId: securityGroupId, }); try { await ec2Client.send(command); console.log(`Security group ${securityGroupId} deleted.\n`); } catch (err) { console.warn(`Failed to delete security group ${securityGroupId}.`, err); } }; const deleteKeyPair = async (keyPairName) => { const command = new DeleteKeyPairCommand({ KeyName: keyPairName, }); try { await ec2Client.send(command); console.log(`Key pair ${keyPairName} deleted.\n`); } catch (err) { console.warn(`Failed to delete key pair ${keyPairName}.`, err); } }; const deleteTemporaryDirectory = () => { try { rmSync(tmpDirectory, { recursive: true }); console.log(`Temporary directory ${tmpDirectory} deleted.\n`); } catch (err) { console.warn(`Failed to delete temporary directory ${tmpDirectory}.`, err); } }; export const main = async () => { const keyPairName = "ec2-scenario-key-pair"; const securityGroupName = "ec2-scenario-security-group"; let securityGroupId, ipAllocationId, publicIp, instanceId, associationId; console.log(wrapText("Welcome to the Amazon EC2 basic usage scenario.")); try { // Prerequisites console.log( "Before you launch an instance, you'll need a few things:", "\n - A Key Pair", "\n - A Security Group", "\n - An IP Address", "\n - An AMI", "\n - A compatible instance type", "\n\n I'll go ahead and take care of the first three, but I'll need your help for the rest.", ); await prompter.confirm({ message: confirmMessage }); await createKeyPair(keyPairName); securityGroupId = await createSecurityGroup(securityGroupName); const { PublicIp, AllocationId } = await allocateIpAddress(); ipAllocationId = AllocationId; publicIp = PublicIp; const ipAddress = await authorizeSecurityGroupIngress(securityGroupId); const { KeyName } = await describeKeyPair(keyPairName); const { GroupName } = await describeSecurityGroup(securityGroupName); console.log(`✅ created the key pair ${KeyName}.\n`); console.log( `✅ created the security group ${GroupName}`, `and allowed SSH access from ${ipAddress} (your IP).\n`, ); console.log(`✅ allocated ${publicIp} to be used for your EC2 instance.\n`); await prompter.confirm({ message: confirmMessage }); // Creating the instance console.log(wrapText("Create the instance.")); console.log( "You get to choose which image you want. Select an amazon-linux-2 image from the following:", ); const imageDetails = await getAmznLinux2AMIs(); const instanceTypeDetails = await getCompatibleInstanceTypes(imageDetails); console.log("Creating your instance. This can take a few seconds."); instanceId = await runInstance({ keyPairName, securityGroupId, imageId: imageDetails.ImageId, instanceType: instanceTypeDetails.InstanceType, }); const instanceDetails = await describeInstance(instanceId); console.log(`✅ instance ${instanceId}.\n`); console.log(instanceDetails); console.log( `\nYou should now be able to SSH into your instance from another terminal:`, `\n${displaySSHConnectionInfo({ publicIp: instanceDetails.PublicIpAddress, keyPairName, })}`, ); await prompter.confirm({ message: confirmMessage }); // Understanding the IP address. console.log(wrapText("Understanding the IP address.")); console.log( "When you stop and start an instance, the IP address will change. I'll restart your", "instance for you. Notice how the IP address changes.", ); const ipAddressAfterRestart = await restartInstance(instanceId); console.log( `\n Instance started. The IP address changed from ${instanceDetails.PublicIpAddress} to ${ipAddressAfterRestart}`, `\n${displaySSHConnectionInfo({ publicIp: ipAddressAfterRestart, keyPairName, })}`, ); await prompter.confirm({ message: confirmMessage }); console.log( `If you want to the IP address to be static, you can associate an allocated`, `IP address to your instance. I allocated ${publicIp} for you earlier, and now I'll associate it to your instance.`, ); associationId = await associateAddress({ allocationId: ipAllocationId, instanceId, }); console.log( "Done. Now you should be able to SSH using the new IP.\n", `${displaySSHConnectionInfo({ publicIp, keyPairName })}`, ); await prompter.confirm({ message: confirmMessage }); console.log( "I'll restart the server again so you can see the IP address remains the same.", ); const ipAddressAfterAssociated = await restartInstance(instanceId); console.log( `Done. Here's your SSH info. Notice the IP address hasn't changed.`, `\n${displaySSHConnectionInfo({ publicIp: ipAddressAfterAssociated, keyPairName, })}`, ); await prompter.confirm({ message: confirmMessage }); } catch (err) { console.error(err); } finally { // Clean up. console.log(wrapText("Clean up.")); console.log("Now I'll clean up all of the stuff I created."); await prompter.confirm({ message: confirmMessage }); console.log("Cleaning up. Some of these steps can take a bit of time."); await disassociateAddress(associationId); await terminateInstance(instanceId); await releaseAddress(ipAllocationId); await deleteSecurityGroup(securityGroupId); deleteTemporaryDirectory(); await deleteKeyPair(keyPairName); console.log( "Done cleaning up. Thanks for staying until the end!", "If you have any feedback please use the feedback button in the docs", "or create an issue on GitHub.", ); } };
Kotlin
SDK for Kotlin
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Amazon Code Examples Repository.

/** Before running this Kotlin code example, set up your development environment, including your credentials. For more information, see the following documentation topic: https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/setup.html This Kotlin example performs the following tasks: 1. Creates an RSA key pair and saves the private key data as a .pem file. 2. Lists key pairs. 3. Creates a security group for the default VPC. 4. Displays security group information. 5. Gets a list of Amazon Linux 2 AMIs and selects one. 6. Gets more information about the image. 7. Gets a list of instance types that are compatible with the selected AMI’s architecture. 8. Creates an instance with the key pair, security group, AMI, and an instance type. 9. Displays information about the instance. 10. Stops the instance and waits for it to stop. 11. Starts the instance and waits for it to start. 12. Allocates an Elastic IP address and associates it with the instance. 13. Displays SSH connection info for the instance. 14. Disassociates and deletes the Elastic IP address. 15. Terminates the instance. 16. Deletes the security group. 17. Deletes the key pair. */ val DASHES = String(CharArray(80)).replace("\u0000", "-") suspend fun main(args: Array<String>) { val usage = """ Usage: <keyName> <fileName> <groupName> <groupDesc> <vpcId> <myIpAddress> Where: keyName - A key pair name (for example, TestKeyPair). fileName - A file name where the key information is written to. groupName - The name of the security group. groupDesc - The description of the security group. vpcId - A VPC ID. You can get this value from the AWS Management Console. myIpAddress - The IP address of your development machine. """ if (args.size != 6) { println(usage) exitProcess(0) } val keyName = args[0] val fileName = args[1] val groupName = args[2] val groupDesc = args[3] val vpcId = args[4] val myIpAddress = args[5] var newInstanceId: String? = "" println(DASHES) println("Welcome to the Amazon EC2 example scenario.") println(DASHES) println(DASHES) println("1. Create an RSA key pair and save the private key material as a .pem file.") createKeyPairSc(keyName, fileName) println(DASHES) println(DASHES) println("2. List key pairs.") describeEC2KeysSc() println(DASHES) println(DASHES) println("3. Create a security group.") val groupId = createEC2SecurityGroupSc(groupName, groupDesc, vpcId, myIpAddress) println(DASHES) println(DASHES) println("4. Display security group info for the newly created security group.") describeSecurityGroupsSc(groupId.toString()) println(DASHES) println(DASHES) println("5. Get a list of Amazon Linux 2 AMIs and select one with amzn2 in the name.") val instanceId = getParaValuesSc() if (instanceId == "") { println("The instance Id value isn't valid.") exitProcess(0) } println("The instance Id is $instanceId.") println(DASHES) println(DASHES) println("6. Get more information about an amzn2 image and return the AMI value.") val amiValue = instanceId?.let { describeImageSc(it) } if (instanceId == "") { println("The instance Id value is invalid.") exitProcess(0) } println("The AMI value is $amiValue.") println(DASHES) println(DASHES) println("7. Get a list of instance types.") val instanceType = getInstanceTypesSc() println(DASHES) println(DASHES) println("8. Create an instance.") if (amiValue != null) { newInstanceId = runInstanceSc(instanceType, keyName, groupName, amiValue) println("The instance Id is $newInstanceId") } println(DASHES) println(DASHES) println("9. Display information about the running instance. ") var ipAddress = describeEC2InstancesSc(newInstanceId) println("You can SSH to the instance using this command:") println("ssh -i " + fileName + "ec2-user@" + ipAddress) println(DASHES) println(DASHES) println("10. Stop the instance.") if (newInstanceId != null) { stopInstanceSc(newInstanceId) } println(DASHES) println(DASHES) println("11. Start the instance.") if (newInstanceId != null) { startInstanceSc(newInstanceId) } ipAddress = describeEC2InstancesSc(newInstanceId) println("You can SSH to the instance using this command:") println("ssh -i " + fileName + "ec2-user@" + ipAddress) println(DASHES) println(DASHES) println("12. Allocate an Elastic IP address and associate it with the instance.") val allocationId = allocateAddressSc() println("The allocation Id value is $allocationId") val associationId = associateAddressSc(newInstanceId, allocationId) println("The associate Id value is $associationId") println(DASHES) println(DASHES) println("13. Describe the instance again.") ipAddress = describeEC2InstancesSc(newInstanceId) println("You can SSH to the instance using this command:") println("ssh -i " + fileName + "ec2-user@" + ipAddress) println(DASHES) println(DASHES) println("14. Disassociate and release the Elastic IP address.") disassociateAddressSc(associationId) releaseEC2AddressSc(allocationId) println(DASHES) println(DASHES) println("15. Terminate the instance and use a waiter.") if (newInstanceId != null) { terminateEC2Sc(newInstanceId) } println(DASHES) println(DASHES) println("16. Delete the security group.") if (groupId != null) { deleteEC2SecGroupSc(groupId) } println(DASHES) println(DASHES) println("17. Delete the key pair.") deleteKeysSc(keyName) println(DASHES) println(DASHES) println("You successfully completed the Amazon EC2 scenario.") println(DASHES) } suspend fun deleteKeysSc(keyPair: String) { val request = DeleteKeyPairRequest { keyName = keyPair } Ec2Client { region = "us-west-2" }.use { ec2 -> ec2.deleteKeyPair(request) println("Successfully deleted key pair named $keyPair") } } suspend fun deleteEC2SecGroupSc(groupIdVal: String) { val request = DeleteSecurityGroupRequest { groupId = groupIdVal } Ec2Client { region = "us-west-2" }.use { ec2 -> ec2.deleteSecurityGroup(request) println("Successfully deleted security group with Id $groupIdVal") } } suspend fun terminateEC2Sc(instanceIdVal: String) { val ti = TerminateInstancesRequest { instanceIds = listOf(instanceIdVal) } println("Wait for the instance to terminate. This will take a few minutes.") Ec2Client { region = "us-west-2" }.use { ec2 -> ec2.terminateInstances(ti) ec2.waitUntilInstanceTerminated { // suspend call instanceIds = listOf(instanceIdVal) } println("$instanceIdVal is terminated!") } } suspend fun releaseEC2AddressSc(allocId: String?) { val request = ReleaseAddressRequest { allocationId = allocId } Ec2Client { region = "us-west-2" }.use { ec2 -> ec2.releaseAddress(request) println("Successfully released Elastic IP address $allocId") } } suspend fun disassociateAddressSc(associationIdVal: String?) { val addressRequest = DisassociateAddressRequest { associationId = associationIdVal } Ec2Client { region = "us-west-2" }.use { ec2 -> ec2.disassociateAddress(addressRequest) println("You successfully disassociated the address!") } } suspend fun associateAddressSc( instanceIdVal: String?, allocationIdVal: String?, ): String? { val associateRequest = AssociateAddressRequest { instanceId = instanceIdVal allocationId = allocationIdVal } Ec2Client { region = "us-west-2" }.use { ec2 -> val associateResponse = ec2.associateAddress(associateRequest) return associateResponse.associationId } } suspend fun allocateAddressSc(): String? { val allocateRequest = AllocateAddressRequest { domain = DomainType.Vpc } Ec2Client { region = "us-west-2" }.use { ec2 -> val allocateResponse = ec2.allocateAddress(allocateRequest) return allocateResponse.allocationId } } suspend fun startInstanceSc(instanceId: String) { val request = StartInstancesRequest { instanceIds = listOf(instanceId) } Ec2Client { region = "us-west-2" }.use { ec2 -> ec2.startInstances(request) println("Waiting until instance $instanceId starts. This will take a few minutes.") ec2.waitUntilInstanceRunning { // suspend call instanceIds = listOf(instanceId) } println("Successfully started instance $instanceId") } } suspend fun stopInstanceSc(instanceId: String) { val request = StopInstancesRequest { instanceIds = listOf(instanceId) } Ec2Client { region = "us-west-2" }.use { ec2 -> ec2.stopInstances(request) println("Waiting until instance $instanceId stops. This will take a few minutes.") ec2.waitUntilInstanceStopped { // suspend call instanceIds = listOf(instanceId) } println("Successfully stopped instance $instanceId") } } suspend fun describeEC2InstancesSc(newInstanceId: String?): String { var pubAddress = "" var isRunning = false val request = DescribeInstancesRequest { instanceIds = listOf(newInstanceId.toString()) } while (!isRunning) { Ec2Client { region = "us-west-2" }.use { ec2 -> val response = ec2.describeInstances(request) val state = response.reservations ?.get(0) ?.instances ?.get(0) ?.state ?.name ?. value if (state != null) { if (state.compareTo("running") == 0) { println("Image id is ${response.reservations!!.get(0).instances?.get(0)?.imageId}") println("Instance type is ${response.reservations!!.get(0).instances?.get(0)?.instanceType}") println("Instance state is ${response.reservations!!.get(0).instances?.get(0)?.state}") pubAddress = response.reservations!! .get(0) .instances ?.get(0) ?.publicIpAddress .toString() println("Instance address is $pubAddress") isRunning = true } } } } return pubAddress } suspend fun runInstanceSc( instanceTypeVal: String, keyNameVal: String, groupNameVal: String, amiIdVal: String, ): String { val runRequest = RunInstancesRequest { instanceType = InstanceType.fromValue(instanceTypeVal) keyName = keyNameVal securityGroups = listOf(groupNameVal) maxCount = 1 minCount = 1 imageId = amiIdVal } Ec2Client { region = "us-west-2" }.use { ec2 -> val response = ec2.runInstances(runRequest) val instanceId = response.instances?.get(0)?.instanceId println("Successfully started EC2 Instance $instanceId based on AMI $amiIdVal") return instanceId.toString() } } // Get a list of instance types. suspend fun getInstanceTypesSc(): String { var instanceType = "" val filterObs = ArrayList<Filter>() val filter = Filter { name = "processor-info.supported-architecture" values = listOf("arm64") } filterObs.add(filter) val typesRequest = DescribeInstanceTypesRequest { filters = filterObs maxResults = 10 } Ec2Client { region = "us-west-2" }.use { ec2 -> val response = ec2.describeInstanceTypes(typesRequest) response.instanceTypes?.forEach { type -> println("The memory information of this type is ${type.memoryInfo?.sizeInMib}") println("Maximum number of network cards is ${type.networkInfo?.maximumNetworkCards}") instanceType = type.instanceType.toString() } return instanceType } } // Display the Description field that corresponds to the instance Id value. suspend fun describeImageSc(instanceId: String): String? { val imagesRequest = DescribeImagesRequest { imageIds = listOf(instanceId) } Ec2Client { region = "us-west-2" }.use { ec2 -> val response = ec2.describeImages(imagesRequest) println("The description of the first image is ${response.images?.get(0)?.description}") println("The name of the first image is ${response.images?.get(0)?.name}") // Return the image Id value. return response.images?.get(0)?.imageId } } // Get the Id value of an instance with amzn2 in the name. suspend fun getParaValuesSc(): String? { val parameterRequest = GetParametersByPathRequest { path = "/aws/service/ami-amazon-linux-latest" } SsmClient { region = "us-west-2" }.use { ssmClient -> val response = ssmClient.getParametersByPath(parameterRequest) response.parameters?.forEach { para -> println("The name of the para is: ${para.name}") println("The type of the para is: ${para.type}") println("") if (para.name?.let { filterName(it) } == true) { return para.value } } } return "" } fun filterName(name: String): Boolean { val parts = name.split("/").toTypedArray() val myValue = parts[4] return myValue.contains("amzn2") } suspend fun describeSecurityGroupsSc(groupId: String) { val request = DescribeSecurityGroupsRequest { groupIds = listOf(groupId) } Ec2Client { region = "us-west-2" }.use { ec2 -> val response = ec2.describeSecurityGroups(request) for (group in response.securityGroups!!) { println("Found Security Group with id " + group.groupId.toString() + " and group VPC " + group.vpcId) } } } suspend fun createEC2SecurityGroupSc( groupNameVal: String?, groupDescVal: String?, vpcIdVal: String?, myIpAddress: String?, ): String? { val request = CreateSecurityGroupRequest { groupName = groupNameVal description = groupDescVal vpcId = vpcIdVal } Ec2Client { region = "us-west-2" }.use { ec2 -> val resp = ec2.createSecurityGroup(request) val ipRange = IpRange { cidrIp = "$myIpAddress/0" } val ipPerm = IpPermission { ipProtocol = "tcp" toPort = 80 fromPort = 80 ipRanges = listOf(ipRange) } val ipPerm2 = IpPermission { ipProtocol = "tcp" toPort = 22 fromPort = 22 ipRanges = listOf(ipRange) } val authRequest = AuthorizeSecurityGroupIngressRequest { groupName = groupNameVal ipPermissions = listOf(ipPerm, ipPerm2) } ec2.authorizeSecurityGroupIngress(authRequest) println("Successfully added ingress policy to Security Group $groupNameVal") return resp.groupId } } suspend fun describeEC2KeysSc() { Ec2Client { region = "us-west-2" }.use { ec2 -> val response = ec2.describeKeyPairs(DescribeKeyPairsRequest {}) response.keyPairs?.forEach { keyPair -> println("Found key pair with name ${keyPair.keyName} and fingerprint ${ keyPair.keyFingerprint}") } } } suspend fun createKeyPairSc( keyNameVal: String, fileNameVal: String, ) { val request = CreateKeyPairRequest { keyName = keyNameVal } Ec2Client { region = "us-west-2" }.use { ec2 -> val response = ec2.createKeyPair(request) val content = response.keyMaterial if (content != null) { File(fileNameVal).writeText(content) } println("Successfully created key pair named $keyNameVal") } }
Python
SDK for Python (Boto3)
Note

There's more on GitHub. Find the complete example and learn how to set up and run in the Amazon Code Examples Repository.

Run an interactive scenario at a command prompt.

class Ec2InstanceScenario: """Runs an interactive scenario that shows how to get started using EC2 instances.""" def __init__(self, inst_wrapper, key_wrapper, sg_wrapper, eip_wrapper, ssm_client): """ :param inst_wrapper: An object that wraps instance actions. :param key_wrapper: An object that wraps key pair actions. :param sg_wrapper: An object that wraps security group actions. :param eip_wrapper: An object that wraps Elastic IP actions. :param ssm_client: A Boto3 AWS Systems Manager client. """ self.inst_wrapper = inst_wrapper self.key_wrapper = key_wrapper self.sg_wrapper = sg_wrapper self.eip_wrapper = eip_wrapper self.ssm_client = ssm_client @demo_func def create_and_list_key_pairs(self): """ 1. Creates an RSA key pair and saves its private key data as a .pem file in secure temporary storage. The private key data is deleted after the example completes. 2. Lists the first five key pairs for the current account. """ print( "Let's create an RSA key pair that you can be use to securely connect to " "your EC2 instance." ) key_name = q.ask("Enter a unique name for your key: ", q.non_empty) self.key_wrapper.create(key_name) print( f"Created a key pair {self.key_wrapper.key_pair.key_name} and saved the " f"private key to {self.key_wrapper.key_file_path}.\n" ) if q.ask("Do you want to list some of your key pairs? (y/n) ", q.is_yesno): self.key_wrapper.list(5) @demo_func def create_security_group(self): """ 1. Creates a security group for the default VPC. 2. Adds an inbound rule to allow SSH. The SSH rule allows only inbound traffic from the current computer’s public IPv4 address. 3. Displays information about the security group. This function uses 'http://checkip.amazonaws.com' to get the current public IP address of the computer that is running the example. This method works in most cases. However, depending on how your computer connects to the internet, you might have to manually add your public IP address to the security group by using the AWS Management Console. """ print("Let's create a security group to manage access to your instance.") sg_name = q.ask("Enter a unique name for your security group: ", q.non_empty) security_group = self.sg_wrapper.create( sg_name, "Security group for example: get started with instances." ) print( f"Created security group {security_group.group_name} in your default " f"VPC {security_group.vpc_id}.\n" ) ip_response = urllib.request.urlopen("http://checkip.amazonaws.com") current_ip_address = ip_response.read().decode("utf-8").strip() print("Let's add a rule to allow SSH only from your current IP address.") print(f"Your public IP address is {current_ip_address}.") q.ask("Press Enter to add this rule to your security group.") response = self.sg_wrapper.authorize_ingress(current_ip_address) if response["Return"]: print("Security group rules updated.") else: print("Couldn't update security group rules.") self.sg_wrapper.describe() @demo_func def create_instance(self): """ 1. Gets a list of Amazon Linux 2 AMIs from AWS Systems Manager. Specifying the '/aws/service/ami-amazon-linux-latest' path returns only the latest AMIs. 2. Gets and displays information about the available AMIs and lets you select one. 3. Gets a list of instance types that are compatible with the selected AMI and lets you select one. 4. Creates an instance with the previously created key pair and security group, and the selected AMI and instance type. 5. Waits for the instance to be running and then displays its information. """ ami_paginator = self.ssm_client.get_paginator("get_parameters_by_path") ami_options = [] for page in ami_paginator.paginate(Path="/aws/service/ami-amazon-linux-latest"): ami_options += page["Parameters"] amzn2_images = self.inst_wrapper.get_images( [opt["Value"] for opt in ami_options if "amzn2" in opt["Name"]] ) print( "Let's create an instance from an Amazon Linux 2 AMI. Here are some options:" ) image_choice = q.choose( "Which one do you want to use? ", [opt.description for opt in amzn2_images] ) print("Great choice!\n") print( f"Here are some instance types that support the " f"{amzn2_images[image_choice].architecture} architecture of the image:" ) inst_types = self.inst_wrapper.get_instance_types( amzn2_images[image_choice].architecture ) inst_type_choice = q.choose( "Which one do you want to use? ", [it["InstanceType"] for it in inst_types] ) print("Another great choice.\n") print("Creating your instance and waiting for it to start...") self.inst_wrapper.create( amzn2_images[image_choice], inst_types[inst_type_choice]["InstanceType"], self.key_wrapper.key_pair, [self.sg_wrapper.security_group], ) print(f"Your instance is ready:\n") self.inst_wrapper.display() print("You can use SSH to connect to your instance.") print( "If the connection attempt times out, you might have to manually update " "the SSH ingress rule for your IP address in the AWS Management Console." ) self._display_ssh_info() def _display_ssh_info(self): """ Displays an SSH connection string that can be used to connect to a running instance. """ print("To connect, open another command prompt and run the following command:") if self.eip_wrapper.elastic_ip is None: print( f"\tssh -i {self.key_wrapper.key_file_path} " f"ec2-user@{self.inst_wrapper.instance.public_ip_address}" ) else: print( f"\tssh -i {self.key_wrapper.key_file_path} " f"ec2-user@{self.eip_wrapper.elastic_ip.public_ip}" ) q.ask("Press Enter when you're ready to continue the demo.") @demo_func def associate_elastic_ip(self): """ 1. Allocates an Elastic IP address and associates it with the instance. 2. Displays an SSH connection string that uses the Elastic IP address. """ print( "You can allocate an Elastic IP address and associate it with your instance\n" "to keep a consistent IP address even when your instance restarts." ) elastic_ip = self.eip_wrapper.allocate() print(f"Allocated static Elastic IP address: {elastic_ip.public_ip}.") self.eip_wrapper.associate(self.inst_wrapper.instance) print(f"Associated your Elastic IP with your instance.") print( "You can now use SSH to connect to your instance by using the Elastic IP." ) self._display_ssh_info() @demo_func def stop_and_start_instance(self): """ 1. Stops the instance and waits for it to stop. 2. Starts the instance and waits for it to start. 3. Displays information about the instance. 4. Displays an SSH connection string. When an Elastic IP address is associated with the instance, the IP address stays consistent when the instance stops and starts. """ print("Let's stop and start your instance to see what changes.") print("Stopping your instance and waiting until it's stopped...") self.inst_wrapper.stop() print("Your instance is stopped. Restarting...") self.inst_wrapper.start() print("Your instance is running.") self.inst_wrapper.display() if self.eip_wrapper.elastic_ip is None: print( "Every time your instance is restarted, its public IP address changes." ) else: print( "Because you have associated an Elastic IP with your instance, you can \n" "connect by using a consistent IP address after the instance restarts." ) self._display_ssh_info() @demo_func def cleanup(self): """ 1. Disassociate and delete the previously created Elastic IP. 2. Terminate the previously created instance. 3. Delete the previously created security group. 4. Delete the previously created key pair. """ print("Let's clean everything up. This example created these resources:") print(f"\tElastic IP: {self.eip_wrapper.elastic_ip.allocation_id}") print(f"\tInstance: {self.inst_wrapper.instance.id}") print(f"\tSecurity group: {self.sg_wrapper.security_group.id}") print(f"\tKey pair: {self.key_wrapper.key_pair.name}") if q.ask("Ready to delete these resources? (y/n) ", q.is_yesno): self.eip_wrapper.disassociate() print("Disassociated the Elastic IP from the instance.") self.eip_wrapper.release() print("Released the Elastic IP.") print("Terminating the instance and waiting for it to terminate...") self.inst_wrapper.terminate() print("Instance terminated.") self.sg_wrapper.delete() print("Deleted security group.") self.key_wrapper.delete() print("Deleted key pair.") def run_scenario(self): logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s") print("-" * 88) print( "Welcome to the Amazon Elastic Compute Cloud (Amazon EC2) get started with instances demo." ) print("-" * 88) self.create_and_list_key_pairs() self.create_security_group() self.create_instance() self.stop_and_start_instance() self.associate_elastic_ip() self.stop_and_start_instance() self.cleanup() print("\nThanks for watching!") print("-" * 88) if __name__ == "__main__": try: scenario = Ec2InstanceScenario( InstanceWrapper.from_resource(), KeyPairWrapper.from_resource(), SecurityGroupWrapper.from_resource(), ElasticIpWrapper.from_resource(), boto3.client("ssm"), ) scenario.run_scenario() except Exception: logging.exception("Something went wrong with the demo.")

Define a class that wraps key pair actions.

class KeyPairWrapper: """Encapsulates Amazon Elastic Compute Cloud (Amazon EC2) key pair actions.""" def __init__(self, ec2_resource, key_file_dir, key_pair=None): """ :param ec2_resource: A Boto3 Amazon EC2 resource. This high-level resource is used to create additional high-level objects that wrap low-level Amazon EC2 service actions. :param key_file_dir: The folder where the private key information is stored. This should be a secure folder. :param key_pair: A Boto3 KeyPair object. This is a high-level object that wraps key pair actions. """ self.ec2_resource = ec2_resource self.key_pair = key_pair self.key_file_path = None self.key_file_dir = key_file_dir @classmethod def from_resource(cls): ec2_resource = boto3.resource("ec2") return cls(ec2_resource, tempfile.TemporaryDirectory()) def create(self, key_name): """ Creates a key pair that can be used to securely connect to an EC2 instance. The returned key pair contains private key information that cannot be retrieved again. The private key data is stored as a .pem file. :param key_name: The name of the key pair to create. :return: A Boto3 KeyPair object that represents the newly created key pair. """ try: self.key_pair = self.ec2_resource.create_key_pair(KeyName=key_name) self.key_file_path = os.path.join( self.key_file_dir.name, f"{self.key_pair.name}.pem" ) with open(self.key_file_path, "w") as key_file: key_file.write(self.key_pair.key_material) except ClientError as err: logger.error( "Couldn't create key %s. Here's why: %s: %s", key_name, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return self.key_pair def list(self, limit): """ Displays a list of key pairs for the current account. :param limit: The maximum number of key pairs to list. """ try: for kp in self.ec2_resource.key_pairs.limit(limit): print(f"Found {kp.key_type} key {kp.name} with fingerprint:") print(f"\t{kp.key_fingerprint}") except ClientError as err: logger.error( "Couldn't list key pairs. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def delete(self): """ Deletes a key pair. """ if self.key_pair is None: logger.info("No key pair to delete.") return key_name = self.key_pair.name try: self.key_pair.delete() self.key_pair = None except ClientError as err: logger.error( "Couldn't delete key %s. Here's why: %s : %s", key_name, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise

Define a class that wraps security group actions.

class SecurityGroupWrapper: """Encapsulates Amazon Elastic Compute Cloud (Amazon EC2) security group actions.""" def __init__(self, ec2_resource, security_group=None): """ :param ec2_resource: A Boto3 Amazon EC2 resource. This high-level resource is used to create additional high-level objects that wrap low-level Amazon EC2 service actions. :param security_group: A Boto3 SecurityGroup object. This is a high-level object that wraps security group actions. """ self.ec2_resource = ec2_resource self.security_group = security_group @classmethod def from_resource(cls): ec2_resource = boto3.resource("ec2") return cls(ec2_resource) def create(self, group_name, group_description): """ Creates a security group in the default virtual private cloud (VPC) of the current account. :param group_name: The name of the security group to create. :param group_description: The description of the security group to create. :return: A Boto3 SecurityGroup object that represents the newly created security group. """ try: self.security_group = self.ec2_resource.create_security_group( GroupName=group_name, Description=group_description ) except ClientError as err: logger.error( "Couldn't create security group %s. Here's why: %s: %s", group_name, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return self.security_group def authorize_ingress(self, ssh_ingress_ip): """ Adds a rule to the security group to allow access to SSH. :param ssh_ingress_ip: The IP address that is granted inbound access to connect to port 22 over TCP, used for SSH. :return: The response to the authorization request. The 'Return' field of the response indicates whether the request succeeded or failed. """ if self.security_group is None: logger.info("No security group to update.") return try: ip_permissions = [ { # SSH ingress open to only the specified IP address. "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "IpRanges": [{"CidrIp": f"{ssh_ingress_ip}/32"}], } ] response = self.security_group.authorize_ingress( IpPermissions=ip_permissions ) except ClientError as err: logger.error( "Couldn't authorize inbound rules for %s. Here's why: %s: %s", self.security_group.id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return response def describe(self): """ Displays information about the security group. """ if self.security_group is None: logger.info("No security group to describe.") return try: print(f"Security group: {self.security_group.group_name}") print(f"\tID: {self.security_group.id}") print(f"\tVPC: {self.security_group.vpc_id}") if self.security_group.ip_permissions: print(f"Inbound permissions:") pp(self.security_group.ip_permissions) except ClientError as err: logger.error( "Couldn't get data for security group %s. Here's why: %s: %s", self.security_group.id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def delete(self): """ Deletes the security group. """ if self.security_group is None: logger.info("No security group to delete.") return group_id = self.security_group.id try: self.security_group.delete() except ClientError as err: logger.error( "Couldn't delete security group %s. Here's why: %s: %s", group_id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise

Define a class that wraps instance actions.

class InstanceWrapper: """Encapsulates Amazon Elastic Compute Cloud (Amazon EC2) instance actions.""" def __init__(self, ec2_resource, instance=None): """ :param ec2_resource: A Boto3 Amazon EC2 resource. This high-level resource is used to create additional high-level objects that wrap low-level Amazon EC2 service actions. :param instance: A Boto3 Instance object. This is a high-level object that wraps instance actions. """ self.ec2_resource = ec2_resource self.instance = instance @classmethod def from_resource(cls): ec2_resource = boto3.resource("ec2") return cls(ec2_resource) def create(self, image, instance_type, key_pair, security_groups=None): """ Creates a new EC2 instance. The instance starts immediately after it is created. The instance is created in the default VPC of the current account. :param image: A Boto3 Image object that represents an Amazon Machine Image (AMI) that defines attributes of the instance that is created. The AMI defines things like the kind of operating system and the type of storage used by the instance. :param instance_type: The type of instance to create, such as 't2.micro'. The instance type defines things like the number of CPUs and the amount of memory. :param key_pair: A Boto3 KeyPair or KeyPairInfo object that represents the key pair that is used to secure connections to the instance. :param security_groups: A list of Boto3 SecurityGroup objects that represents the security groups that are used to grant access to the instance. When no security groups are specified, the default security group of the VPC is used. :return: A Boto3 Instance object that represents the newly created instance. """ try: instance_params = { "ImageId": image.id, "InstanceType": instance_type, "KeyName": key_pair.name, } if security_groups is not None: instance_params["SecurityGroupIds"] = [sg.id for sg in security_groups] self.instance = self.ec2_resource.create_instances( **instance_params, MinCount=1, MaxCount=1 )[0] self.instance.wait_until_running() except ClientError as err: logging.error( "Couldn't create instance with image %s, instance type %s, and key %s. " "Here's why: %s: %s", image.id, instance_type, key_pair.name, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return self.instance def display(self, indent=1): """ Displays information about an instance. :param indent: The visual indent to apply to the output. """ if self.instance is None: logger.info("No instance to display.") return try: self.instance.load() ind = "\t" * indent print(f"{ind}ID: {self.instance.id}") print(f"{ind}Image ID: {self.instance.image_id}") print(f"{ind}Instance type: {self.instance.instance_type}") print(f"{ind}Key name: {self.instance.key_name}") print(f"{ind}VPC ID: {self.instance.vpc_id}") print(f"{ind}Public IP: {self.instance.public_ip_address}") print(f"{ind}State: {self.instance.state['Name']}") except ClientError as err: logger.error( "Couldn't display your instance. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def terminate(self): """ Terminates an instance and waits for it to be in a terminated state. """ if self.instance is None: logger.info("No instance to terminate.") return instance_id = self.instance.id try: self.instance.terminate() self.instance.wait_until_terminated() self.instance = None except ClientError as err: logging.error( "Couldn't terminate instance %s. Here's why: %s: %s", instance_id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def start(self): """ Starts an instance and waits for it to be in a running state. :return: The response to the start request. """ if self.instance is None: logger.info("No instance to start.") return try: response = self.instance.start() self.instance.wait_until_running() except ClientError as err: logger.error( "Couldn't start instance %s. Here's why: %s: %s", self.instance.id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return response def stop(self): """ Stops an instance and waits for it to be in a stopped state. :return: The response to the stop request. """ if self.instance is None: logger.info("No instance to stop.") return try: response = self.instance.stop() self.instance.wait_until_stopped() except ClientError as err: logger.error( "Couldn't stop instance %s. Here's why: %s: %s", self.instance.id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return response def get_images(self, image_ids): """ Gets information about Amazon Machine Images (AMIs) from a list of AMI IDs. :param image_ids: The list of AMIs to look up. :return: A list of Boto3 Image objects that represent the requested AMIs. """ try: images = list(self.ec2_resource.images.filter(ImageIds=image_ids)) except ClientError as err: logger.error( "Couldn't get images. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return images def get_instance_types(self, architecture): """ Gets instance types that support the specified architecture and are designated as either 'micro' or 'small'. When an instance is created, the instance type you specify must support the architecture of the AMI you use. :param architecture: The kind of architecture the instance types must support, such as 'x86_64'. :return: A list of instance types that support the specified architecture and are either 'micro' or 'small'. """ try: inst_types = [] it_paginator = self.ec2_resource.meta.client.get_paginator( "describe_instance_types" ) for page in it_paginator.paginate( Filters=[ { "Name": "processor-info.supported-architecture", "Values": [architecture], }, {"Name": "instance-type", "Values": ["*.micro", "*.small"]}, ] ): inst_types += page["InstanceTypes"] except ClientError as err: logger.error( "Couldn't get instance types. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return inst_types

Define a class that wraps Elastic IP actions.

class ElasticIpWrapper: """Encapsulates Amazon Elastic Compute Cloud (Amazon EC2) Elastic IP address actions.""" def __init__(self, ec2_resource, elastic_ip=None): """ :param ec2_resource: A Boto3 Amazon EC2 resource. This high-level resource is used to create additional high-level objects that wrap low-level Amazon EC2 service actions. :param elastic_ip: A Boto3 VpcAddress object. This is a high-level object that wraps Elastic IP actions. """ self.ec2_resource = ec2_resource self.elastic_ip = elastic_ip @classmethod def from_resource(cls): ec2_resource = boto3.resource("ec2") return cls(ec2_resource) def allocate(self): """ Allocates an Elastic IP address that can be associated with an Amazon EC2 instance. By using an Elastic IP address, you can keep the public IP address constant even when you restart the associated instance. :return: The newly created Elastic IP object. By default, the address is not associated with any instance. """ try: response = self.ec2_resource.meta.client.allocate_address(Domain="vpc") self.elastic_ip = self.ec2_resource.VpcAddress(response["AllocationId"]) except ClientError as err: logger.error( "Couldn't allocate Elastic IP. Here's why: %s: %s", err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise else: return self.elastic_ip def associate(self, instance): """ Associates an Elastic IP address with an instance. When this association is created, the Elastic IP's public IP address is immediately used as the public IP address of the associated instance. :param instance: A Boto3 Instance object. This is a high-level object that wraps Amazon EC2 instance actions. :return: A response that contains the ID of the association. """ if self.elastic_ip is None: logger.info("No Elastic IP to associate.") return try: response = self.elastic_ip.associate(InstanceId=instance.id) except ClientError as err: logger.error( "Couldn't associate Elastic IP %s with instance %s. Here's why: %s: %s", self.elastic_ip.allocation_id, instance.id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise return response def disassociate(self): """ Removes an association between an Elastic IP address and an instance. When the association is removed, the instance is assigned a new public IP address. """ if self.elastic_ip is None: logger.info("No Elastic IP to disassociate.") return try: self.elastic_ip.association.delete() except ClientError as err: logger.error( "Couldn't disassociate Elastic IP %s from its instance. Here's why: %s: %s", self.elastic_ip.allocation_id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise def release(self): """ Releases an Elastic IP address. After the Elastic IP address is released, it can no longer be used. """ if self.elastic_ip is None: logger.info("No Elastic IP to release.") return try: self.elastic_ip.release() except ClientError as err: logger.error( "Couldn't release Elastic IP address %s. Here's why: %s: %s", self.elastic_ip.allocation_id, err.response["Error"]["Code"], err.response["Error"]["Message"], ) raise

For a complete list of Amazon SDK developer guides and code examples, see Create Amazon EC2 resources using an Amazon SDK. This topic also includes information about getting started and details about previous SDK versions.