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