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 }