github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/amazon/ebs/builder_acc_test.go (about)

     1  package ebs
     2  
     3  import (
     4  	"fmt"
     5  	"os"
     6  	"testing"
     7  
     8  	"github.com/aws/aws-sdk-go/aws"
     9  	"github.com/aws/aws-sdk-go/service/ec2"
    10  	"github.com/hashicorp/packer/builder/amazon/common"
    11  	builderT "github.com/hashicorp/packer/helper/builder/testing"
    12  	"github.com/hashicorp/packer/packer"
    13  )
    14  
    15  func TestBuilderAcc_basic(t *testing.T) {
    16  	builderT.Test(t, builderT.TestCase{
    17  		PreCheck: func() { testAccPreCheck(t) },
    18  		Builder:  &Builder{},
    19  		Template: testBuilderAccBasic,
    20  	})
    21  }
    22  
    23  func TestBuilderAcc_regionCopy(t *testing.T) {
    24  	builderT.Test(t, builderT.TestCase{
    25  		PreCheck: func() { testAccPreCheck(t) },
    26  		Builder:  &Builder{},
    27  		Template: testBuilderAccRegionCopy,
    28  		Check:    checkRegionCopy([]string{"us-east-1", "us-west-2"}),
    29  	})
    30  }
    31  
    32  func TestBuilderAcc_forceDeregister(t *testing.T) {
    33  	// Build the same AMI name twice, with force_deregister on the second run
    34  	builderT.Test(t, builderT.TestCase{
    35  		PreCheck:             func() { testAccPreCheck(t) },
    36  		Builder:              &Builder{},
    37  		Template:             buildForceDeregisterConfig("false", "dereg"),
    38  		SkipArtifactTeardown: true,
    39  	})
    40  
    41  	builderT.Test(t, builderT.TestCase{
    42  		PreCheck: func() { testAccPreCheck(t) },
    43  		Builder:  &Builder{},
    44  		Template: buildForceDeregisterConfig("true", "dereg"),
    45  	})
    46  }
    47  
    48  func TestBuilderAcc_forceDeleteSnapshot(t *testing.T) {
    49  	amiName := "packer-test-dereg"
    50  
    51  	// Build the same AMI name twice, with force_delete_snapshot on the second run
    52  	builderT.Test(t, builderT.TestCase{
    53  		PreCheck:             func() { testAccPreCheck(t) },
    54  		Builder:              &Builder{},
    55  		Template:             buildForceDeleteSnapshotConfig("false", amiName),
    56  		SkipArtifactTeardown: true,
    57  	})
    58  
    59  	// Get image data by AMI name
    60  	ec2conn, _ := testEC2Conn()
    61  	imageResp, _ := ec2conn.DescribeImages(
    62  		&ec2.DescribeImagesInput{Filters: []*ec2.Filter{
    63  			{
    64  				Name:   aws.String("name"),
    65  				Values: []*string{aws.String(amiName)},
    66  			},
    67  		}},
    68  	)
    69  	image := imageResp.Images[0]
    70  
    71  	// Get snapshot ids for image
    72  	snapshotIds := []*string{}
    73  	for _, device := range image.BlockDeviceMappings {
    74  		if device.Ebs != nil && device.Ebs.SnapshotId != nil {
    75  			snapshotIds = append(snapshotIds, device.Ebs.SnapshotId)
    76  		}
    77  	}
    78  
    79  	builderT.Test(t, builderT.TestCase{
    80  		PreCheck: func() { testAccPreCheck(t) },
    81  		Builder:  &Builder{},
    82  		Template: buildForceDeleteSnapshotConfig("true", amiName),
    83  		Check:    checkSnapshotsDeleted(snapshotIds),
    84  	})
    85  }
    86  
    87  func checkSnapshotsDeleted(snapshotIds []*string) builderT.TestCheckFunc {
    88  	return func(artifacts []packer.Artifact) error {
    89  		// Verify the snapshots are gone
    90  		ec2conn, _ := testEC2Conn()
    91  		snapshotResp, _ := ec2conn.DescribeSnapshots(
    92  			&ec2.DescribeSnapshotsInput{SnapshotIds: snapshotIds},
    93  		)
    94  
    95  		if len(snapshotResp.Snapshots) > 0 {
    96  			return fmt.Errorf("Snapshots weren't successfully deleted by `force_delete_snapshot`")
    97  		}
    98  		return nil
    99  	}
   100  }
   101  
   102  func TestBuilderAcc_amiSharing(t *testing.T) {
   103  	builderT.Test(t, builderT.TestCase{
   104  		PreCheck: func() { testAccPreCheck(t) },
   105  		Builder:  &Builder{},
   106  		Template: testBuilderAccSharing,
   107  		Check:    checkAMISharing(2, "932021504756", "all"),
   108  	})
   109  }
   110  
   111  func TestBuilderAcc_encryptedBoot(t *testing.T) {
   112  	builderT.Test(t, builderT.TestCase{
   113  		PreCheck: func() { testAccPreCheck(t) },
   114  		Builder:  &Builder{},
   115  		Template: testBuilderAccEncrypted,
   116  		Check:    checkBootEncrypted(),
   117  	})
   118  }
   119  
   120  func checkAMISharing(count int, uid, group string) builderT.TestCheckFunc {
   121  	return func(artifacts []packer.Artifact) error {
   122  		if len(artifacts) > 1 {
   123  			return fmt.Errorf("more than 1 artifact")
   124  		}
   125  
   126  		// Get the actual *Artifact pointer so we can access the AMIs directly
   127  		artifactRaw := artifacts[0]
   128  		artifact, ok := artifactRaw.(*common.Artifact)
   129  		if !ok {
   130  			return fmt.Errorf("unknown artifact: %#v", artifactRaw)
   131  		}
   132  
   133  		// describe the image, get block devices with a snapshot
   134  		ec2conn, _ := testEC2Conn()
   135  		imageResp, err := ec2conn.DescribeImageAttribute(&ec2.DescribeImageAttributeInput{
   136  			Attribute: aws.String("launchPermission"),
   137  			ImageId:   aws.String(artifact.Amis["us-east-1"]),
   138  		})
   139  
   140  		if err != nil {
   141  			return fmt.Errorf("Error retrieving Image Attributes for AMI Artifact (%#v) in AMI Sharing Test: %s", artifact, err)
   142  		}
   143  
   144  		// Launch Permissions are in addition to the userid that created it, so if
   145  		// you add 3 additional ami_users, you expect 2 Launch Permissions here
   146  		if len(imageResp.LaunchPermissions) != count {
   147  			return fmt.Errorf("Error in Image Attributes, expected (%d) Launch Permissions, got (%d)", count, len(imageResp.LaunchPermissions))
   148  		}
   149  
   150  		userFound := false
   151  		for _, lp := range imageResp.LaunchPermissions {
   152  			if lp.UserId != nil && uid == *lp.UserId {
   153  				userFound = true
   154  			}
   155  		}
   156  
   157  		if !userFound {
   158  			return fmt.Errorf("Error in Image Attributes, expected User ID (%s) to have Launch Permissions, but was not found", uid)
   159  		}
   160  
   161  		groupFound := false
   162  		for _, lp := range imageResp.LaunchPermissions {
   163  			if lp.Group != nil && group == *lp.Group {
   164  				groupFound = true
   165  			}
   166  		}
   167  
   168  		if !groupFound {
   169  			return fmt.Errorf("Error in Image Attributes, expected Group ID (%s) to have Launch Permissions, but was not found", group)
   170  		}
   171  
   172  		return nil
   173  	}
   174  }
   175  
   176  func checkRegionCopy(regions []string) builderT.TestCheckFunc {
   177  	return func(artifacts []packer.Artifact) error {
   178  		if len(artifacts) > 1 {
   179  			return fmt.Errorf("more than 1 artifact")
   180  		}
   181  
   182  		// Get the actual *Artifact pointer so we can access the AMIs directly
   183  		artifactRaw := artifacts[0]
   184  		artifact, ok := artifactRaw.(*common.Artifact)
   185  		if !ok {
   186  			return fmt.Errorf("unknown artifact: %#v", artifactRaw)
   187  		}
   188  
   189  		// Verify that we copied to only the regions given
   190  		regionSet := make(map[string]struct{})
   191  		for _, r := range regions {
   192  			regionSet[r] = struct{}{}
   193  		}
   194  		for r := range artifact.Amis {
   195  			if _, ok := regionSet[r]; !ok {
   196  				return fmt.Errorf("unknown region: %s", r)
   197  			}
   198  
   199  			delete(regionSet, r)
   200  		}
   201  		if len(regionSet) > 0 {
   202  			return fmt.Errorf("didn't copy to: %#v", regionSet)
   203  		}
   204  
   205  		return nil
   206  	}
   207  }
   208  
   209  func checkBootEncrypted() builderT.TestCheckFunc {
   210  	return func(artifacts []packer.Artifact) error {
   211  
   212  		// Get the actual *Artifact pointer so we can access the AMIs directly
   213  		artifactRaw := artifacts[0]
   214  		artifact, ok := artifactRaw.(*common.Artifact)
   215  		if !ok {
   216  			return fmt.Errorf("unknown artifact: %#v", artifactRaw)
   217  		}
   218  
   219  		// describe the image, get block devices with a snapshot
   220  		ec2conn, _ := testEC2Conn()
   221  		imageResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{
   222  			ImageIds: []*string{aws.String(artifact.Amis["us-east-1"])},
   223  		})
   224  
   225  		if err != nil {
   226  			return fmt.Errorf("Error retrieving Image Attributes for AMI (%s) in AMI Encrypted Boot Test: %s", artifact, err)
   227  		}
   228  
   229  		image := imageResp.Images[0] // Only requested a single AMI ID
   230  
   231  		rootDeviceName := image.RootDeviceName
   232  
   233  		for _, bd := range image.BlockDeviceMappings {
   234  			if *bd.DeviceName == *rootDeviceName {
   235  				if *bd.Ebs.Encrypted != true {
   236  					return fmt.Errorf("volume not encrypted: %s", *bd.Ebs.SnapshotId)
   237  				}
   238  			}
   239  		}
   240  
   241  		return nil
   242  	}
   243  }
   244  
   245  func testAccPreCheck(t *testing.T) {
   246  	if v := os.Getenv("AWS_ACCESS_KEY_ID"); v == "" {
   247  		t.Fatal("AWS_ACCESS_KEY_ID must be set for acceptance tests")
   248  	}
   249  
   250  	if v := os.Getenv("AWS_SECRET_ACCESS_KEY"); v == "" {
   251  		t.Fatal("AWS_SECRET_ACCESS_KEY must be set for acceptance tests")
   252  	}
   253  }
   254  
   255  func testEC2Conn() (*ec2.EC2, error) {
   256  	access := &common.AccessConfig{RawRegion: "us-east-1"}
   257  	session, err := access.Session()
   258  	if err != nil {
   259  		return nil, err
   260  	}
   261  
   262  	return ec2.New(session), nil
   263  }
   264  
   265  const testBuilderAccBasic = `
   266  {
   267  	"builders": [{
   268  		"type": "test",
   269  		"region": "us-east-1",
   270  		"instance_type": "m3.medium",
   271  		"source_ami": "ami-76b2a71e",
   272  		"ssh_username": "ubuntu",
   273  		"ami_name": "packer-test {{timestamp}}"
   274  	}]
   275  }
   276  `
   277  
   278  const testBuilderAccRegionCopy = `
   279  {
   280  	"builders": [{
   281  		"type": "test",
   282  		"region": "us-east-1",
   283  		"instance_type": "m3.medium",
   284  		"source_ami": "ami-76b2a71e",
   285  		"ssh_username": "ubuntu",
   286  		"ami_name": "packer-test {{timestamp}}",
   287  		"ami_regions": ["us-east-1", "us-west-2"]
   288  	}]
   289  }
   290  `
   291  
   292  const testBuilderAccForceDeregister = `
   293  {
   294  	"builders": [{
   295  		"type": "test",
   296  		"region": "us-east-1",
   297  		"instance_type": "m3.medium",
   298  		"source_ami": "ami-76b2a71e",
   299  		"ssh_username": "ubuntu",
   300  		"force_deregister": "%s",
   301  		"ami_name": "packer-test-%s"
   302  	}]
   303  }
   304  `
   305  
   306  const testBuilderAccForceDeleteSnapshot = `
   307  {
   308  	"builders": [{
   309  		"type": "test",
   310  		"region": "us-east-1",
   311  		"instance_type": "m3.medium",
   312  		"source_ami": "ami-76b2a71e",
   313  		"ssh_username": "ubuntu",
   314  		"force_deregister": "%s",
   315  		"force_delete_snapshot": "%s",
   316  		"ami_name": "packer-test-%s"
   317  	}]
   318  }
   319  `
   320  
   321  // share with catsby
   322  const testBuilderAccSharing = `
   323  {
   324  	"builders": [{
   325  		"type": "test",
   326  		"region": "us-east-1",
   327  		"instance_type": "m3.medium",
   328  		"source_ami": "ami-76b2a71e",
   329  		"ssh_username": "ubuntu",
   330  		"ami_name": "packer-test {{timestamp}}",
   331  		"ami_users":["932021504756"],
   332  		"ami_groups":["all"]
   333  	}]
   334  }
   335  `
   336  
   337  const testBuilderAccEncrypted = `
   338  {
   339  	"builders": [{
   340  		"type": "test",
   341  		"region": "us-east-1",
   342  		"instance_type": "m3.medium",
   343  		"source_ami":"ami-c15bebaa",
   344  		"ssh_username": "ubuntu",
   345  		"ami_name": "packer-enc-test {{timestamp}}",
   346  		"encrypt_boot": true
   347  	}]
   348  }
   349  `
   350  
   351  func buildForceDeregisterConfig(val, name string) string {
   352  	return fmt.Sprintf(testBuilderAccForceDeregister, val, name)
   353  }
   354  
   355  func buildForceDeleteSnapshotConfig(val, name string) string {
   356  	return fmt.Sprintf(testBuilderAccForceDeleteSnapshot, val, val, name)
   357  }