github.com/mmcquillan/packer@v1.1.1-0.20171009221028-c85cf0483a5d/builder/amazon/common/artifact.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "log" 6 "sort" 7 "strings" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/aws/session" 11 "github.com/aws/aws-sdk-go/service/ec2" 12 "github.com/hashicorp/packer/packer" 13 ) 14 15 // Artifact is an artifact implementation that contains built AMIs. 16 type Artifact struct { 17 // A map of regions to AMI IDs. 18 Amis map[string]string 19 20 // BuilderId is the unique ID for the builder that created this AMI 21 BuilderIdValue string 22 23 // EC2 connection for performing API stuff. 24 Conn *ec2.EC2 25 } 26 27 func (a *Artifact) BuilderId() string { 28 return a.BuilderIdValue 29 } 30 31 func (*Artifact) Files() []string { 32 // We have no files 33 return nil 34 } 35 36 func (a *Artifact) Id() string { 37 parts := make([]string, 0, len(a.Amis)) 38 for region, amiId := range a.Amis { 39 parts = append(parts, fmt.Sprintf("%s:%s", region, amiId)) 40 } 41 42 sort.Strings(parts) 43 return strings.Join(parts, ",") 44 } 45 46 func (a *Artifact) String() string { 47 amiStrings := make([]string, 0, len(a.Amis)) 48 for region, id := range a.Amis { 49 single := fmt.Sprintf("%s: %s", region, id) 50 amiStrings = append(amiStrings, single) 51 } 52 53 sort.Strings(amiStrings) 54 return fmt.Sprintf("AMIs were created:\n%s\n", strings.Join(amiStrings, "\n")) 55 } 56 57 func (a *Artifact) State(name string) interface{} { 58 switch name { 59 case "atlas.artifact.metadata": 60 return a.stateAtlasMetadata() 61 default: 62 return nil 63 } 64 } 65 66 func (a *Artifact) Destroy() error { 67 errors := make([]error, 0) 68 69 for region, imageId := range a.Amis { 70 log.Printf("Deregistering image ID (%s) from region (%s)", imageId, region) 71 72 regionConfig := &aws.Config{ 73 Credentials: a.Conn.Config.Credentials, 74 Region: aws.String(region), 75 } 76 session, err := session.NewSession(regionConfig) 77 if err != nil { 78 return err 79 } 80 regionConn := ec2.New(session) 81 82 // Get image metadata 83 imageResp, err := regionConn.DescribeImages(&ec2.DescribeImagesInput{ 84 ImageIds: []*string{&imageId}, 85 }) 86 if err != nil { 87 errors = append(errors, err) 88 } 89 if len(imageResp.Images) == 0 { 90 err := fmt.Errorf("Error retrieving details for AMI (%s), no images found", imageId) 91 errors = append(errors, err) 92 } 93 94 // Deregister ami 95 input := &ec2.DeregisterImageInput{ 96 ImageId: &imageId, 97 } 98 if _, err := regionConn.DeregisterImage(input); err != nil { 99 errors = append(errors, err) 100 } 101 102 // TODO(mitchellh): Delete the snapshots associated with an AMI too 103 } 104 105 if len(errors) > 0 { 106 if len(errors) == 1 { 107 return errors[0] 108 } else { 109 return &packer.MultiError{Errors: errors} 110 } 111 } 112 113 return nil 114 } 115 116 func (a *Artifact) stateAtlasMetadata() interface{} { 117 metadata := make(map[string]string) 118 for region, imageId := range a.Amis { 119 k := fmt.Sprintf("region.%s", region) 120 metadata[k] = imageId 121 } 122 123 return metadata 124 }