github.com/amanya/packer@v0.12.1-0.20161117214323-902ac5ab2eb6/builder/amazon/ebs/step_encrypted_ami.go (about) 1 package ebs 2 3 import ( 4 "fmt" 5 6 "github.com/aws/aws-sdk-go/aws" 7 "github.com/aws/aws-sdk-go/service/ec2" 8 "github.com/mitchellh/multistep" 9 awscommon "github.com/mitchellh/packer/builder/amazon/common" 10 "github.com/mitchellh/packer/packer" 11 ) 12 13 type stepCreateEncryptedAMICopy struct { 14 image *ec2.Image 15 } 16 17 func (s *stepCreateEncryptedAMICopy) Run(state multistep.StateBag) multistep.StepAction { 18 config := state.Get("config").(Config) 19 ec2conn := state.Get("ec2").(*ec2.EC2) 20 ui := state.Get("ui").(packer.Ui) 21 22 // Encrypt boot not set, so skip step 23 if !config.AMIConfig.AMIEncryptBootVolume { 24 return multistep.ActionContinue 25 } 26 27 ui.Say("Creating Encrypted AMI Copy") 28 29 amis := state.Get("amis").(map[string]string) 30 var region, id string 31 if amis != nil { 32 for region, id = range amis { 33 break // Only get the first 34 } 35 } 36 37 ui.Say(fmt.Sprintf("Copying AMI: %s(%s)", region, id)) 38 39 copyOpts := &ec2.CopyImageInput{ 40 Name: &config.AMIName, // Try to overwrite existing AMI 41 SourceImageId: aws.String(id), 42 SourceRegion: aws.String(region), 43 Encrypted: aws.Bool(true), 44 } 45 46 copyResp, err := ec2conn.CopyImage(copyOpts) 47 if err != nil { 48 err := fmt.Errorf("Error copying AMI: %s", err) 49 state.Put("error", err) 50 ui.Error(err.Error()) 51 return multistep.ActionHalt 52 } 53 54 // Wait for the copy to become ready 55 stateChange := awscommon.StateChangeConf{ 56 Pending: []string{"pending"}, 57 Target: "available", 58 Refresh: awscommon.AMIStateRefreshFunc(ec2conn, *copyResp.ImageId), 59 StepState: state, 60 } 61 62 ui.Say("Waiting for AMI copy to become ready...") 63 if _, err := awscommon.WaitForState(&stateChange); err != nil { 64 err := fmt.Errorf("Error waiting for AMI Copy: %s", err) 65 state.Put("error", err) 66 ui.Error(err.Error()) 67 return multistep.ActionHalt 68 } 69 70 // Get the unencrypted AMI image 71 unencImagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{aws.String(id)}}) 72 if err != nil { 73 err := fmt.Errorf("Error searching for AMI: %s", err) 74 state.Put("error", err) 75 ui.Error(err.Error()) 76 return multistep.ActionHalt 77 } 78 unencImage := unencImagesResp.Images[0] 79 80 // Remove unencrypted AMI 81 ui.Say("Deregistering unencrypted AMI") 82 deregisterOpts := &ec2.DeregisterImageInput{ImageId: aws.String(id)} 83 if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil { 84 ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err)) 85 return multistep.ActionHalt 86 } 87 88 // Remove associated unencrypted snapshot(s) 89 ui.Say("Deleting unencrypted snapshots") 90 91 for _, blockDevice := range unencImage.BlockDeviceMappings { 92 if blockDevice.Ebs != nil { 93 if blockDevice.Ebs.SnapshotId != nil { 94 ui.Message(fmt.Sprintf("Snapshot ID: %s", *blockDevice.Ebs.SnapshotId)) 95 deleteSnapOpts := &ec2.DeleteSnapshotInput{ 96 SnapshotId: aws.String(*blockDevice.Ebs.SnapshotId), 97 } 98 if _, err := ec2conn.DeleteSnapshot(deleteSnapOpts); err != nil { 99 ui.Error(fmt.Sprintf("Error deleting snapshot, may still be around: %s", err)) 100 return multistep.ActionHalt 101 } 102 } 103 } 104 } 105 106 // Replace original AMI ID with Encrypted ID in state 107 amis[region] = *copyResp.ImageId 108 state.Put("amis", amis) 109 110 imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{copyResp.ImageId}}) 111 if err != nil { 112 err := fmt.Errorf("Error searching for AMI: %s", err) 113 state.Put("error", err) 114 ui.Error(err.Error()) 115 return multistep.ActionHalt 116 } 117 s.image = imagesResp.Images[0] 118 119 return multistep.ActionContinue 120 } 121 122 func (s *stepCreateEncryptedAMICopy) Cleanup(state multistep.StateBag) { 123 if s.image == nil { 124 return 125 } 126 127 _, cancelled := state.GetOk(multistep.StateCancelled) 128 _, halted := state.GetOk(multistep.StateHalted) 129 if !cancelled && !halted { 130 return 131 } 132 133 ec2conn := state.Get("ec2").(*ec2.EC2) 134 ui := state.Get("ui").(packer.Ui) 135 136 ui.Say("Deregistering the AMI because cancelation or error...") 137 deregisterOpts := &ec2.DeregisterImageInput{ImageId: s.image.ImageId} 138 if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil { 139 ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err)) 140 return 141 } 142 }