Amazon EC2 examples using SDK for Swift - AWS SDK for Swift

Amazon EC2 examples using SDK for Swift

The following code examples show you how to perform actions and implement common scenarios by using the AWS SDK for Swift with Amazon EC2.

Basics are code examples that show you how to perform the essential operations within a service.

Actions are code excerpts from larger programs and must be run in context. While actions show you how to call individual service functions, you can see actions in context in their related scenarios.

Each example includes a link to the complete source code, where you can find instructions on how to set up and run the code in context.

Get started

The following code examples show how to get started using Amazon EC2.

SDK for Swift
Note

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

The Package.swift file.

// swift-tools-version: 5.9 // // The swift-tools-version declares the minimum version of Swift required to // build this package. import PackageDescription let package = Package( name: "hello-ec2", // Let Xcode know the minimum Apple platforms supported. platforms: [ .macOS(.v13), .iOS(.v15) ], dependencies: [ // Dependencies declare other packages that this package depends on. .package( url: "https://github.com/awslabs/aws-sdk-swift", from: "1.0.0"), .package( url: "https://github.com/apple/swift-argument-parser.git", branch: "main" ) ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products // from dependencies. .executableTarget( name: "hello-ec2", dependencies: [ .product(name: "AWSEC2", package: "aws-sdk-swift"), .product(name: "ArgumentParser", package: "swift-argument-parser") ], path: "Sources") ] )

The entry.swift file.

// An example that shows how to use the AWS SDK for Swift to perform a simple // operation using Amazon Elastic Compute Cloud (EC2). // import ArgumentParser import Foundation import AWSEC2 struct ExampleCommand: ParsableCommand { @Option(help: "The AWS Region to run AWS API calls in.") var awsRegion = "us-east-1" @Option( help: ArgumentHelp("The level of logging for the Swift SDK to perform."), completion: .list([ "critical", "debug", "error", "info", "notice", "trace", "warning" ]) ) var logLevel: String = "error" static var configuration = CommandConfiguration( commandName: "hello-ec2", abstract: """ Demonstrates a simple operation using Amazon EC2. """, discussion: """ An example showing how to make a call to Amazon EC2 using the AWS SDK for Swift. """ ) /// Return an array of strings giving the names of every security group /// the user is a member of. /// /// - Parameter ec2Client: The `EC2Client` to use when calling /// `describeSecurityGroupsPaginated()`. /// /// - Returns: An array of strings giving the names of every security /// group the user is a member of. func getSecurityGroupNames(ec2Client: EC2Client) async -> [String] { let pages = ec2Client.describeSecurityGroupsPaginated( input: DescribeSecurityGroupsInput() ) var groupNames: [String] = [] do { for try await page in pages { guard let groups = page.securityGroups else { print("*** Error: No groups returned.") continue } for group in groups { groupNames.append(group.groupName ?? "<unknown>") } } } catch { print("*** Error: \(error.localizedDescription)") } return groupNames } /// Called by ``main()`` to run the bulk of the example. func runAsync() async throws { let ec2Config = try await EC2Client.EC2ClientConfiguration(region: awsRegion) let ec2Client = EC2Client(config: ec2Config) let groupNames = await getSecurityGroupNames(ec2Client: ec2Client) print("Found \(groupNames.count) security group(s):") for group in groupNames { print(" \(group)") } } } /// The program's asynchronous entry point. @main struct Main { static func main() async { let args = Array(CommandLine.arguments.dropFirst()) do { let command = try ExampleCommand.parse(args) try await command.runAsync() } catch { ExampleCommand.exit(withError: error) } } }

Basics

The following code example shows 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.

SDK for Swift
Note

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

The Package.swift file.

// swift-tools-version: 5.9 // // The swift-tools-version declares the minimum version of Swift required to // build this package. import PackageDescription let package = Package( name: "ec2-scenario", // Let Xcode know the minimum Apple platforms supported. platforms: [ .macOS(.v13), .iOS(.v15) ], dependencies: [ // Dependencies declare other packages that this package depends on. .package( url: "https://github.com/awslabs/aws-sdk-swift", from: "1.4.0"), .package( url: "https://github.com/apple/swift-argument-parser.git", branch: "main" ) ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products // from dependencies. .executableTarget( name: "ec2-scenario", dependencies: [ .product(name: "AWSEC2", package: "aws-sdk-swift"), .product(name: "AWSSSM", package: "aws-sdk-swift"), .product(name: "ArgumentParser", package: "swift-argument-parser") ], path: "Sources") ] )

The entry.swift file.

