github.com/darmach/terratest@v0.34.8-0.20210517103231-80931f95e3ff/modules/aws/ec2.go (about)

     1  package aws
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/aws/aws-sdk-go/aws"
     7  	"github.com/aws/aws-sdk-go/service/ec2"
     8  	"github.com/gruntwork-io/terratest/modules/logger"
     9  	"github.com/gruntwork-io/terratest/modules/testing"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  // GetPrivateIpOfEc2Instance gets the private IP address of the given EC2 Instance in the given region.
    14  func GetPrivateIpOfEc2Instance(t testing.TestingT, instanceID string, awsRegion string) string {
    15  	ip, err := GetPrivateIpOfEc2InstanceE(t, instanceID, awsRegion)
    16  	require.NoError(t, err)
    17  	return ip
    18  }
    19  
    20  // GetPrivateIpOfEc2InstanceE gets the private IP address of the given EC2 Instance in the given region.
    21  func GetPrivateIpOfEc2InstanceE(t testing.TestingT, instanceID string, awsRegion string) (string, error) {
    22  	ips, err := GetPrivateIpsOfEc2InstancesE(t, []string{instanceID}, awsRegion)
    23  	if err != nil {
    24  		return "", err
    25  	}
    26  
    27  	ip, containsIP := ips[instanceID]
    28  
    29  	if !containsIP {
    30  		return "", IpForEc2InstanceNotFound{InstanceId: instanceID, AwsRegion: awsRegion, Type: "private"}
    31  	}
    32  
    33  	return ip, nil
    34  }
    35  
    36  // GetPrivateIpsOfEc2Instances gets the private IP address of the given EC2 Instance in the given region. Returns a map of instance ID to IP address.
    37  func GetPrivateIpsOfEc2Instances(t testing.TestingT, instanceIDs []string, awsRegion string) map[string]string {
    38  	ips, err := GetPrivateIpsOfEc2InstancesE(t, instanceIDs, awsRegion)
    39  	require.NoError(t, err)
    40  	return ips
    41  }
    42  
    43  // GetPrivateIpsOfEc2InstancesE gets the private IP address of the given EC2 Instance in the given region. Returns a map of instance ID to IP address.
    44  func GetPrivateIpsOfEc2InstancesE(t testing.TestingT, instanceIDs []string, awsRegion string) (map[string]string, error) {
    45  	ec2Client := NewEc2Client(t, awsRegion)
    46  	// TODO: implement pagination for cases that extend beyond limit (1000 instances)
    47  	input := ec2.DescribeInstancesInput{InstanceIds: aws.StringSlice(instanceIDs)}
    48  	output, err := ec2Client.DescribeInstances(&input)
    49  	if err != nil {
    50  		return nil, err
    51  	}
    52  
    53  	ips := map[string]string{}
    54  
    55  	for _, reserveration := range output.Reservations {
    56  		for _, instance := range reserveration.Instances {
    57  			ips[aws.StringValue(instance.InstanceId)] = aws.StringValue(instance.PrivateIpAddress)
    58  		}
    59  	}
    60  
    61  	return ips, nil
    62  }
    63  
    64  // GetPrivateHostnameOfEc2Instance gets the private IP address of the given EC2 Instance in the given region.
    65  func GetPrivateHostnameOfEc2Instance(t testing.TestingT, instanceID string, awsRegion string) string {
    66  	ip, err := GetPrivateHostnameOfEc2InstanceE(t, instanceID, awsRegion)
    67  	require.NoError(t, err)
    68  	return ip
    69  }
    70  
    71  // GetPrivateHostnameOfEc2InstanceE gets the private IP address of the given EC2 Instance in the given region.
    72  func GetPrivateHostnameOfEc2InstanceE(t testing.TestingT, instanceID string, awsRegion string) (string, error) {
    73  	hostnames, err := GetPrivateHostnamesOfEc2InstancesE(t, []string{instanceID}, awsRegion)
    74  	if err != nil {
    75  		return "", err
    76  	}
    77  
    78  	hostname, containsHostname := hostnames[instanceID]
    79  
    80  	if !containsHostname {
    81  		return "", HostnameForEc2InstanceNotFound{InstanceId: instanceID, AwsRegion: awsRegion, Type: "private"}
    82  	}
    83  
    84  	return hostname, nil
    85  }
    86  
    87  // GetPrivateHostnamesOfEc2Instances gets the private IP address of the given EC2 Instance in the given region. Returns a map of instance ID to IP address.
    88  func GetPrivateHostnamesOfEc2Instances(t testing.TestingT, instanceIDs []string, awsRegion string) map[string]string {
    89  	ips, err := GetPrivateHostnamesOfEc2InstancesE(t, instanceIDs, awsRegion)
    90  	require.NoError(t, err)
    91  	return ips
    92  }
    93  
    94  // GetPrivateHostnamesOfEc2InstancesE gets the private IP address of the given EC2 Instance in the given region. Returns a map of instance ID to IP address.
    95  func GetPrivateHostnamesOfEc2InstancesE(t testing.TestingT, instanceIDs []string, awsRegion string) (map[string]string, error) {
    96  	ec2Client, err := NewEc2ClientE(t, awsRegion)
    97  	if err != nil {
    98  		return nil, err
    99  	}
   100  	// TODO: implement pagination for cases that extend beyond limit (1000 instances)
   101  	input := ec2.DescribeInstancesInput{InstanceIds: aws.StringSlice(instanceIDs)}
   102  	output, err := ec2Client.DescribeInstances(&input)
   103  	if err != nil {
   104  		return nil, err
   105  	}
   106  
   107  	hostnames := map[string]string{}
   108  
   109  	for _, reserveration := range output.Reservations {
   110  		for _, instance := range reserveration.Instances {
   111  			hostnames[aws.StringValue(instance.InstanceId)] = aws.StringValue(instance.PrivateDnsName)
   112  		}
   113  	}
   114  
   115  	return hostnames, nil
   116  }
   117  
   118  // GetPublicIpOfEc2Instance gets the public IP address of the given EC2 Instance in the given region.
   119  func GetPublicIpOfEc2Instance(t testing.TestingT, instanceID string, awsRegion string) string {
   120  	ip, err := GetPublicIpOfEc2InstanceE(t, instanceID, awsRegion)
   121  	require.NoError(t, err)
   122  	return ip
   123  }
   124  
   125  // GetPublicIpOfEc2InstanceE gets the public IP address of the given EC2 Instance in the given region.
   126  func GetPublicIpOfEc2InstanceE(t testing.TestingT, instanceID string, awsRegion string) (string, error) {
   127  	ips, err := GetPublicIpsOfEc2InstancesE(t, []string{instanceID}, awsRegion)
   128  	if err != nil {
   129  		return "", err
   130  	}
   131  
   132  	ip, containsIP := ips[instanceID]
   133  
   134  	if !containsIP {
   135  		return "", IpForEc2InstanceNotFound{InstanceId: instanceID, AwsRegion: awsRegion, Type: "public"}
   136  	}
   137  
   138  	return ip, nil
   139  }
   140  
   141  // GetPublicIpsOfEc2Instances gets the public IP address of the given EC2 Instance in the given region. Returns a map of instance ID to IP address.
   142  func GetPublicIpsOfEc2Instances(t testing.TestingT, instanceIDs []string, awsRegion string) map[string]string {
   143  	ips, err := GetPublicIpsOfEc2InstancesE(t, instanceIDs, awsRegion)
   144  	require.NoError(t, err)
   145  	return ips
   146  }
   147  
   148  // GetPublicIpsOfEc2InstancesE gets the public IP address of the given EC2 Instance in the given region. Returns a map of instance ID to IP address.
   149  func GetPublicIpsOfEc2InstancesE(t testing.TestingT, instanceIDs []string, awsRegion string) (map[string]string, error) {
   150  	ec2Client := NewEc2Client(t, awsRegion)
   151  	// TODO: implement pagination for cases that extend beyond limit (1000 instances)
   152  	input := ec2.DescribeInstancesInput{InstanceIds: aws.StringSlice(instanceIDs)}
   153  	output, err := ec2Client.DescribeInstances(&input)
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  
   158  	ips := map[string]string{}
   159  
   160  	for _, reserveration := range output.Reservations {
   161  		for _, instance := range reserveration.Instances {
   162  			ips[aws.StringValue(instance.InstanceId)] = aws.StringValue(instance.PublicIpAddress)
   163  		}
   164  	}
   165  
   166  	return ips, nil
   167  }
   168  
   169  // GetEc2InstanceIdsByTag returns all the IDs of EC2 instances in the given region with the given tag.
   170  func GetEc2InstanceIdsByTag(t testing.TestingT, region string, tagName string, tagValue string) []string {
   171  	out, err := GetEc2InstanceIdsByTagE(t, region, tagName, tagValue)
   172  	require.NoError(t, err)
   173  	return out
   174  }
   175  
   176  // GetEc2InstanceIdsByTagE returns all the IDs of EC2 instances in the given region with the given tag.
   177  func GetEc2InstanceIdsByTagE(t testing.TestingT, region string, tagName string, tagValue string) ([]string, error) {
   178  	ec2Filters := map[string][]string{
   179  		fmt.Sprintf("tag:%s", tagName): {tagValue},
   180  	}
   181  	return GetEc2InstanceIdsByFiltersE(t, region, ec2Filters)
   182  }
   183  
   184  // GetEc2InstanceIdsByFilters returns all the IDs of EC2 instances in the given region which match to EC2 filter list
   185  // as per https://docs.aws.amazon.com/sdk-for-go/api/service/ec2/#DescribeInstancesInput.
   186  func GetEc2InstanceIdsByFilters(t testing.TestingT, region string, ec2Filters map[string][]string) []string {
   187  	out, err := GetEc2InstanceIdsByFiltersE(t, region, ec2Filters)
   188  	require.NoError(t, err)
   189  	return out
   190  }
   191  
   192  // GetEc2InstanceIdsByFilters returns all the IDs of EC2 instances in the given region which match to EC2 filter list
   193  // as per https://docs.aws.amazon.com/sdk-for-go/api/service/ec2/#DescribeInstancesInput.
   194  func GetEc2InstanceIdsByFiltersE(t testing.TestingT, region string, ec2Filters map[string][]string) ([]string, error) {
   195  	client, err := NewEc2ClientE(t, region)
   196  	if err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	ec2FilterList := []*ec2.Filter{}
   201  
   202  	for name, values := range ec2Filters {
   203  		ec2FilterList = append(ec2FilterList, &ec2.Filter{Name: aws.String(name), Values: aws.StringSlice(values)})
   204  	}
   205  
   206  	// TODO: implement pagination for cases that extend beyond limit (1000 instances)
   207  	output, err := client.DescribeInstances(&ec2.DescribeInstancesInput{Filters: ec2FilterList})
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  
   212  	instanceIDs := []string{}
   213  
   214  	for _, reservation := range output.Reservations {
   215  		for _, instance := range reservation.Instances {
   216  			instanceIDs = append(instanceIDs, *instance.InstanceId)
   217  		}
   218  	}
   219  
   220  	return instanceIDs, err
   221  }
   222  
   223  // GetTagsForEc2Instance returns all the tags for the given EC2 Instance.
   224  func GetTagsForEc2Instance(t testing.TestingT, region string, instanceID string) map[string]string {
   225  	tags, err := GetTagsForEc2InstanceE(t, region, instanceID)
   226  	require.NoError(t, err)
   227  	return tags
   228  }
   229  
   230  // GetTagsForEc2InstanceE returns all the tags for the given EC2 Instance.
   231  func GetTagsForEc2InstanceE(t testing.TestingT, region string, instanceID string) (map[string]string, error) {
   232  	client, err := NewEc2ClientE(t, region)
   233  	if err != nil {
   234  		return nil, err
   235  	}
   236  
   237  	input := ec2.DescribeTagsInput{
   238  		Filters: []*ec2.Filter{
   239  			{
   240  				Name:   aws.String("resource-type"),
   241  				Values: aws.StringSlice([]string{"instance"}),
   242  			},
   243  			{
   244  				Name:   aws.String("resource-id"),
   245  				Values: aws.StringSlice([]string{instanceID}),
   246  			},
   247  		},
   248  	}
   249  
   250  	out, err := client.DescribeTags(&input)
   251  	if err != nil {
   252  		return nil, err
   253  	}
   254  
   255  	tags := map[string]string{}
   256  
   257  	for _, tag := range out.Tags {
   258  		tags[aws.StringValue(tag.Key)] = aws.StringValue(tag.Value)
   259  	}
   260  
   261  	return tags, nil
   262  }
   263  
   264  // DeleteAmi deletes the given AMI in the given region.
   265  func DeleteAmi(t testing.TestingT, region string, imageID string) {
   266  	require.NoError(t, DeleteAmiE(t, region, imageID))
   267  }
   268  
   269  // DeleteAmiE deletes the given AMI in the given region.
   270  func DeleteAmiE(t testing.TestingT, region string, imageID string) error {
   271  	logger.Logf(t, "Deregistering AMI %s", imageID)
   272  
   273  	client, err := NewEc2ClientE(t, region)
   274  	if err != nil {
   275  		return err
   276  	}
   277  
   278  	_, err = client.DeregisterImage(&ec2.DeregisterImageInput{ImageId: aws.String(imageID)})
   279  	return err
   280  }
   281  
   282  // AddTagsToResource adds the tags to the given taggable AWS resource such as EC2, AMI or VPC.
   283  func AddTagsToResource(t testing.TestingT, region string, resource string, tags map[string]string) {
   284  	require.NoError(t, AddTagsToResourceE(t, region, resource, tags))
   285  }
   286  
   287  // AddTagsToResourceE adds the tags to the given taggable AWS resource such as EC2, AMI or VPC.
   288  func AddTagsToResourceE(t testing.TestingT, region string, resource string, tags map[string]string) error {
   289  	client, err := NewEc2ClientE(t, region)
   290  	if err != nil {
   291  		return err
   292  	}
   293  
   294  	var awsTags []*ec2.Tag
   295  	for key, value := range tags {
   296  		awsTags = append(awsTags, &ec2.Tag{
   297  			Key:   aws.String(key),
   298  			Value: aws.String(value),
   299  		})
   300  	}
   301  
   302  	_, err = client.CreateTags(&ec2.CreateTagsInput{
   303  		Resources: []*string{aws.String(resource)},
   304  		Tags:      awsTags,
   305  	})
   306  
   307  	return err
   308  }
   309  
   310  // TerminateInstance terminates the EC2 instance with the given ID in the given region.
   311  func TerminateInstance(t testing.TestingT, region string, instanceID string) {
   312  	require.NoError(t, TerminateInstanceE(t, region, instanceID))
   313  }
   314  
   315  // TerminateInstanceE terminates the EC2 instance with the given ID in the given region.
   316  func TerminateInstanceE(t testing.TestingT, region string, instanceID string) error {
   317  	logger.Logf(t, "Terminating Instance %s", instanceID)
   318  
   319  	client, err := NewEc2ClientE(t, region)
   320  	if err != nil {
   321  		return err
   322  	}
   323  
   324  	_, err = client.TerminateInstances(&ec2.TerminateInstancesInput{
   325  		InstanceIds: []*string{
   326  			aws.String(instanceID),
   327  		},
   328  	})
   329  
   330  	return err
   331  }
   332  
   333  // GetAmiPubliclyAccessible returns whether the AMI is publicly accessible or not
   334  func GetAmiPubliclyAccessible(t testing.TestingT, awsRegion string, amiID string) bool {
   335  	output, err := GetAmiPubliclyAccessibleE(t, awsRegion, amiID)
   336  	require.NoError(t, err)
   337  	return output
   338  }
   339  
   340  // GetAmiPubliclyAccessibleE returns whether the AMI is publicly accessible or not
   341  func GetAmiPubliclyAccessibleE(t testing.TestingT, awsRegion string, amiID string) (bool, error) {
   342  	launchPermissions, err := GetLaunchPermissionsForAmiE(t, awsRegion, amiID)
   343  	if err != nil {
   344  		return false, err
   345  	}
   346  	for _, launchPermission := range launchPermissions {
   347  		if aws.StringValue(launchPermission.Group) == "all" {
   348  			return true, nil
   349  		}
   350  	}
   351  	return false, nil
   352  }
   353  
   354  // GetAccountsWithLaunchPermissionsForAmi returns list of accounts that the AMI is shared with
   355  func GetAccountsWithLaunchPermissionsForAmi(t testing.TestingT, awsRegion string, amiID string) []string {
   356  	output, err := GetAccountsWithLaunchPermissionsForAmiE(t, awsRegion, amiID)
   357  	require.NoError(t, err)
   358  	return output
   359  }
   360  
   361  // GetAccountsWithLaunchPermissionsForAmiE returns list of accounts that the AMI is shared with
   362  func GetAccountsWithLaunchPermissionsForAmiE(t testing.TestingT, awsRegion string, amiID string) ([]string, error) {
   363  	accountIDs := []string{}
   364  	launchPermissions, err := GetLaunchPermissionsForAmiE(t, awsRegion, amiID)
   365  	if err != nil {
   366  		return accountIDs, err
   367  	}
   368  	for _, launchPermission := range launchPermissions {
   369  		if aws.StringValue(launchPermission.UserId) != "" {
   370  			accountIDs = append(accountIDs, aws.StringValue(launchPermission.UserId))
   371  		}
   372  	}
   373  	return accountIDs, nil
   374  }
   375  
   376  // GetLaunchPermissionsForAmiE returns launchPermissions as configured in AWS
   377  func GetLaunchPermissionsForAmiE(t testing.TestingT, awsRegion string, amiID string) ([]*ec2.LaunchPermission, error) {
   378  	client := NewEc2Client(t, awsRegion)
   379  	input := &ec2.DescribeImageAttributeInput{
   380  		Attribute: aws.String("launchPermission"),
   381  		ImageId:   aws.String(amiID),
   382  	}
   383  
   384  	output, err := client.DescribeImageAttribute(input)
   385  	if err != nil {
   386  		return []*ec2.LaunchPermission{}, err
   387  	}
   388  	return output.LaunchPermissions, nil
   389  }
   390  
   391  // GetRecommendedInstanceType takes in a list of EC2 instance types (e.g., "t2.micro", "t3.micro") and returns the
   392  // first instance type in the list that is available in all Availability Zones (AZs) in the given region. If there's no
   393  // instance available in all AZs, this function exits with an error. This is useful because certain instance types,
   394  // such as t2.micro, are not available in some of the newer AZs, while t3.micro is not available in some of the older
   395  // AZs, and if you have code that needs to run on a "small" instance across all AZs in many different regions, you can
   396  // use this function to automatically figure out which instance type you should use.
   397  // This function will fail the test if there is an error.
   398  func GetRecommendedInstanceType(t testing.TestingT, region string, instanceTypeOptions []string) string {
   399  	out, err := GetRecommendedInstanceTypeE(t, region, instanceTypeOptions)
   400  	require.NoError(t, err)
   401  	return out
   402  }
   403  
   404  // GetRecommendedInstanceTypeE takes in a list of EC2 instance types (e.g., "t2.micro", "t3.micro") and returns the
   405  // first instance type in the list that is available in all Availability Zones (AZs) in the given region. If there's no
   406  // instance available in all AZs, this function exits with an error. This is useful because certain instance types,
   407  // such as t2.micro, are not available in some of the newer AZs, while t3.micro is not available in some of the older
   408  // AZs. If you have code that needs to run on a "small" instance across all AZs in many different regions, you can
   409  // use this function to automatically figure out which instance type you should use.
   410  func GetRecommendedInstanceTypeE(t testing.TestingT, region string, instanceTypeOptions []string) (string, error) {
   411  	client, err := NewEc2ClientE(t, region)
   412  	if err != nil {
   413  		return "", err
   414  	}
   415  	return GetRecommendedInstanceTypeWithClientE(t, client, instanceTypeOptions)
   416  }
   417  
   418  // GetRecommendedInstanceTypeWithClientE takes in a list of EC2 instance types (e.g., "t2.micro", "t3.micro") and returns the
   419  // first instance type in the list that is available in all Availability Zones (AZs) in the given region. If there's no
   420  // instance available in all AZs, this function exits with an error. This is useful because certain instance types,
   421  // such as t2.micro, are not available in some of the newer AZs, while t3.micro is not available in some of the older
   422  // AZs. If you have code that needs to run on a "small" instance across all AZs in many different regions, you can
   423  // use this function to automatically figure out which instance type you should use.
   424  // This function expects an authenticated EC2 client from the AWS SDK Go library.
   425  func GetRecommendedInstanceTypeWithClientE(t testing.TestingT, ec2Client *ec2.EC2, instanceTypeOptions []string) (string, error) {
   426  	availabilityZones, err := getAllAvailabilityZonesE(ec2Client)
   427  	if err != nil {
   428  		return "", err
   429  	}
   430  
   431  	instanceTypeOfferings, err := getInstanceTypeOfferingsE(ec2Client, instanceTypeOptions)
   432  	if err != nil {
   433  		return "", err
   434  	}
   435  
   436  	return pickRecommendedInstanceTypeE(availabilityZones, instanceTypeOfferings, instanceTypeOptions)
   437  }
   438  
   439  // pickRecommendedInstanceTypeE returns the first instance type from instanceTypeOptions that is available in all the
   440  // AZs in availabilityZones based on the availability data in instanceTypeOfferings. If none of the instance types are
   441  // available in all AZs, this function returns an error.
   442  func pickRecommendedInstanceTypeE(availabilityZones []string, instanceTypeOfferings []*ec2.InstanceTypeOffering, instanceTypeOptions []string) (string, error) {
   443  	// O(n^3) for the win!
   444  	for _, instanceType := range instanceTypeOptions {
   445  		if instanceTypeExistsInAllAzs(instanceType, availabilityZones, instanceTypeOfferings) {
   446  			return instanceType, nil
   447  		}
   448  	}
   449  
   450  	return "", NoInstanceTypeError{InstanceTypeOptions: instanceTypeOptions, Azs: availabilityZones}
   451  }
   452  
   453  // instanceTypeExistsInAllAzs returns true if the given inistance type exists in all the given availabilityZones based
   454  // on the availability data in instanceTypeOfferings
   455  func instanceTypeExistsInAllAzs(instanceType string, availabilityZones []string, instanceTypeOfferings []*ec2.InstanceTypeOffering) bool {
   456  	if len(availabilityZones) == 0 || len(instanceTypeOfferings) == 0 {
   457  		return false
   458  	}
   459  
   460  	for _, az := range availabilityZones {
   461  		if !hasOffering(instanceTypeOfferings, az, instanceType) {
   462  			return false
   463  		}
   464  	}
   465  
   466  	return true
   467  }
   468  
   469  // hasOffering returns true if the given availability zone and instance type are one of the offerings in
   470  // instanceTypeOfferings
   471  func hasOffering(instanceTypeOfferings []*ec2.InstanceTypeOffering, availabilityZone string, instanceType string) bool {
   472  	for _, offering := range instanceTypeOfferings {
   473  		if aws.StringValue(offering.InstanceType) == instanceType && aws.StringValue(offering.Location) == availabilityZone {
   474  			return true
   475  		}
   476  	}
   477  
   478  	return false
   479  }
   480  
   481  // getInstanceTypeOfferingsE returns the instance types from the given list that are available in the region configured
   482  // in the given EC2 client
   483  func getInstanceTypeOfferingsE(client *ec2.EC2, instanceTypeOptions []string) ([]*ec2.InstanceTypeOffering, error) {
   484  	input := ec2.DescribeInstanceTypeOfferingsInput{
   485  		LocationType: aws.String(ec2.LocationTypeAvailabilityZone),
   486  		Filters: []*ec2.Filter{
   487  			{
   488  				Name:   aws.String("instance-type"),
   489  				Values: aws.StringSlice(instanceTypeOptions),
   490  			},
   491  		},
   492  	}
   493  
   494  	out, err := client.DescribeInstanceTypeOfferings(&input)
   495  	if err != nil {
   496  		return nil, err
   497  	}
   498  
   499  	return out.InstanceTypeOfferings, nil
   500  }
   501  
   502  // getAllAvailabilityZonesE returns all the available AZs in the region configured in the given EC2 client
   503  func getAllAvailabilityZonesE(client *ec2.EC2) ([]string, error) {
   504  	input := ec2.DescribeAvailabilityZonesInput{
   505  		Filters: []*ec2.Filter{
   506  			{
   507  				Name:   aws.String("state"),
   508  				Values: aws.StringSlice([]string{"available"}),
   509  			},
   510  		},
   511  	}
   512  
   513  	out, err := client.DescribeAvailabilityZones(&input)
   514  	if err != nil {
   515  		return nil, err
   516  	}
   517  
   518  	var azs []string
   519  
   520  	for _, az := range out.AvailabilityZones {
   521  		azs = append(azs, aws.StringValue(az.ZoneName))
   522  	}
   523  
   524  	return azs, nil
   525  }
   526  
   527  // NewEc2Client creates an EC2 client.
   528  func NewEc2Client(t testing.TestingT, region string) *ec2.EC2 {
   529  	client, err := NewEc2ClientE(t, region)
   530  	require.NoError(t, err)
   531  	return client
   532  }
   533  
   534  // NewEc2ClientE creates an EC2 client.
   535  func NewEc2ClientE(t testing.TestingT, region string) (*ec2.EC2, error) {
   536  	sess, err := NewAuthenticatedSession(region)
   537  	if err != nil {
   538  		return nil, err
   539  	}
   540  
   541  	return ec2.New(sess), nil
   542  }