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  }