// An example that shows how to use the AWS SDK for Swift to perform a variety // of operations using Amazon Elastic Compute Cloud (EC2). // import ArgumentParser import Foundation import AWSEC2 // Allow waiters to be used. import class SmithyWaitersAPI.Waiter import struct SmithyWaitersAPI.WaiterOptions import AWSSSM struct ExampleCommand: ParsableCommand { @Option(help: "The AWS Region to run AWS API calls in.") var awsRegion = "us-east-1" @Option( help: ArgumentHelp("The level of logging for the Swift SDK to perform."), completion: .list([ "critical", "debug", "error", "info", "notice", "trace", "warning" ]) ) var logLevel: String = "error" static var configuration = CommandConfiguration( commandName: "ec2-scenario", abstract: """ Performs various operations to demonstrate the use of Amazon EC2 using the AWS SDK for Swift. """, discussion: """ """ ) /// Called by ``main()`` to run the bulk of the example. func runAsync() async throws { let ssmConfig = try await SSMClient.SSMClientConfiguration(region: awsRegion) let ssmClient = SSMClient(config: ssmConfig) let ec2Config = try await EC2Client.EC2ClientConfiguration(region: awsRegion) let ec2Client = EC2Client(config: ec2Config) let example = Example(ec2Client: ec2Client, ssmClient: ssmClient) await example.run() } } class Example { let ec2Client: EC2Client let ssmClient: SSMClient // Storage for AWS EC2 properties. var keyName: String? = nil var securityGroupId: String? = nil var instanceId: String? = nil var allocationId: String? = nil var associationId: String? = nil init(ec2Client: EC2Client, ssmClient: SSMClient) { self.ec2Client = ec2Client self.ssmClient = ssmClient } /// The example's main body. func run() async { //===================================================================== // 1. Create an RSA key pair, saving the private key as a `.pem` file. // Create a `defer` block that will delete the private key when the // program exits. //===================================================================== print("Creating an RSA key pair...") keyName = self.tempName(prefix: "ExampleKeyName") let keyUrl = await self.createKeyPair(name: keyName!) guard let keyUrl else { print("*** Failed to create the key pair!") return } print("Created the private key at: \(keyUrl.absoluteString)") // Schedule deleting the private key file to occur automatically when // the program exits, no matter how it exits. defer { do { try FileManager.default.removeItem(at: keyUrl) } catch { print("*** Failed to delete the private key at \(keyUrl.absoluteString)") } } //===================================================================== // 2. List the key pairs by calling `DescribeKeyPairs`. //===================================================================== print("Describing available key pairs...") await self.describeKeyPairs() //===================================================================== // 3. Create a security group for the default VPC, and add an inbound // rule to allow SSH from the current computer's public IPv4 // address. //===================================================================== print("Creating the security group...") let secGroupName = self.tempName(prefix: "ExampleSecurityGroup") let ipAddress = self.getMyIPAddress() guard let ipAddress else { print("*** Unable to get the device's IP address.") return } print("IP address is: \(ipAddress)") securityGroupId = await self.createSecurityGroup( name: secGroupName, description: "An example security group created using the AWS SDK for Swift" ) if securityGroupId == nil { await cleanUp() return } print("Created security group: \(securityGroupId ?? "<unknown>")") if !(await self.authorizeSecurityGroupIngress(groupId: securityGroupId!, ipAddress: ipAddress)) { await cleanUp() return } //===================================================================== // 4. Display security group information for the new security group // using DescribeSecurityGroups. //===================================================================== if !(await self.describeSecurityGroups(groupId: securityGroupId!)) { await cleanUp() return } //===================================================================== // 5. Get a list of Amazon Linux 2023 AMIs and pick one (SSM is the // best practice), using path and then filter the list after the // fact to include "al2023" in the Name field // (ssm.GetParametersByPath). Paginate to get all images. //===================================================================== print("Searching available images for Amazon Linux 2023 images...") let options = await self.findAMIsMatchingFilter("al2023") //===================================================================== // 6. The information in the AMI options isn't great, so make a list // of the image IDs (the "Value" field in the AMI options) and get // more information about them from EC2. Display the Description // field and select one of them (DescribeImages with ImageIds // filter). //===================================================================== print("Images matching Amazon Linux 2023:") var imageIds: [String] = [] for option in options { guard let id = option.value else { continue } imageIds.append(id) } let images = await self.describeImages(imageIds) // This is where you would normally let the user choose which AMI to // use. However, for this example, we're just going to use the first // one, whatever it is. let chosenImage = images[0] //===================================================================== // 7. Get a list of instance types that are compatible with the // selected AMI's architecture (such as "x86_64") and are either // small or micro. Select one (DescribeInstanceTypes). //===================================================================== print("Getting the instance types compatible with the selected image...") guard let arch = chosenImage.architecture else { print("*** The selected image doesn't have a valid architecture.") await cleanUp() return } let imageTypes = await self.getMatchingInstanceTypes(architecture: arch) for type in imageTypes { guard let instanceType = type.instanceType else { continue } print(" \(instanceType.rawValue)") } // This example selects the first returned instance type. A real-world // application would probably ask the user to select one here. let chosenInstanceType = imageTypes[0] //===================================================================== // 8. Create an instance with the key pair, security group, AMI, and // instance type (RunInstances). //===================================================================== print("Creating an instance...") guard let imageId = chosenImage.imageId else { print("*** Cannot start image without a valid image ID.") await cleanUp() return } guard let instanceType = chosenInstanceType.instanceType else { print("*** Unable to start image without a valid image type.") await cleanUp() return } let instance = await self.runInstance( imageId: imageId, instanceType: instanceType, keyPairName: keyName!, securityGroups: [securityGroupId!] ) guard let instance else { await cleanUp() return } instanceId = instance.instanceId if instanceId == nil { print("*** Instance is missing an ID. Canceling.") await cleanUp() return } //===================================================================== // 9. Wait for the instance to be ready and then display its // information (DescribeInstances). //===================================================================== print("Waiting a few seconds to let the instance come up...") do { try await Task.sleep(for: .seconds(20)) } catch { print("*** Error pausing the task.") } print("Success! Your new instance is ready:") //===================================================================== // 10. Display SSH connection info for the instance. //===================================================================== var runningInstance = await self.describeInstance(instanceId: instanceId!) if (runningInstance != nil) && (runningInstance!.publicIpAddress != nil) { print("\nYou can SSH to this instance using the following command:") print("ssh -i \(keyUrl.path) ec2-user@\(runningInstance!.publicIpAddress!)") } //===================================================================== // 11. Stop the instance and wait for it to stop (StopInstances). //===================================================================== print("Stopping the instance...") if !(await self.stopInstance(instanceId: instanceId!, waitUntilStopped: true)) { await cleanUp() return } //===================================================================== // 12. Start the instance and wait for it to start (StartInstances). //===================================================================== print("Starting the instance again...") if !(await self.startInstance(instanceId: instanceId!, waitUntilStarted: true)) { await cleanUp() return } //===================================================================== // 13. Display SSH connection info for the instance. Note that it's // changed. //===================================================================== runningInstance = await self.describeInstance(instanceId: instanceId!) if (runningInstance != nil) && (runningInstance!.publicIpAddress != nil) { print("\nYou can SSH to this instance using the following command.") print("This is probably different from when the instance was running before.") print("ssh -i \(keyUrl.path) ec2-user@\(runningInstance!.publicIpAddress!)") } //===================================================================== // 14. Allocate an elastic IP and associate it with the instance // (AllocateAddress and AssociateAddress). //===================================================================== allocationId = await self.allocateAddress() if allocationId == nil { await cleanUp() return } associationId = await self.associateAddress(instanceId: instanceId!, allocationId: allocationId) if associationId == nil { await cleanUp() return } //===================================================================== // 15. Display SSH connection info for the connection. Note that the // public IP is now the Elastic IP, which stays constant. //===================================================================== runningInstance = await self.describeInstance(instanceId: instanceId!) if (runningInstance != nil) && (runningInstance!.publicIpAddress != nil) { print("\nYou can SSH to this instance using the following command.") print("This has changed again, and is now the Elastic IP.") print("ssh -i \(keyUrl.path) ec2-user@\(runningInstance!.publicIpAddress!)") } //===================================================================== // Handle all cleanup tasks //===================================================================== await cleanUp() } /// Clean up by discarding and closing down all allocated EC2 items: /// /// * Elastic IP allocation and association /// * Terminate the instance /// * Delete the security group /// * Delete the key pair func cleanUp() async { //===================================================================== // 16. Disassociate and delete the Elastic IP (DisassociateAddress and // ReleaseAddress). //===================================================================== if associationId != nil { await self.disassociateAddress(associationId: associationId!) } if allocationId != nil { await self.releaseAddress(allocationId: allocationId!) } //===================================================================== // 17. Terminate the instance and wait for it to terminate // (TerminateInstances). //===================================================================== if instanceId != nil { print("Terminating the instance...") _ = await self.terminateInstance(instanceId: instanceId!, waitUntilTerminated: true) } //===================================================================== // 18. Delete the security group (DeleteSecurityGroup). //===================================================================== if securityGroupId != nil { print("Deleting the security group...") _ = await self.deleteSecurityGroup(groupId: securityGroupId!) } //===================================================================== // 19. Delete the key pair (DeleteKeyPair). //===================================================================== if keyName != nil { print("Deleting the key pair...") _ = await self.deleteKeyPair(keyPair: keyName!) } } /// Create a new RSA key pair and save the private key to a randomly-named /// file in the temporary directory. /// /// - Parameter name: The name of the key pair to create. /// /// - Returns: The URL of the newly created `.pem` file or `nil` if unable /// to create the key pair. func createKeyPair(name: String) async -> URL? { do { let output = try await ec2Client.createKeyPair( input: CreateKeyPairInput( keyName: name ) ) guard let keyMaterial = output.keyMaterial else { return nil } // Build the URL of the temporary private key file. let fileURL = URL.temporaryDirectory .appendingPathComponent(name) .appendingPathExtension("pem") do { try keyMaterial.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8) return fileURL } catch { print("*** Failed to write the private key.") return nil } } catch { print("*** Unable to create the key pair.") return nil } } /// Describe the key pairs associated with the user by outputting each key /// pair's name and fingerprint. func describeKeyPairs() async { do { let output = try await ec2Client.describeKeyPairs( input: DescribeKeyPairsInput() ) guard let keyPairs = output.keyPairs else { print("*** No key pairs list available.") return } for keyPair in keyPairs { print(keyPair.keyName ?? "<unknown>", ":", keyPair.keyFingerprint ?? "<unknown>") } } catch { print("*** Error: Unable to obtain a key pair list.") } } /// Delete an EC2 key pair. /// /// - Parameter keyPair: The name of the key pair to delete. /// /// - Returns: `true` if the key pair is deleted successfully; otherwise /// `false`. func deleteKeyPair(keyPair: String) async -> Bool { do { _ = try await ec2Client.deleteKeyPair( input: DeleteKeyPairInput( keyName: keyPair ) ) return true } catch { print("*** Error deleting the key pair: \(error.localizedDescription)") return false } } /// Return a list of AMI names that contain the specified string. /// /// - Parameter filter: A string that must be contained in all returned /// AMI names. /// /// - Returns: An array of the parameters matching the specified substring. func findAMIsMatchingFilter(_ filter: String) async -> [SSMClientTypes.Parameter] { var parameterList: [SSMClientTypes.Parameter] = [] var matchingAMIs: [SSMClientTypes.Parameter] = [] do { let pages = ssmClient.getParametersByPathPaginated( input: GetParametersByPathInput( path: "/aws/service/ami-amazon-linux-latest" ) ) for try await page in pages { guard let parameters = page.parameters else { return matchingAMIs } for parameter in parameters { parameterList.append(parameter) } } print("Found \(parameterList.count) images total:") for parameter in parameterList { guard let name = parameter.name else { continue } print(" \(name)") if name.contains(filter) { matchingAMIs.append(parameter) } } } catch { return matchingAMIs } return matchingAMIs } /// Return a list of instance types matching the specified architecture /// and instance sizes. /// /// - Parameters: /// - architecture: The architecture of the instance types to return, as /// a member of `EC2ClientTypes.ArchitectureValues`. /// - sizes: An array of one or more strings identifying sizes of /// instance type to accept. /// /// - Returns: An array of `EC2ClientTypes.InstanceTypeInfo` records /// describing the instance types matching the given requirements. func getMatchingInstanceTypes(architecture: EC2ClientTypes.ArchitectureValues = EC2ClientTypes.ArchitectureValues.x8664, sizes: [String] = ["*.micro", "*.small"]) async -> [EC2ClientTypes.InstanceTypeInfo] { var instanceTypes: [EC2ClientTypes.InstanceTypeInfo] = [] let archFilter = EC2ClientTypes.Filter( name: "processor-info.supported-architecture", values: [architecture.rawValue] ) let sizeFilter = EC2ClientTypes.Filter( name: "instance-type", values: sizes ) do { let pages = ec2Client.describeInstanceTypesPaginated( input: DescribeInstanceTypesInput( filters: [archFilter, sizeFilter] ) ) for try await page in pages { guard let types = page.instanceTypes else { return [] } instanceTypes += types } } catch { print("*** Error getting image types: \(error.localizedDescription)") return [] } return instanceTypes } /// Get the latest information about the specified instance and output it /// to the screen, returning the instance details to the caller. /// /// - Parameters: /// - instanceId: The ID of the instance to provide details about. /// - stateFilter: The state to require the instance to be in. /// /// - Returns: The instance's details as an `EC2ClientTypes.Instance` object. func describeInstance(instanceId: String, stateFilter: EC2ClientTypes.InstanceStateName? = EC2ClientTypes.InstanceStateName.running) async -> EC2ClientTypes.Instance? { do { let pages = ec2Client.describeInstancesPaginated( input: DescribeInstancesInput( instanceIds: [instanceId] ) ) for try await page in pages { guard let reservations = page.reservations else { continue } for reservation in reservations { guard let instances = reservation.instances else { continue } for instance in instances { guard let state = instance.state else { print("*** Instance is missing its state...") continue } let instanceState = state.name if stateFilter != nil && (instanceState != stateFilter) { continue } let instanceTypeName: String if instance.instanceType == nil { instanceTypeName = "<N/A>" } else { instanceTypeName = instance.instanceType?.rawValue ?? "<N/A>" } let instanceStateName: String if instanceState == nil { instanceStateName = "<N/A>" } else { instanceStateName = instanceState?.rawValue ?? "<N/A>" } print(""" Instance: \(instance.instanceId ?? "<N/A>") • Image ID: \(instance.imageId ?? "<N/A>") • Instance type: \(instanceTypeName) • Key name: \(instance.keyName ?? "<N/A>") • VPC ID: \(instance.vpcId ?? "<N/A>") • Public IP: \(instance.publicIpAddress ?? "N/A") • State: \(instanceStateName) """) return instance } } } } catch { print("*** Error retrieving instance information to display: \(error.localizedDescription)") return nil } return nil } /// Stop the specified instance. /// /// - Parameters: /// - instanceId: The ID of the instance to stop. /// - waitUntilStopped: If `true`, execution waits until the instance /// has stopped. Otherwise, execution continues and the instance stops /// asynchronously. /// /// - Returns: `true` if the image is successfully stopped (or is left to /// stop asynchronously). `false` if the instance doesn't stop. func stopInstance(instanceId: String, waitUntilStopped: Bool = false) async -> Bool { let instanceList = [instanceId] do { _ = try await ec2Client.stopInstances( input: StopInstancesInput( instanceIds: instanceList ) ) if waitUntilStopped { print("Waiting for the instance to stop. Please be patient!") let waitOptions = WaiterOptions(maxWaitTime: 600) let output = try await ec2Client.waitUntilInstanceStopped( options: waitOptions, input: DescribeInstancesInput( instanceIds: instanceList ) ) switch output.result { case .success: return true case .failure: return false } } else { return true } } catch { print("*** Unable to stop the instance: \(error.localizedDescription)") return false } } /// Start the specified instance. /// /// - Parameters: /// - instanceId: The ID of the instance to start. /// - waitUntilStarted: If `true`, execution waits until the instance /// has started. Otherwise, execution continues and the instance starts /// asynchronously. /// /// - Returns: `true` if the image is successfully started (or is left to /// start asynchronously). `false` if the instance doesn't start. func startInstance(instanceId: String, waitUntilStarted: Bool = false) async -> Bool { let instanceList = [instanceId] do { _ = try await ec2Client.startInstances( input: StartInstancesInput( instanceIds: instanceList ) ) if waitUntilStarted { print("Waiting for the instance to start...") let waitOptions = WaiterOptions(maxWaitTime: 60.0) let output = try await ec2Client.waitUntilInstanceRunning( options: waitOptions, input: DescribeInstancesInput( instanceIds: instanceList ) ) switch output.result { case .success: return true case .failure: return false } } else { return true } } catch { print("*** Unable to start the instance: \(error.localizedDescription)") return false } } /// Terminate the specified instance. /// /// - Parameters: /// - instanceId: The instance to terminate. /// - waitUntilTerminated: Whether or not to wait until the instance is /// terminated before returning. /// /// - Returns: `true` if terminated successfully. `false` if not or if an /// error occurs. func terminateInstance(instanceId: String, waitUntilTerminated: Bool = false) async -> Bool { let instanceList = [instanceId] do { _ = try await ec2Client.terminateInstances( input: TerminateInstancesInput( instanceIds: instanceList ) ) if waitUntilTerminated { print("Waiting for the instance to terminate...") let waitOptions = WaiterOptions(maxWaitTime: 600.0) let output = try await ec2Client.waitUntilInstanceTerminated( options: waitOptions, input: DescribeInstancesInput( instanceIds: instanceList ) ) switch output.result { case .success: return true case .failure: return false } } else { return true } } catch { print("*** Unable to terminate the instance: \(error.localizedDescription)") return false } } /// Return an array of `EC2ClientTypes.Image` objects describing all of /// the images in the specified array. /// /// - Parameter idList: A list of image ID strings indicating the images /// to return details about. /// /// - Returns: An array of the images. func describeImages(_ idList: [String]) async -> [EC2ClientTypes.Image] { do { let output = try await ec2Client.describeImages( input: DescribeImagesInput( imageIds: idList ) ) guard let images = output.images else { print("*** No images found.") return [] } for image in images { guard let id = image.imageId else { continue } print(" \(id): \(image.description ?? "<no description>")") } return images } catch { print("*** Error getting image descriptions: \(error.localizedDescription)") return [] } } /// Create and return a new EC2 instance. /// /// - Parameters: /// - imageId: The image ID of the AMI to use when creating the instance. /// - instanceType: The type of instance to create. /// - keyPairName: The RSA key pair's name to use to secure the instance. /// - securityGroups: The security group or groups to add the instance /// to. /// /// - Returns: The EC2 instance as an `EC2ClientTypes.Instance` object. func runInstance(imageId: String, instanceType: EC2ClientTypes.InstanceType, keyPairName: String, securityGroups: [String]?) async -> EC2ClientTypes.Instance? { do { let output = try await ec2Client.runInstances( input: RunInstancesInput( imageId: imageId, instanceType: instanceType, keyName: keyPairName, maxCount: 1, minCount: 1, securityGroupIds: securityGroups ) ) guard let instances = output.instances else { print("*** Unable to create the instance.") return nil } return instances[0] } catch { print("*** Error creating the instance: \(error.localizedDescription)") return nil } } /// Return the device's external IP address. /// /// - Returns: A string containing the device's IP address. func getMyIPAddress() -> String? { guard let url = URL(string: "http://checkip.amazonaws.com") else { print("Couldn't create the URL") return nil } do { print("Getting the IP address...") return try String(contentsOf: url, encoding: String.Encoding.utf8).trim() } catch { print("*** Unable to get your public IP address.") return nil } } /// Create a new security group. /// /// - Parameters: /// - groupName: The name of the group to create. /// - groupDescription: A description of the new security group. /// /// - Returns: The ID string of the new security group. func createSecurityGroup(name groupName: String, description groupDescription: String) async -> String? { do { let output = try await ec2Client.createSecurityGroup( input: CreateSecurityGroupInput( description: groupDescription, groupName: groupName ) ) return output.groupId } catch { print("*** Error creating the security group: \(error.localizedDescription)") return nil } } /// Authorize ingress of connections for the security group. /// /// - Parameters: /// - groupId: The group ID of the security group to authorize access for. /// - ipAddress: The IP address of the device to grant access to. /// /// - Returns: `true` if access is successfully granted; otherwise `false`. func authorizeSecurityGroupIngress(groupId: String, ipAddress: String) async -> Bool { let ipRange = EC2ClientTypes.IpRange(cidrIp: "\(ipAddress)/0") let httpPermission = EC2ClientTypes.IpPermission( fromPort: 80, ipProtocol: "tcp", ipRanges: [ipRange], toPort: 80 ) let sshPermission = EC2ClientTypes.IpPermission( fromPort: 22, ipProtocol: "tcp", ipRanges: [ipRange], toPort: 22 ) do { _ = try await ec2Client.authorizeSecurityGroupIngress( input: AuthorizeSecurityGroupIngressInput( groupId: groupId, ipPermissions: [httpPermission, sshPermission] ) ) return true } catch { print("*** Error authorizing ingress for the security group: \(error.localizedDescription)") return false } } func describeSecurityGroups(groupId: String) async -> Bool { do { let output = try await ec2Client.describeSecurityGroups( input: DescribeSecurityGroupsInput( groupIds: [groupId] ) ) guard let securityGroups = output.securityGroups else { print("No security groups found.") return true } for group in securityGroups { print("Group \(group.groupId ?? "<unknown>") found with VPC \(group.vpcId ?? "<unknown>")") } return true } catch { print("*** Error getting security group details: \(error.localizedDescription)") return false } } /// Delete a security group. /// /// - Parameter groupId: The ID of the security group to delete. /// /// - Returns: `true` on successful deletion; `false` on error. func deleteSecurityGroup(groupId: String) async -> Bool { do { _ = try await ec2Client.deleteSecurityGroup( input: DeleteSecurityGroupInput( groupId: groupId ) ) return true } catch { print("*** Error deleting the security group: \(error.localizedDescription)") return false } } /// Allocate an Elastic IP address. /// /// - Returns: A string containing the ID of the Elastic IP. func allocateAddress() async -> String? { do { let output = try await ec2Client.allocateAddress( input: AllocateAddressInput( domain: EC2ClientTypes.DomainType.vpc ) ) guard let allocationId = output.allocationId else { return nil } return allocationId } catch { print("*** Unable to allocate the IP address: \(error.localizedDescription)") return nil } } /// Associate the specified allocated Elastic IP to a given instance. /// /// - Parameters: /// - instanceId: The instance to associate the Elastic IP with. /// - allocationId: The ID of the allocated Elastic IP to associate with /// the instance. /// /// - Returns: The association ID of the association. func associateAddress(instanceId: String?, allocationId: String?) async -> String? { do { let output = try await ec2Client.associateAddress( input: AssociateAddressInput( allocationId: allocationId, instanceId: instanceId ) ) return output.associationId } catch { print("*** Unable to associate the IP address: \(error.localizedDescription)") return nil } } /// Disassociate an Elastic IP. /// /// - Parameter associationId: The ID of the association to end. func disassociateAddress(associationId: String?) async { do { _ = try await ec2Client.disassociateAddress( input: DisassociateAddressInput( associationId: associationId ) ) } catch { print("*** Unable to disassociate the IP address: \(error.localizedDescription)") } } /// Release an allocated Elastic IP. /// /// - Parameter allocationId: The allocation ID of the Elastic IP to /// release. func releaseAddress(allocationId: String?) async { do { _ = try await ec2Client.releaseAddress( input: ReleaseAddressInput( allocationId: allocationId ) ) } catch { print("*** Unable to release the IP address: \(error.localizedDescription)") } } /// Generate and return a unique file name that begins with the specified /// string. /// /// - Parameters: /// - prefix: Text to use at the beginning of the returned name. /// /// - Returns: A string containing a unique filename that begins with the /// specified `prefix`. /// /// The returned name uses a random number between 1 million and 1 billion to /// provide reasonable certainty of uniqueness for the purposes of this /// example. func tempName(prefix: String) -> String { return "\(prefix)-\(Int.random(in: 1000000..<1000000000))" } } /// The program's asynchronous entry point. @main struct Main { static func main() async { let args = Array(CommandLine.arguments.dropFirst()) do { let command = try ExampleCommand.parse(args) try await command.runAsync() } catch { ExampleCommand.exit(withError: error) } } }

