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 }