Refactored SnapshotConfig
Added Group and user permission to each snapshot
This commit is contained in:
parent
482a2c8232
commit
7f0b41bb0e
|
@ -135,26 +135,8 @@ type AMIConfig struct {
|
|||
// the intermediary AMI into any regions provided in `ami_regions`, then
|
||||
// delete the intermediary AMI. Default `false`.
|
||||
AMISkipBuildRegion bool `mapstructure:"skip_save_build_region"`
|
||||
// Key/value pair tags to apply to snapshot. They will override AMI tags if
|
||||
// already applied to snapshot. This is a [template
|
||||
// engine](/docs/templates/legacy_json_templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false"`
|
||||
// Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular
|
||||
// repeatable block containing a `key` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
SnapshotTag config.KeyValues `mapstructure:"snapshot_tag" required:"false"`
|
||||
// A list of account IDs that have
|
||||
// access to create volumes from the snapshot(s). By default no additional
|
||||
// users other than the user creating the AMI has permissions to create
|
||||
// volumes from the backing snapshot(s).
|
||||
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false"`
|
||||
// A list of groups that have access to
|
||||
// create volumes from the snapshot(s). By default no groups have permission
|
||||
// to create volumes from the snapshot(s). all will make the snapshot
|
||||
// publicly accessible.
|
||||
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false"`
|
||||
|
||||
SnapshotConfig `mapstructure:",squash"`
|
||||
}
|
||||
|
||||
func stringInSlice(s []string, searchstr string) bool {
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
//go:generate struct-markdown
|
||||
|
||||
package common
|
||||
|
||||
import "github.com/hashicorp/packer-plugin-sdk/template/config"
|
||||
|
||||
// SnapshotConfig is for common configuration related to creating AMIs.
|
||||
type SnapshotConfig struct {
|
||||
// Key/value pair tags to apply to snapshot. They will override AMI tags if
|
||||
// already applied to snapshot. This is a [template
|
||||
// engine](/docs/templates/legacy_json_templates/engine), see [Build template
|
||||
// data](#build-template-data) for more information.
|
||||
SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false"`
|
||||
// Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular
|
||||
// repeatable block containing a `key` and a `value` field. In HCL2 mode the
|
||||
// [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
SnapshotTag config.KeyValues `mapstructure:"snapshot_tag" required:"false"`
|
||||
// A list of account IDs that have
|
||||
// access to create volumes from the snapshot(s). By default no additional
|
||||
// users other than the user creating the AMI has permissions to create
|
||||
// volumes from the backing snapshot(s).
|
||||
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false"`
|
||||
// A list of groups that have access to
|
||||
// create volumes from the snapshot(s). By default no groups have permission
|
||||
// to create volumes from the snapshot(s). all will make the snapshot
|
||||
// publicly accessible.
|
||||
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false"`
|
||||
}
|
|
@ -11,8 +11,6 @@ import (
|
|||
|
||||
type BlockDevice struct {
|
||||
awscommon.BlockDevice `mapstructure:",squash"`
|
||||
// Create a Snapshot of this Volume and copy all tags.
|
||||
SnapshotVolume bool `mapstructure:"snapshot_volume" required:"false"`
|
||||
// Key/value pair tags to apply to the volume. These are retained after the builder
|
||||
// completes. This is a [template engine](/docs/templates/legacy_json_templates/engine), see
|
||||
// [Build template data](#build-template-data) for more information.
|
||||
|
@ -22,6 +20,11 @@ type BlockDevice struct {
|
|||
// [`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
// will allow you to create those programatically.
|
||||
Tag config.KeyValues `mapstructure:"tag" required:"false"`
|
||||
|
||||
// Create a Snapshot of this Volume.
|
||||
SnapshotVolume bool `mapstructure:"snapshot_volume" required:"false"`
|
||||
|
||||
awscommon.SnapshotConfig `mapstructure:",squash"`
|
||||
}
|
||||
|
||||
type BlockDevices []BlockDevice
|
||||
|
@ -40,6 +43,7 @@ func (bds BlockDevices) Prepare(ctx *interpolate.Context) (errs []error) {
|
|||
for _, block := range bds {
|
||||
|
||||
errs = append(errs, block.Tag.CopyOn(&block.Tags)...)
|
||||
errs = append(errs, block.SnapshotTag.CopyOn(&block.SnapshotTags)...)
|
||||
|
||||
if err := block.Prepare(ctx); err != nil {
|
||||
errs = append(errs, err)
|
||||
|
|
|
@ -23,9 +23,13 @@ type FlatBlockDevice struct {
|
|||
VolumeType *string `mapstructure:"volume_type" required:"false" cty:"volume_type" hcl:"volume_type"`
|
||||
VolumeSize *int64 `mapstructure:"volume_size" required:"false" cty:"volume_size" hcl:"volume_size"`
|
||||
KmsKeyId *string `mapstructure:"kms_key_id" required:"false" cty:"kms_key_id" hcl:"kms_key_id"`
|
||||
SnapshotVolume *bool `mapstructure:"snapshot_volume" required:"false" cty:"snapshot_volume" hcl:"snapshot_volume"`
|
||||
Tags map[string]string `mapstructure:"tags" required:"false" cty:"tags" hcl:"tags"`
|
||||
Tag []config.FlatKeyValue `mapstructure:"tag" required:"false" cty:"tag" hcl:"tag"`
|
||||
SnapshotVolume *bool `mapstructure:"snapshot_volume" required:"false" cty:"snapshot_volume" hcl:"snapshot_volume"`
|
||||
SnapshotTags map[string]string `mapstructure:"snapshot_tags" required:"false" cty:"snapshot_tags" hcl:"snapshot_tags"`
|
||||
SnapshotTag []config.FlatKeyValue `mapstructure:"snapshot_tag" required:"false" cty:"snapshot_tag" hcl:"snapshot_tag"`
|
||||
SnapshotUsers []string `mapstructure:"snapshot_users" required:"false" cty:"snapshot_users" hcl:"snapshot_users"`
|
||||
SnapshotGroups []string `mapstructure:"snapshot_groups" required:"false" cty:"snapshot_groups" hcl:"snapshot_groups"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatBlockDevice.
|
||||
|
@ -51,9 +55,13 @@ func (*FlatBlockDevice) HCL2Spec() map[string]hcldec.Spec {
|
|||
"volume_type": &hcldec.AttrSpec{Name: "volume_type", Type: cty.String, Required: false},
|
||||
"volume_size": &hcldec.AttrSpec{Name: "volume_size", Type: cty.Number, Required: false},
|
||||
"kms_key_id": &hcldec.AttrSpec{Name: "kms_key_id", Type: cty.String, Required: false},
|
||||
"snapshot_volume": &hcldec.AttrSpec{Name: "snapshot_volume", Type: cty.Bool, Required: false},
|
||||
"tags": &hcldec.AttrSpec{Name: "tags", Type: cty.Map(cty.String), Required: false},
|
||||
"tag": &hcldec.BlockListSpec{TypeName: "tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())},
|
||||
"snapshot_volume": &hcldec.AttrSpec{Name: "snapshot_volume", Type: cty.Bool, Required: false},
|
||||
"snapshot_tags": &hcldec.AttrSpec{Name: "snapshot_tags", Type: cty.Map(cty.String), Required: false},
|
||||
"snapshot_tag": &hcldec.BlockListSpec{TypeName: "snapshot_tag", Nested: hcldec.ObjectSpec((*config.FlatKeyValue)(nil).HCL2Spec())},
|
||||
"snapshot_users": &hcldec.AttrSpec{Name: "snapshot_users", Type: cty.List(cty.String), Required: false},
|
||||
"snapshot_groups": &hcldec.AttrSpec{Name: "snapshot_groups", Type: cty.List(cty.String), Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -14,31 +14,35 @@ import (
|
|||
|
||||
type stepSnapshotEBSVolumes struct {
|
||||
VolumeMapping []BlockDevice
|
||||
Ctx interpolate.Context
|
||||
//Map of SnapshotID: BlockDevice, Where *BlockDevice is in VolumeMapping
|
||||
SnapshotMap map[string]*BlockDevice
|
||||
Ctx interpolate.Context
|
||||
}
|
||||
|
||||
func (s *stepSnapshotEBSVolumes) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
snapshotsIds := make([]string, 0)
|
||||
s.SnapshotMap = make(map[string]*BlockDevice)
|
||||
|
||||
for _, instanceBlockDevices := range instance.BlockDeviceMappings {
|
||||
for _, configVolumeMapping := range s.VolumeMapping {
|
||||
//Find the config entry for the instance blockDevice
|
||||
if configVolumeMapping.DeviceName == *instanceBlockDevices.DeviceName {
|
||||
//Skip Volumes that are not set to create snapshot
|
||||
if configVolumeMapping.SnapshotVolume != true {
|
||||
continue
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Compiling list of tags to apply to snapshot from Volume %s...", *instanceBlockDevices.DeviceName))
|
||||
tags, err := awscommon.TagMap(configVolumeMapping.Tags).EC2Tags(s.Ctx, *ec2conn.Config.Region, state)
|
||||
tags, err := awscommon.TagMap(configVolumeMapping.SnapshotTags).EC2Tags(s.Ctx, *ec2conn.Config.Region, state)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error generating tags for device %s: %s", *instanceBlockDevices.DeviceName, err)
|
||||
err := fmt.Errorf("Error generating tags for snapshot %s: %s", *instanceBlockDevices.DeviceName, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
tags.Report(ui)
|
||||
|
||||
tagSpec := &ec2.TagSpecification{
|
||||
ResourceType: aws.String("snapshot"),
|
||||
|
@ -46,23 +50,31 @@ func (s *stepSnapshotEBSVolumes) Run(ctx context.Context, state multistep.StateB
|
|||
}
|
||||
|
||||
input := &ec2.CreateSnapshotInput{
|
||||
VolumeId: instanceBlockDevices.Ebs.VolumeId,
|
||||
VolumeId: aws.String(*instanceBlockDevices.Ebs.VolumeId),
|
||||
TagSpecifications: []*ec2.TagSpecification{tagSpec},
|
||||
}
|
||||
|
||||
//Dont try to set an empty tag spec
|
||||
if len(tags) == 0 {
|
||||
input.TagSpecifications = nil
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Requesting snapshot of volume: %s...", *instanceBlockDevices.Ebs.VolumeId))
|
||||
snapshot, err := ec2conn.CreateSnapshot(input)
|
||||
if err != nil {
|
||||
if err != nil || snapshot == nil {
|
||||
err := fmt.Errorf("Error generating snapsot for volume %s: %s", *instanceBlockDevices.Ebs.VolumeId, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
snapshotsIds = append(snapshotsIds, *snapshot.SnapshotId)
|
||||
ui.Message(fmt.Sprintf("Requested Snapshot of Volume %s: %s", *instanceBlockDevices.Ebs.VolumeId, *snapshot.SnapshotId))
|
||||
s.SnapshotMap[*snapshot.SnapshotId] = &configVolumeMapping
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ui.Say("Waiting for Snapshots to become ready...")
|
||||
for _, snapID := range snapshotsIds {
|
||||
for snapID := range s.SnapshotMap {
|
||||
ui.Message(fmt.Sprintf("Waiting for %s to be ready.", snapID))
|
||||
err := awscommon.WaitUntilSnapshotDone(ctx, ec2conn, snapID)
|
||||
if err != nil {
|
||||
|
@ -75,6 +87,62 @@ func (s *stepSnapshotEBSVolumes) Run(ctx context.Context, state multistep.StateB
|
|||
ui.Message(fmt.Sprintf("Snapshot Ready: %s", snapID))
|
||||
}
|
||||
|
||||
//Attach User and Group permissions to snapshots
|
||||
ui.Say("Setting User/Group Permissions for Snapshots...")
|
||||
for snapID, bd := range s.SnapshotMap {
|
||||
snapshotOptions := make(map[string]*ec2.ModifySnapshotAttributeInput)
|
||||
|
||||
if len(bd.SnapshotGroups) > 0 {
|
||||
groups := make([]*string, len(bd.SnapshotGroups))
|
||||
addsSnapshot := make([]*ec2.CreateVolumePermission, len(bd.SnapshotGroups))
|
||||
|
||||
addSnapshotGroups := &ec2.ModifySnapshotAttributeInput{
|
||||
CreateVolumePermission: &ec2.CreateVolumePermissionModifications{},
|
||||
}
|
||||
|
||||
for i, g := range bd.SnapshotGroups {
|
||||
groups[i] = aws.String(g)
|
||||
addsSnapshot[i] = &ec2.CreateVolumePermission{
|
||||
Group: aws.String(g),
|
||||
}
|
||||
}
|
||||
|
||||
addSnapshotGroups.GroupNames = groups
|
||||
addSnapshotGroups.CreateVolumePermission.Add = addsSnapshot
|
||||
snapshotOptions["groups"] = addSnapshotGroups
|
||||
|
||||
}
|
||||
|
||||
if len(bd.SnapshotUsers) > 0 {
|
||||
users := make([]*string, len(bd.SnapshotUsers))
|
||||
addsSnapshot := make([]*ec2.CreateVolumePermission, len(bd.SnapshotUsers))
|
||||
for i, u := range bd.SnapshotUsers {
|
||||
users[i] = aws.String(u)
|
||||
addsSnapshot[i] = &ec2.CreateVolumePermission{UserId: aws.String(u)}
|
||||
}
|
||||
|
||||
snapshotOptions["users"] = &ec2.ModifySnapshotAttributeInput{
|
||||
UserIds: users,
|
||||
CreateVolumePermission: &ec2.CreateVolumePermissionModifications{
|
||||
Add: addsSnapshot,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
//Todo: Copy to other regions and repeat this block in all regions.
|
||||
for name, input := range snapshotOptions {
|
||||
ui.Message(fmt.Sprintf("Modifying: %s", name))
|
||||
input.SnapshotId = &snapID
|
||||
_, err := ec2conn.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
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io/fs"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
@ -13,7 +13,7 @@ import (
|
|||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatOutputConfig struct {
|
||||
OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"`
|
||||
DirPerm *os.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"`
|
||||
DirPerm *fs.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatOutputConfig.
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"os"
|
||||
"io/fs"
|
||||
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
|
@ -17,7 +17,7 @@ type FlatExportConfig struct {
|
|||
Images *bool `mapstructure:"images" cty:"images" hcl:"images"`
|
||||
Manifest *string `mapstructure:"manifest" cty:"manifest" hcl:"manifest"`
|
||||
OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory" hcl:"output_directory"`
|
||||
DirPerm *os.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"`
|
||||
DirPerm *fs.FileMode `mapstructure:"directory_permission" required:"false" cty:"directory_permission" hcl:"directory_permission"`
|
||||
Options []string `mapstructure:"options" cty:"options" hcl:"options"`
|
||||
}
|
||||
|
||||
|
|
|
@ -85,6 +85,8 @@ builders.
|
|||
|
||||
@include 'builder/amazon/common/AMIConfig-not-required.mdx'
|
||||
|
||||
@include 'builder/amazon/common/SnapshotConfig-not-required.mdx'
|
||||
|
||||
### Block Devices Configuration
|
||||
|
||||
Block devices can be nested in the
|
||||
|
|
|
@ -59,6 +59,8 @@ necessary for this build to succeed and can be found further down the page.
|
|||
|
||||
@include 'builder/amazon/common/AMIConfig-not-required.mdx'
|
||||
|
||||
@include 'builder/amazon/common/SnapshotConfig-not-required.mdx'
|
||||
|
||||
### Access Configuration
|
||||
|
||||
#### Required:
|
||||
|
|
|
@ -55,6 +55,8 @@ necessary for this build to succeed and can be found further down the page.
|
|||
|
||||
@include 'builder/amazon/common/AMIConfig-not-required.mdx'
|
||||
|
||||
@include 'builder/amazon/common/SnapshotConfig-not-required.mdx'
|
||||
|
||||
### Access Configuration
|
||||
|
||||
#### Required:
|
||||
|
|
|
@ -96,6 +96,8 @@ Block devices can be nested in the
|
|||
|
||||
@include 'builder/amazon/ebsvolume/BlockDevice-not-required.mdx'
|
||||
|
||||
@include 'builder/amazon/common/SnapshotConfig-not-required.mdx'
|
||||
|
||||
### Run Configuration
|
||||
|
||||
#### Required:
|
||||
|
|
|
@ -44,7 +44,7 @@ filesystem and data.
|
|||
|
||||
- [amazon-ebsvolume](/docs/builders/amazon/ebsvolume) - Create EBS
|
||||
volumes by launching a source AMI with block devices mapped. Provision the
|
||||
instance, then destroy it, retaining the EBS volumes.
|
||||
instance, then destroy it, retaining the EBS volumes and or Snapshot.
|
||||
|
||||
<!-- TODO: fix -->
|
||||
|
||||
|
|
|
@ -116,23 +116,3 @@
|
|||
which it will not convert to an AMI in the build region. It will copy
|
||||
the intermediary AMI into any regions provided in `ami_regions`, then
|
||||
delete the intermediary AMI. Default `false`.
|
||||
|
||||
- `snapshot_tags` (map[string]string) - Key/value pair tags to apply to snapshot. They will override AMI tags if
|
||||
already applied to snapshot. This is a [template
|
||||
engine](/docs/templates/legacy_json_templates/engine), see [Build template
|
||||
data](#build-template-data) for more information.
|
||||
|
||||
- `snapshot_tag` ([]{key string, value string}) - Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular
|
||||
repeatable block containing a `key` and a `value` field. In HCL2 mode the
|
||||
[`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
will allow you to create those programatically.
|
||||
|
||||
- `snapshot_users` ([]string) - A list of account IDs that have
|
||||
access to create volumes from the snapshot(s). By default no additional
|
||||
users other than the user creating the AMI has permissions to create
|
||||
volumes from the backing snapshot(s).
|
||||
|
||||
- `snapshot_groups` ([]string) - A list of groups that have access to
|
||||
create volumes from the snapshot(s). By default no groups have permission
|
||||
to create volumes from the snapshot(s). all will make the snapshot
|
||||
publicly accessible.
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<!-- Code generated from the comments of the SnapshotConfig struct in builder/amazon/common/snapshot_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `snapshot_tags` (map[string]string) - Key/value pair tags to apply to snapshot. They will override AMI tags if
|
||||
already applied to snapshot. This is a [template
|
||||
engine](/docs/templates/legacy_json_templates/engine), see [Build template
|
||||
data](#build-template-data) for more information.
|
||||
|
||||
- `snapshot_tag` ([]{key string, value string}) - Same as [`snapshot_tags`](#snapshot_tags) but defined as a singular
|
||||
repeatable block containing a `key` and a `value` field. In HCL2 mode the
|
||||
[`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
will allow you to create those programatically.
|
||||
|
||||
- `snapshot_users` ([]string) - A list of account IDs that have
|
||||
access to create volumes from the snapshot(s). By default no additional
|
||||
users other than the user creating the AMI has permissions to create
|
||||
volumes from the backing snapshot(s).
|
||||
|
||||
- `snapshot_groups` ([]string) - A list of groups that have access to
|
||||
create volumes from the snapshot(s). By default no groups have permission
|
||||
to create volumes from the snapshot(s). all will make the snapshot
|
||||
publicly accessible.
|
|
@ -0,0 +1,3 @@
|
|||
<!-- Code generated from the comments of the SnapshotConfig struct in builder/amazon/common/snapshot_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
SnapshotConfig is for common configuration related to creating AMIs.
|
|
@ -1,7 +1,5 @@
|
|||
<!-- Code generated from the comments of the BlockDevice struct in builder/amazon/ebsvolume/block_device.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `snapshot_volume` (bool) - Create a Snapshot of this Volume and copy all tags.
|
||||
|
||||
- `tags` (map[string]string) - Key/value pair tags to apply to the volume. These are retained after the builder
|
||||
completes. This is a [template engine](/docs/templates/legacy_json_templates/engine), see
|
||||
[Build template data](#build-template-data) for more information.
|
||||
|
@ -10,3 +8,5 @@
|
|||
containing a `key` and a `value` field. In HCL2 mode the
|
||||
[`dynamic_block`](/docs/templates/hcl_templates/expressions#dynamic-blocks)
|
||||
will allow you to create those programatically.
|
||||
|
||||
- `snapshot_volume` (bool) - Create a Snapshot of this Volume.
|
||||
|
|
Loading…
Reference in New Issue