Actions

The following code example shows how to use AllocateAddress.

SDK for Swift
Note

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

import AWSEC2 /// Allocate an Elastic IP address. /// /// - Returns: A string containing the ID of the Elastic IP. func allocateAddress() async -> String? { do { let output = try await ec2Client.allocateAddress( input: AllocateAddressInput( domain: EC2ClientTypes.DomainType.vpc ) ) guard let allocationId = output.allocationId else { return nil } return allocationId } catch { print("*** Unable to allocate the IP address: \(error.localizedDescription)") return nil } }

The following code example shows how to use AssociateAddress.

SDK for Swift
Note

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

import AWSEC2 /// Associate the specified allocated Elastic IP to a given instance. /// /// - Parameters: /// - instanceId: The instance to associate the Elastic IP with. /// - allocationId: The ID of the allocated Elastic IP to associate with /// the instance. /// /// - Returns: The association ID of the association. func associateAddress(instanceId: String?, allocationId: String?) async -> String? { do { let output = try await ec2Client.associateAddress( input: AssociateAddressInput( allocationId: allocationId, instanceId: instanceId ) ) return output.associationId } catch { print("*** Unable to associate the IP address: \(error.localizedDescription)") return nil } }

The following code example shows how to use AuthorizeSecurityGroupIngress.

