github.com/darmach/terratest@v0.34.8-0.20210517103231-80931f95e3ff/test/packer_basic_example_test.go (about) 1 package test 2 3 import ( 4 "fmt" 5 "io/ioutil" 6 "os" 7 "testing" 8 "time" 9 10 "github.com/aws/aws-sdk-go/aws" 11 "github.com/aws/aws-sdk-go/service/ec2" 12 terratest_aws "github.com/gruntwork-io/terratest/modules/aws" 13 "github.com/gruntwork-io/terratest/modules/packer" 14 "github.com/gruntwork-io/terratest/modules/random" 15 "github.com/stretchr/testify/assert" 16 "github.com/stretchr/testify/require" 17 ) 18 19 // Occasionally, a Packer build may fail due to intermittent issues (e.g., brief network outage or EC2 issue). We try 20 // to make our tests resilient to that by specifying those known common errors here and telling our builds to retry if 21 // they hit those errors. 22 var DefaultRetryablePackerErrors = map[string]string{ 23 "Script disconnected unexpectedly": "Occasionally, Packer seems to lose connectivity to AWS, perhaps due to a brief network outage", 24 "can not open /var/lib/apt/lists/archive.ubuntu.com_ubuntu_dists_xenial_InRelease": "Occasionally, apt-get fails on ubuntu to update the cache", 25 } 26 var DefaultTimeBetweenPackerRetries = 15 * time.Second 27 28 const DefaultMaxPackerRetries = 3 29 30 // An example of how to test the Packer template in examples/packer-basic-example using Terratest. 31 func TestPackerBasicExample(t *testing.T) { 32 t.Parallel() 33 34 // Pick a random AWS region to test in. This helps ensure your code works in all regions. 35 awsRegion := terratest_aws.GetRandomStableRegion(t, nil, nil) 36 37 // Some AWS regions are missing certain instance types, so pick an available type based on the region we picked 38 instanceType := terratest_aws.GetRecommendedInstanceType(t, awsRegion, []string{"t2.micro", "t3.micro"}) 39 40 // website::tag::1::Read Packer's template and set AWS Region variable. 41 packerOptions := &packer.Options{ 42 // The path to where the Packer template is located 43 Template: "../examples/packer-basic-example/build.json", 44 45 // Variables to pass to our Packer build using -var options 46 Vars: map[string]string{ 47 "aws_region": awsRegion, 48 "ami_base_name": fmt.Sprintf("%s", random.UniqueId()), 49 "instance_type": instanceType, 50 }, 51 52 // Only build the AWS AMI 53 Only: "amazon-ebs", 54 55 // Configure retries for intermittent errors 56 RetryableErrors: DefaultRetryablePackerErrors, 57 TimeBetweenRetries: DefaultTimeBetweenPackerRetries, 58 MaxRetries: DefaultMaxPackerRetries, 59 } 60 61 // website::tag::2::Build artifacts from Packer's template. 62 // Make sure the Packer build completes successfully 63 amiID := packer.BuildArtifact(t, packerOptions) 64 65 // website::tag::4::Remove AMI after test. 66 // Clean up the AMI after we're done 67 defer terratest_aws.DeleteAmiAndAllSnapshots(t, awsRegion, amiID) 68 69 // Check if AMI is shared/not shared with account 70 requestingAccount := terratest_aws.CanonicalAccountId 71 randomAccount := "123456789012" // Random Account 72 ec2Client := terratest_aws.NewEc2Client(t, awsRegion) 73 ShareAmi(t, amiID, requestingAccount, ec2Client) 74 accountsWithLaunchPermissions := terratest_aws.GetAccountsWithLaunchPermissionsForAmi(t, awsRegion, amiID) 75 assert.NotContains(t, accountsWithLaunchPermissions, randomAccount) 76 assert.Contains(t, accountsWithLaunchPermissions, requestingAccount) 77 78 // website::tag::3::Check AMI's properties. 79 // Check if AMI is public 80 MakeAmiPublic(t, amiID, ec2Client) 81 amiIsPublic := terratest_aws.GetAmiPubliclyAccessible(t, awsRegion, amiID) 82 assert.True(t, amiIsPublic) 83 } 84 85 // An example of how to test the Packer template in examples/packer-basic-example using Terratest 86 // with the VarFiles option. This test generates a temporary *.json file containing the value 87 // for the `aws_region` variable. 88 func TestPackerBasicExampleWithVarFile(t *testing.T) { 89 t.Parallel() 90 91 // Pick a random AWS region to test in. This helps ensure your code works in all regions. 92 awsRegion := terratest_aws.GetRandomStableRegion(t, nil, nil) 93 94 // Some AWS regions are missing certain instance types, so pick an available type based on the region we picked 95 instanceType := terratest_aws.GetRecommendedInstanceType(t, awsRegion, []string{"t2.micro", "t3.micro"}) 96 97 // Create temporary packer variable file to store aws region 98 varFile, err := ioutil.TempFile("", "*.json") 99 require.NoError(t, err, "Did not expect temp file creation to cause error") 100 101 // Be sure to clean up temp file 102 defer os.Remove(varFile.Name()) 103 104 // Write the vars we need to a temporary json file 105 varFileContent := []byte(fmt.Sprintf(`{"aws_region": "%s", "instance_type": "%s"}`, awsRegion, instanceType)) 106 _, err = varFile.Write(varFileContent) 107 require.NoError(t, err, "Did not expect writing to temp file %s to cause error", varFile.Name()) 108 109 packerOptions := &packer.Options{ 110 // The path to where the Packer template is located 111 Template: "../examples/packer-basic-example/build.json", 112 113 // Variable file to to pass to our Packer build using -var-file option 114 VarFiles: []string{ 115 varFile.Name(), 116 }, 117 118 // Only build the AWS AMI 119 Only: "amazon-ebs", 120 121 // Configure retries for intermittent errors 122 RetryableErrors: DefaultRetryablePackerErrors, 123 TimeBetweenRetries: DefaultTimeBetweenPackerRetries, 124 MaxRetries: DefaultMaxPackerRetries, 125 } 126 127 // Make sure the Packer build completes successfully 128 amiID := packer.BuildArtifact(t, packerOptions) 129 130 // Clean up the AMI after we're done 131 defer terratest_aws.DeleteAmiAndAllSnapshots(t, awsRegion, amiID) 132 133 // Check if AMI is shared/not shared with account 134 requestingAccount := terratest_aws.CanonicalAccountId 135 randomAccount := "123456789012" // Random Account 136 ec2Client := terratest_aws.NewEc2Client(t, awsRegion) 137 ShareAmi(t, amiID, requestingAccount, ec2Client) 138 accountsWithLaunchPermissions := terratest_aws.GetAccountsWithLaunchPermissionsForAmi(t, awsRegion, amiID) 139 assert.NotContains(t, accountsWithLaunchPermissions, randomAccount) 140 assert.Contains(t, accountsWithLaunchPermissions, requestingAccount) 141 142 // Check if AMI is public 143 MakeAmiPublic(t, amiID, ec2Client) 144 amiIsPublic := terratest_aws.GetAmiPubliclyAccessible(t, awsRegion, amiID) 145 assert.True(t, amiIsPublic) 146 } 147 148 func TestPackerMultipleConcurrentAmis(t *testing.T) { 149 t.Parallel() 150 151 // Build a map of 3 randomId <-> packer.Options, in 3 random AWS Regions 152 // then build all of these AMIs in parallel and make sure that there are 153 // no errors. 154 var identifierToOptions = map[string]*packer.Options{} 155 for i := 0; i < 3; i++ { 156 // Pick a random AWS region to test in. This helps ensure your code works in all regions. 157 awsRegion := terratest_aws.GetRandomStableRegion(t, nil, nil) 158 159 // Some AWS regions are missing certain instance types, so pick an available type based on the region we picked 160 instanceType := terratest_aws.GetRecommendedInstanceType(t, awsRegion, []string{"t2.micro", "t3.micro"}) 161 162 packerOptions := &packer.Options{ 163 // The path to where the Packer template is located 164 Template: "../examples/packer-basic-example/build.json", 165 166 // Variables to pass to our Packer build using -var options 167 Vars: map[string]string{ 168 "aws_region": awsRegion, 169 "ami_base_name": fmt.Sprintf("%s", random.UniqueId()), 170 "instance_type": instanceType, 171 }, 172 173 // Only build the AWS AMI 174 Only: "amazon-ebs", 175 176 // Configure retries for intermittent errors 177 RetryableErrors: DefaultRetryablePackerErrors, 178 TimeBetweenRetries: DefaultTimeBetweenPackerRetries, 179 MaxRetries: DefaultMaxPackerRetries, 180 } 181 182 identifierToOptions[random.UniqueId()] = packerOptions 183 } 184 185 resultMap := packer.BuildArtifacts(t, identifierToOptions) 186 187 // Clean up the AMIs after we're done 188 for key, amiId := range resultMap { 189 awsRegion := identifierToOptions[key].Vars["aws_region"] 190 terratest_aws.DeleteAmiAndAllSnapshots(t, awsRegion, amiId) 191 } 192 } 193 194 func ShareAmi(t *testing.T, amiID string, accountID string, ec2Client *ec2.EC2) { 195 input := &ec2.ModifyImageAttributeInput{ 196 ImageId: aws.String(amiID), 197 LaunchPermission: &ec2.LaunchPermissionModifications{ 198 Add: []*ec2.LaunchPermission{ 199 { 200 UserId: aws.String(accountID), 201 }, 202 }, 203 }, 204 } 205 _, err := ec2Client.ModifyImageAttribute(input) 206 if err != nil { 207 t.Fatal(err) 208 } 209 } 210 211 func MakeAmiPublic(t *testing.T, amiID string, ec2Client *ec2.EC2) { 212 input := &ec2.ModifyImageAttributeInput{ 213 ImageId: aws.String(amiID), 214 LaunchPermission: &ec2.LaunchPermissionModifications{ 215 Add: []*ec2.LaunchPermission{ 216 { 217 Group: aws.String("all"), 218 }, 219 }, 220 }, 221 } 222 _, err := ec2Client.ModifyImageAttribute(input) 223 if err != nil { 224 t.Fatal(err) 225 } 226 }