amazon - Snapshot permissions correctly applied

Fixes #3344
This commit is contained in:
Ari Aviran 2016-09-11 15:37:24 +03:00 committed by Rickard von Essen
parent d91b65b0e2
commit 46f217f255
4 changed files with 94 additions and 18 deletions

View File

@ -23,6 +23,7 @@ func (s *StepAMIRegionCopy) Run(state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)
amis := state.Get("amis").(map[string]string)
snapshots := state.Get("snapshots").(map[string][]string)
ami := amis[*ec2conn.Config.Region]
if len(s.Regions) == 0 {
@ -46,11 +47,12 @@ func (s *StepAMIRegionCopy) Run(state multistep.StateBag) multistep.StepAction {
go func(region string) {
defer wg.Done()
id, err := amiRegionCopy(state, s.AccessConfig, s.Name, ami, region, *ec2conn.Config.Region)
id, snapshotIds, err := amiRegionCopy(state, s.AccessConfig, s.Name, ami, region, *ec2conn.Config.Region)
lock.Lock()
defer lock.Unlock()
amis[region] = id
snapshots[region] = snapshotIds
if err != nil {
errs = packer.MultiErrorAppend(errs, err)
}
@ -77,20 +79,21 @@ func (s *StepAMIRegionCopy) Cleanup(state multistep.StateBag) {
}
// amiRegionCopy does a copy for the given AMI to the target region and
// returns the resulting ID or error.
// returns the resulting ID and snapshot IDs, or error.
func amiRegionCopy(state multistep.StateBag, config *AccessConfig, name string, imageId string,
target string, source string) (string, error) {
target string, source string) (string, []string, error) {
snapshotIds := []string{}
// Connect to the region where the AMI will be copied to
awsConfig, err := config.Config()
if err != nil {
return "", err
return "", snapshotIds, err
}
awsConfig.Region = aws.String(target)
session, err := session.NewSession(awsConfig)
if err != nil {
return "", err
return "", snapshotIds, err
}
regionconn := ec2.New(session)
@ -101,7 +104,7 @@ func amiRegionCopy(state multistep.StateBag, config *AccessConfig, name string,
})
if err != nil {
return "", fmt.Errorf("Error Copying AMI (%s) to region (%s): %s",
return "", snapshotIds, fmt.Errorf("Error Copying AMI (%s) to region (%s): %s",
imageId, target, err)
}
@ -113,9 +116,22 @@ func amiRegionCopy(state multistep.StateBag, config *AccessConfig, name string,
}
if _, err := WaitForState(&stateChange); err != nil {
return "", fmt.Errorf("Error waiting for AMI (%s) in region (%s): %s",
return "", snapshotIds, fmt.Errorf("Error waiting for AMI (%s) in region (%s): %s",
*resp.ImageId, target, err)
}
return *resp.ImageId, nil
// Getting snapshot IDs out of the copied AMI
describeImageResp, err := regionconn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{resp.ImageId}})
if err != nil {
return "", snapshotIds, fmt.Errorf("Error describing copied AMI (%s) in region (%s): %s",
imageId, target, err)
}
for _, blockDeviceMapping := range describeImageResp.Images[0].BlockDeviceMappings {
if blockDeviceMapping.Ebs != nil {
snapshotIds = append(snapshotIds, *blockDeviceMapping.Ebs.SnapshotId)
}
}
return *resp.ImageId, snapshotIds, nil
}

View File

@ -21,6 +21,7 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
ec2conn := state.Get("ec2").(*ec2.EC2)
ui := state.Get("ui").(packer.Ui)
amis := state.Get("amis").(map[string]string)
snapshots := state.Get("snapshots").(map[string][]string)
// Determine if there is any work to do.
valid := false
@ -33,46 +34,71 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
return multistep.ActionContinue
}
// Construct the modify image attribute requests we're going to make.
// We need to make each separately since the EC2 API only allows changing
// one type at a kind currently.
// Construct the modify image and snapshot attribute requests we're going
// to make. We need to make each separately since the EC2 API only allows
// changing one type at a kind currently.
options := make(map[string]*ec2.ModifyImageAttributeInput)
if s.Description != "" {
options["description"] = &ec2.ModifyImageAttributeInput{
Description: &ec2.AttributeValue{Value: &s.Description},
}
}
snapshotOptions := make(map[string]*ec2.ModifySnapshotAttributeInput)
if len(s.Groups) > 0 {
groups := make([]*string, len(s.Groups))
adds := make([]*ec2.LaunchPermission, len(s.Groups))
addsImage := make([]*ec2.LaunchPermission, len(s.Groups))
addGroups := &ec2.ModifyImageAttributeInput{
LaunchPermission: &ec2.LaunchPermissionModifications{},
}
addsSnapshot := make([]*ec2.CreateVolumePermission, len(s.Groups))
addSnapshotGroups := &ec2.ModifySnapshotAttributeInput{
CreateVolumePermission: &ec2.CreateVolumePermissionModifications{},
}
for i, g := range s.Groups {
groups[i] = aws.String(g)
adds[i] = &ec2.LaunchPermission{
addsImage[i] = &ec2.LaunchPermission{
Group: aws.String(g),
}
addsSnapshot[i] = &ec2.CreateVolumePermission{
Group: aws.String(g),
}
}
addGroups.UserGroups = groups
addGroups.LaunchPermission.Add = adds
addGroups.UserGroups = groups
addGroups.LaunchPermission.Add = addsImage
options["groups"] = addGroups
addSnapshotGroups.GroupNames = groups
addSnapshotGroups.CreateVolumePermission.Add = addsSnapshot
snapshotOptions["groups"] = addSnapshotGroups
}
if len(s.Users) > 0 {
users := make([]*string, len(s.Users))
adds := make([]*ec2.LaunchPermission, len(s.Users))
addsImage := make([]*ec2.LaunchPermission, len(s.Users))
addsSnapshot := make([]*ec2.CreateVolumePermission, len(s.Users))
for i, u := range s.Users {
users[i] = aws.String(u)
adds[i] = &ec2.LaunchPermission{UserId: aws.String(u)}
addsImage[i] = &ec2.LaunchPermission{UserId: aws.String(u)}
addsSnapshot[i] = &ec2.CreateVolumePermission{UserId: aws.String(u)}
}
options["users"] = &ec2.ModifyImageAttributeInput{
UserIds: users,
LaunchPermission: &ec2.LaunchPermissionModifications{
Add: adds,
Add: addsImage,
},
}
snapshotOptions["users"] = &ec2.ModifySnapshotAttributeInput{
UserIds: users,
CreateVolumePermission: &ec2.CreateVolumePermissionModifications{
Add: addsSnapshot,
},
}
}
@ -87,6 +113,7 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
}
}
// Modifying image attributes
for region, ami := range amis {
ui.Say(fmt.Sprintf("Modifying attributes on AMI (%s)...", ami))
awsConfig := aws.Config{
@ -114,6 +141,30 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
}
}
// Modifying snapshot attributes
for region, region_snapshots := range snapshots {
for _, snapshot := range region_snapshots {
ui.Say(fmt.Sprintf("Modifying attributes on snapshot (%s)...", snapshot))
awsConfig := aws.Config{
Credentials: ec2conn.Config.Credentials,
Region: aws.String(region),
}
session := session.New(&awsConfig)
regionconn := ec2.New(session)
for name, input := range snapshotOptions {
ui.Message(fmt.Sprintf("Modifying: %s", name))
input.SnapshotId = &snapshot
_, err := regionconn.ModifySnapshotAttribute(input)
if err != nil {
err := fmt.Errorf("Error modify snapshot attributes: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
}
}
return multistep.ActionContinue
}

View File

@ -66,6 +66,14 @@ func (s *stepCreateAMI) Run(state multistep.StateBag) multistep.StepAction {
}
s.image = imagesResp.Images[0]
snapshots := make(map[string][]string)
for _, blockDeviceMapping := range imagesResp.Images[0].BlockDeviceMappings {
if blockDeviceMapping.Ebs != nil {
snapshots[*ec2conn.Config.Region] = append(snapshots[*ec2conn.Config.Region], *blockDeviceMapping.Ebs.SnapshotId)
}
}
state.Put("snapshots", snapshots)
return multistep.ActionContinue
}

View File

@ -129,6 +129,7 @@ Packer to work:
"ec2:GetPasswordData",
"ec2:ModifyImageAttribute",
"ec2:ModifyInstanceAttribute",
"ec2:ModifySnapshotAttribute"
"ec2:RegisterImage",
"ec2:RunInstances",
"ec2:StopInstances",