SDK for Swift
Note

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

import AWSEC2 /// Authorize ingress of connections for the security group. /// /// - Parameters: /// - groupId: The group ID of the security group to authorize access for. /// - ipAddress: The IP address of the device to grant access to. /// /// - Returns: `true` if access is successfully granted; otherwise `false`. func authorizeSecurityGroupIngress(groupId: String, ipAddress: String) async -> Bool { let ipRange = EC2ClientTypes.IpRange(cidrIp: "\(ipAddress)/0") let httpPermission = EC2ClientTypes.IpPermission( fromPort: 80, ipProtocol: "tcp", ipRanges: [ipRange], toPort: 80 ) let sshPermission = EC2ClientTypes.IpPermission( fromPort: 22, ipProtocol: "tcp", ipRanges: [ipRange], toPort: 22 ) do { _ = try await ec2Client.authorizeSecurityGroupIngress( input: AuthorizeSecurityGroupIngressInput( groupId: groupId, ipPermissions: [httpPermission, sshPermission] ) ) return true } catch { print("*** Error authorizing ingress for the security group: \(error.localizedDescription)") return false } }

The following code example shows how to use CreateKeyPair.

SDK for Swift
Note

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

import AWSEC2 /// Create a new RSA key pair and save the private key to a randomly-named /// file in the temporary directory. /// /// - Parameter name: The name of the key pair to create. /// /// - Returns: The URL of the newly created `.pem` file or `nil` if unable /// to create the key pair. func createKeyPair(name: String) async -> URL? { do { let output = try await ec2Client.createKeyPair( input: CreateKeyPairInput( keyName: name ) ) guard let keyMaterial = output.keyMaterial else { return nil } // Build the URL of the temporary private key file. let fileURL = URL.temporaryDirectory .appendingPathComponent(name) .appendingPathExtension("pem") do { try keyMaterial.write(to: fileURL, atomically: true, encoding: String.Encoding.utf8) return fileURL } catch { print("*** Failed to write the private key.") return nil } } catch { print("*** Unable to create the key pair.") return nil } }
  • For API details, see CreateKeyPair in AWS SDK for Swift API reference.

The following code example shows how to use CreateSecurityGroup.

SDK for Swift
Note

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

import AWSEC2 /// Create a new security group. /// /// - Parameters: /// - groupName: The name of the group to create. /// - groupDescription: A description of the new security group. /// /// - Returns: The ID string of the new security group. func createSecurityGroup(name groupName: String, description groupDescription: String) async -> String? { do { let output = try await ec2Client.createSecurityGroup( input: CreateSecurityGroupInput( description: groupDescription, groupName: groupName ) ) return output.groupId } catch { print("*** Error creating the security group: \(error.localizedDescription)") return nil } }

The following code example shows how to use DeleteKeyPair.

SDK for Swift
Note

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

import AWSEC2 /// Delete an EC2 key pair. /// /// - Parameter keyPair: The name of the key pair to delete. /// /// - Returns: `true` if the key pair is deleted successfully; otherwise /// `false`. func deleteKeyPair(keyPair: String) async -> Bool { do { _ = try await ec2Client.deleteKeyPair( input: DeleteKeyPairInput( keyName: keyPair ) ) return true } catch { print("*** Error deleting the key pair: \(error.localizedDescription)") return false } }
  • For API details, see DeleteKeyPair in AWS SDK for Swift API reference.

The following code example shows how to use DeleteSecurityGroup.

SDK for Swift
Note

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

import AWSEC2 /// Delete a security group. /// /// - Parameter groupId: The ID of the security group to delete. /// /// - Returns: `true` on successful deletion; `false` on error. func deleteSecurityGroup(groupId: String) async -> Bool { do { _ = try await ec2Client.deleteSecurityGroup( input: DeleteSecurityGroupInput( groupId: groupId ) ) return true } catch { print("*** Error deleting the security group: \(error.localizedDescription)") return false } }

The following code example shows how to use DescribeImages.

SDK for Swift
Note

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

import AWSEC2 /// Return an array of `EC2ClientTypes.Image` objects describing all of /// the images in the specified array. /// /// - Parameter idList: A list of image ID strings indicating the images /// to return details about. /// /// - Returns: An array of the images. func describeImages(_ idList: [String]) async -> [EC2ClientTypes.Image] { do { let output = try await ec2Client.describeImages( input: DescribeImagesInput( imageIds: idList ) ) guard let images = output.images else { print("*** No images found.") return [] } for image in images { guard let id = image.imageId else { continue } print(" \(id): \(image.description ?? "<no description>")") } return images } catch { print("*** Error getting image descriptions: \(error.localizedDescription)") return [] } }
  • For API details, see DescribeImages in AWS SDK for Swift API reference.

The following code example shows how to use DescribeInstanceTypes.

SDK for Swift
Note

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

import AWSEC2 /// Return a list of instance types matching the specified architecture /// and instance sizes. /// /// - Parameters: /// - architecture: The architecture of the instance types to return, as /// a member of `EC2ClientTypes.ArchitectureValues`. /// - sizes: An array of one or more strings identifying sizes of /// instance type to accept. /// /// - Returns: An array of `EC2ClientTypes.InstanceTypeInfo` records /// describing the instance types matching the given requirements. func getMatchingInstanceTypes(architecture: EC2ClientTypes.ArchitectureValues = EC2ClientTypes.ArchitectureValues.x8664, sizes: [String] = ["*.micro", "*.small"]) async -> [EC2ClientTypes.InstanceTypeInfo] { var instanceTypes: [EC2ClientTypes.InstanceTypeInfo] = [] let archFilter = EC2ClientTypes.Filter( name: "processor-info.supported-architecture", values: [architecture.rawValue] ) let sizeFilter = EC2ClientTypes.Filter( name: "instance-type", values: sizes ) do { let pages = ec2Client.describeInstanceTypesPaginated( input: DescribeInstanceTypesInput( filters: [archFilter, sizeFilter] ) ) for try await page in pages { guard let types = page.instanceTypes else { return [] } instanceTypes += types } } catch { print("*** Error getting image types: \(error.localizedDescription)") return [] } return instanceTypes }

The following code example shows how to use DescribeKeyPairs.

SDK for Swift
Note

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

import AWSEC2 /// Describe the key pairs associated with the user by outputting each key /// pair's name and fingerprint. func describeKeyPairs() async { do { let output = try await ec2Client.describeKeyPairs( input: DescribeKeyPairsInput() ) guard let keyPairs = output.keyPairs else { print("*** No key pairs list available.") return } for keyPair in keyPairs { print(keyPair.keyName ?? "<unknown>", ":", keyPair.keyFingerprint ?? "<unknown>") } } catch { print("*** Error: Unable to obtain a key pair list.") } }

The following code example shows how to use DescribeSecurityGroups.

SDK for Swift
Note

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

Using pagination with describeSecurityGroupsPaginated().

import AWSEC2 /// Return an array of strings giving the names of every security group /// the user is a member of. /// /// - Parameter ec2Client: The `EC2Client` to use when calling /// `describeSecurityGroupsPaginated()`. /// /// - Returns: An array of strings giving the names of every security /// group the user is a member of. func getSecurityGroupNames(ec2Client: EC2Client) async -> [String] { let pages = ec2Client.describeSecurityGroupsPaginated( input: DescribeSecurityGroupsInput() ) var groupNames: [String] = [] do { for try await page in pages { guard let groups = page.securityGroups else { print("*** Error: No groups returned.") continue } for group in groups { groupNames.append(group.groupName ?? "<unknown>") } } } catch { print("*** Error: \(error.localizedDescription)") } return groupNames }

Without pagination.

import AWSEC2 func describeSecurityGroups(groupId: String) async -> Bool { do { let output = try await ec2Client.describeSecurityGroups( input: DescribeSecurityGroupsInput( groupIds: [groupId] ) ) guard let securityGroups = output.securityGroups else { print("No security groups found.") return true } for group in securityGroups { print("Group \(group.groupId ?? "<unknown>") found with VPC \(group.vpcId ?? "<unknown>")") } return true } catch { print("*** Error getting security group details: \(error.localizedDescription)") return false } }

The following code example shows how to use DisassociateAddress.

SDK for Swift
Note

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

import AWSEC2 /// Disassociate an Elastic IP. /// /// - Parameter associationId: The ID of the association to end. func disassociateAddress(associationId: String?) async { do { _ = try await ec2Client.disassociateAddress( input: DisassociateAddressInput( associationId: associationId ) ) } catch { print("*** Unable to disassociate the IP address: \(error.localizedDescription)") } }

The following code example shows how to use ReleaseAddress.

SDK for Swift
Note

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

import AWSEC2 /// Release an allocated Elastic IP. /// /// - Parameter allocationId: The allocation ID of the Elastic IP to /// release. func releaseAddress(allocationId: String?) async { do { _ = try await ec2Client.releaseAddress( input: ReleaseAddressInput( allocationId: allocationId ) ) } catch { print("*** Unable to release the IP address: \(error.localizedDescription)") } }
  • For API details, see ReleaseAddress in AWS SDK for Swift API reference.

The following code example shows how to use RunInstances.

SDK for Swift
Note

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

import AWSEC2 /// Create and return a new EC2 instance. /// /// - Parameters: /// - imageId: The image ID of the AMI to use when creating the instance. /// - instanceType: The type of instance to create. /// - keyPairName: The RSA key pair's name to use to secure the instance. /// - securityGroups: The security group or groups to add the instance /// to. /// /// - Returns: The EC2 instance as an `EC2ClientTypes.Instance` object. func runInstance(imageId: String, instanceType: EC2ClientTypes.InstanceType, keyPairName: String, securityGroups: [String]?) async -> EC2ClientTypes.Instance? { do { let output = try await ec2Client.runInstances( input: RunInstancesInput( imageId: imageId, instanceType: instanceType, keyName: keyPairName, maxCount: 1, minCount: 1, securityGroupIds: securityGroups ) ) guard let instances = output.instances else { print("*** Unable to create the instance.") return nil } return instances[0] } catch { print("*** Error creating the instance: \(error.localizedDescription)") return nil } }
  • For API details, see RunInstances in AWS SDK for Swift API reference.

The following code example shows how to use StartInstances.

SDK for Swift
Note

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

import AWSEC2 /// Start the specified instance. /// /// - Parameters: /// - instanceId: The ID of the instance to start. /// - waitUntilStarted: If `true`, execution waits until the instance /// has started. Otherwise, execution continues and the instance starts /// asynchronously. /// /// - Returns: `true` if the image is successfully started (or is left to /// start asynchronously). `false` if the instance doesn't start. func startInstance(instanceId: String, waitUntilStarted: Bool = false) async -> Bool { let instanceList = [instanceId] do { _ = try await ec2Client.startInstances( input: StartInstancesInput( instanceIds: instanceList ) ) if waitUntilStarted { print("Waiting for the instance to start...") let waitOptions = WaiterOptions(maxWaitTime: 60.0) let output = try await ec2Client.waitUntilInstanceRunning( options: waitOptions, input: DescribeInstancesInput( instanceIds: instanceList ) ) switch output.result { case .success: return true case .failure: return false } } else { return true } } catch { print("*** Unable to start the instance: \(error.localizedDescription)") return false } }
  • For API details, see StartInstances in AWS SDK for Swift API reference.

The following code example shows how to use StopInstances.

SDK for Swift
Note

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

import AWSEC2 /// Stop the specified instance. /// /// - Parameters: /// - instanceId: The ID of the instance to stop. /// - waitUntilStopped: If `true`, execution waits until the instance /// has stopped. Otherwise, execution continues and the instance stops /// asynchronously. /// /// - Returns: `true` if the image is successfully stopped (or is left to /// stop asynchronously). `false` if the instance doesn't stop. func stopInstance(instanceId: String, waitUntilStopped: Bool = false) async -> Bool { let instanceList = [instanceId] do { _ = try await ec2Client.stopInstances( input: StopInstancesInput( instanceIds: instanceList ) ) if waitUntilStopped { print("Waiting for the instance to stop. Please be patient!") let waitOptions = WaiterOptions(maxWaitTime: 600) let output = try await ec2Client.waitUntilInstanceStopped( options: waitOptions, input: DescribeInstancesInput( instanceIds: instanceList ) ) switch output.result { case .success: return true case .failure: return false } } else { return true } } catch { print("*** Unable to stop the instance: \(error.localizedDescription)") return false } }
  • For API details, see StopInstances in AWS SDK for Swift API reference.

The following code example shows how to use TerminateInstances.

SDK for Swift
Note

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

import AWSEC2 /// Terminate the specified instance. /// /// - Parameters: /// - instanceId: The instance to terminate. /// - waitUntilTerminated: Whether or not to wait until the instance is /// terminated before returning. /// /// - Returns: `true` if terminated successfully. `false` if not or if an /// error occurs. func terminateInstance(instanceId: String, waitUntilTerminated: Bool = false) async -> Bool { let instanceList = [instanceId] do { _ = try await ec2Client.terminateInstances( input: TerminateInstancesInput( instanceIds: instanceList ) ) if waitUntilTerminated { print("Waiting for the instance to terminate...") let waitOptions = WaiterOptions(maxWaitTime: 600.0) let output = try await ec2Client.waitUntilInstanceTerminated( options: waitOptions, input: DescribeInstancesInput( instanceIds: instanceList ) ) switch output.result { case .success: return true case .failure: return false } } else { return true } } catch { print("*** Unable to terminate the instance: \(error.localizedDescription)") return false } }