feature: bsusurrogate, add StepUpdateOMIAttributes step
This commit is contained in:
parent
b46636a39b
commit
2c4b2b8657
|
@ -227,6 +227,11 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
||||||
OMIDevices: omiDevices,
|
OMIDevices: omiDevices,
|
||||||
LaunchDevices: launchDevices,
|
LaunchDevices: launchDevices,
|
||||||
},
|
},
|
||||||
|
&osccommon.StepUpdateOMIAttributes{
|
||||||
|
AccountIds: b.config.OMIAccountIDs,
|
||||||
|
SnapshotAccountIds: b.config.SnapshotAccountIDs,
|
||||||
|
Ctx: b.config.ctx,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
|
b.runner = common.NewRunner(steps, b.config.PackerConfig, ui)
|
||||||
|
|
|
@ -10,25 +10,22 @@ import (
|
||||||
|
|
||||||
// OMIConfig is for common configuration related to creating OMIs.
|
// OMIConfig is for common configuration related to creating OMIs.
|
||||||
type OMIConfig struct {
|
type OMIConfig struct {
|
||||||
OMIName string `mapstructure:"omi_name"`
|
OMIName string `mapstructure:"omi_name"`
|
||||||
OMIDescription string `mapstructure:"omi_description"`
|
OMIDescription string `mapstructure:"omi_description"`
|
||||||
OMIVirtType string `mapstructure:"omi_virtualization_type"`
|
OMIVirtType string `mapstructure:"omi_virtualization_type"`
|
||||||
OMIUsers []string `mapstructure:"omi_users"`
|
OMIAccountIDs []string `mapstructure:"omi_account_ids"`
|
||||||
OMIGroups []string `mapstructure:"omi_groups"`
|
OMIGroups []string `mapstructure:"omi_groups"`
|
||||||
OMIProductCodes []string `mapstructure:"omi_product_codes"`
|
OMIProductCodes []string `mapstructure:"omi_product_codes"`
|
||||||
OMIRegions []string `mapstructure:"omi_regions"`
|
OMIRegions []string `mapstructure:"omi_regions"`
|
||||||
OMISkipRegionValidation bool `mapstructure:"skip_region_validation"`
|
OMISkipRegionValidation bool `mapstructure:"skip_region_validation"`
|
||||||
OMITags TagMap `mapstructure:"tags"`
|
OMITags TagMap `mapstructure:"tags"`
|
||||||
OMIENASupport *bool `mapstructure:"ena_support"`
|
OMIENASupport *bool `mapstructure:"ena_support"`
|
||||||
OMISriovNetSupport bool `mapstructure:"sriov_support"`
|
OMISriovNetSupport bool `mapstructure:"sriov_support"`
|
||||||
OMIForceDeregister bool `mapstructure:"force_deregister"`
|
OMIForceDeregister bool `mapstructure:"force_deregister"`
|
||||||
OMIForceDeleteSnapshot bool `mapstructure:"force_delete_snapshot"`
|
OMIForceDeleteSnapshot bool `mapstructure:"force_delete_snapshot"`
|
||||||
OMIEncryptBootVolume bool `mapstructure:"encrypt_boot"`
|
SnapshotTags TagMap `mapstructure:"snapshot_tags"`
|
||||||
OMIKmsKeyId string `mapstructure:"kms_key_id"`
|
SnapshotAccountIDs []string `mapstructure:"snapshot_account_ids"`
|
||||||
OMIRegionKMSKeyIDs map[string]string `mapstructure:"region_kms_key_ids"`
|
SnapshotGroups []string `mapstructure:"snapshot_groups"`
|
||||||
SnapshotTags TagMap `mapstructure:"snapshot_tags"`
|
|
||||||
SnapshotUsers []string `mapstructure:"snapshot_users"`
|
|
||||||
SnapshotGroups []string `mapstructure:"snapshot_groups"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func stringInSlice(s []string, searchstr string) bool {
|
func stringInSlice(s []string, searchstr string) bool {
|
||||||
|
@ -47,52 +44,8 @@ func (c *OMIConfig) Prepare(accessConfig *AccessConfig, ctx *interpolate.Context
|
||||||
errs = append(errs, fmt.Errorf("omi_name must be specified"))
|
errs = append(errs, fmt.Errorf("omi_name must be specified"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure that if we have region_kms_key_ids defined,
|
|
||||||
// the regions in region_kms_key_ids are also in omi_regions
|
|
||||||
if len(c.OMIRegionKMSKeyIDs) > 0 {
|
|
||||||
for kmsKeyRegion := range c.OMIRegionKMSKeyIDs {
|
|
||||||
if !stringInSlice(c.OMIRegions, kmsKeyRegion) {
|
|
||||||
errs = append(errs, fmt.Errorf("Region %s is in region_kms_key_ids but not in omi_regions", kmsKeyRegion))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
errs = append(errs, c.prepareRegions(accessConfig)...)
|
errs = append(errs, c.prepareRegions(accessConfig)...)
|
||||||
|
|
||||||
if len(c.OMIUsers) > 0 && c.OMIEncryptBootVolume {
|
|
||||||
errs = append(errs, fmt.Errorf("Cannot share OMI with encrypted boot volume"))
|
|
||||||
}
|
|
||||||
|
|
||||||
var kmsKeys []string
|
|
||||||
if len(c.OMIKmsKeyId) > 0 {
|
|
||||||
kmsKeys = append(kmsKeys, c.OMIKmsKeyId)
|
|
||||||
}
|
|
||||||
if len(c.OMIRegionKMSKeyIDs) > 0 {
|
|
||||||
for _, kmsKey := range c.OMIRegionKMSKeyIDs {
|
|
||||||
if len(kmsKey) == 0 {
|
|
||||||
kmsKeys = append(kmsKeys, c.OMIKmsKeyId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for _, kmsKey := range kmsKeys {
|
|
||||||
if !validateKmsKey(kmsKey) {
|
|
||||||
errs = append(errs, fmt.Errorf("%s is not a valid KMS Key Id.", kmsKey))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.SnapshotUsers) > 0 {
|
|
||||||
if len(c.OMIKmsKeyId) == 0 && c.OMIEncryptBootVolume {
|
|
||||||
errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
|
|
||||||
}
|
|
||||||
if len(c.OMIRegionKMSKeyIDs) > 0 {
|
|
||||||
for _, kmsKey := range c.OMIRegionKMSKeyIDs {
|
|
||||||
if len(kmsKey) == 0 {
|
|
||||||
errs = append(errs, fmt.Errorf("Cannot share snapshot encrypted with default KMS key"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(c.OMIName) < 3 || len(c.OMIName) > 128 {
|
if len(c.OMIName) < 3 || len(c.OMIName) > 128 {
|
||||||
errs = append(errs, fmt.Errorf("omi_name must be between 3 and 128 characters long"))
|
errs = append(errs, fmt.Errorf("omi_name must be between 3 and 128 characters long"))
|
||||||
}
|
}
|
||||||
|
@ -126,13 +79,6 @@ func (c *OMIConfig) prepareRegions(accessConfig *AccessConfig) (errs []error) {
|
||||||
// Mark that we saw the region
|
// Mark that we saw the region
|
||||||
regionSet[region] = struct{}{}
|
regionSet[region] = struct{}{}
|
||||||
|
|
||||||
// Make sure that if we have region_kms_key_ids defined,
|
|
||||||
// the regions in omi_regions are also in region_kms_key_ids
|
|
||||||
if len(c.OMIRegionKMSKeyIDs) > 0 {
|
|
||||||
if _, ok := c.OMIRegionKMSKeyIDs[region]; !ok {
|
|
||||||
errs = append(errs, fmt.Errorf("Region %s is in omi_regions but not in region_kms_key_ids", region))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (accessConfig != nil) && (region == accessConfig.RawRegion) {
|
if (accessConfig != nil) && (region == accessConfig.RawRegion) {
|
||||||
// make sure we don't try to copy to the region we originally
|
// make sure we don't try to copy to the region we originally
|
||||||
// create the OMI in.
|
// create the OMI in.
|
||||||
|
|
|
@ -68,64 +68,35 @@ func TestOMIConfigPrepare_regions(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
c.OMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
c.OMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
||||||
c.OMIRegionKMSKeyIDs = map[string]string{
|
|
||||||
"us-east-1": "123-456-7890",
|
|
||||||
"us-west-1": "789-012-3456",
|
|
||||||
"us-east-2": "456-789-0123",
|
|
||||||
}
|
|
||||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||||
t.Fatal(fmt.Sprintf("shouldn't have error: %s", errs[0]))
|
t.Fatal(fmt.Sprintf("shouldn't have error: %s", errs[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
c.OMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
c.OMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
||||||
c.OMIRegionKMSKeyIDs = map[string]string{
|
|
||||||
"us-east-1": "123-456-7890",
|
|
||||||
"us-west-1": "789-012-3456",
|
|
||||||
"us-east-2": "",
|
|
||||||
}
|
|
||||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||||
t.Fatal("should have passed; we are able to use default KMS key if not sharing")
|
t.Fatal("should have passed; we are able to use default KMS key if not sharing")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.SnapshotUsers = []string{"user-foo", "user-bar"}
|
c.SnapshotAccountIDs = []string{"user-foo", "user-bar"}
|
||||||
c.OMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
c.OMIRegions = []string{"us-east-1", "us-east-2", "us-west-1"}
|
||||||
c.OMIRegionKMSKeyIDs = map[string]string{
|
|
||||||
"us-east-1": "123-456-7890",
|
|
||||||
"us-west-1": "789-012-3456",
|
|
||||||
"us-east-2": "",
|
|
||||||
}
|
|
||||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||||
t.Fatal("should have an error b/c can't use default KMS key if sharing")
|
t.Fatal("should have an error b/c can't use default KMS key if sharing")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.OMIRegions = []string{"us-east-1", "us-west-1"}
|
c.OMIRegions = []string{"us-east-1", "us-west-1"}
|
||||||
c.OMIRegionKMSKeyIDs = map[string]string{
|
|
||||||
"us-east-1": "123-456-7890",
|
|
||||||
"us-west-1": "789-012-3456",
|
|
||||||
"us-east-2": "456-789-0123",
|
|
||||||
}
|
|
||||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||||
t.Fatal("should have error b/c theres a region in the key map that isn't in omi_regions")
|
t.Fatal("should have error b/c theres a region in the key map that isn't in omi_regions")
|
||||||
}
|
}
|
||||||
|
|
||||||
c.OMIRegions = []string{"us-east-1", "us-west-1", "us-east-2"}
|
c.OMIRegions = []string{"us-east-1", "us-west-1", "us-east-2"}
|
||||||
c.OMIRegionKMSKeyIDs = map[string]string{
|
|
||||||
"us-east-1": "123-456-7890",
|
|
||||||
"us-west-1": "789-012-3456",
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := c.Prepare(accessConf, nil); err == nil {
|
c.SnapshotAccountIDs = []string{"foo", "bar"}
|
||||||
t.Fatal("should have error b/c theres a region in in omi_regions that isn't in the key map")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.SnapshotUsers = []string{"foo", "bar"}
|
|
||||||
c.OMIKmsKeyId = "123-abc-456"
|
|
||||||
c.OMIEncryptBootVolume = true
|
|
||||||
c.OMIRegions = []string{"us-east-1", "us-west-1"}
|
c.OMIRegions = []string{"us-east-1", "us-west-1"}
|
||||||
c.OMIRegionKMSKeyIDs = map[string]string{
|
|
||||||
"us-east-1": "123-456-7890",
|
|
||||||
"us-west-1": "",
|
|
||||||
}
|
|
||||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||||
t.Fatal("should have error b/c theres a region in in omi_regions that isn't in the key map")
|
t.Fatal("should have error b/c theres a region in in omi_regions that isn't in the key map")
|
||||||
}
|
}
|
||||||
|
@ -133,66 +104,13 @@ func TestOMIConfigPrepare_regions(t *testing.T) {
|
||||||
// allow rawregion to exist in omi_regions list.
|
// allow rawregion to exist in omi_regions list.
|
||||||
accessConf = getFakeAccessConfig("us-east-1")
|
accessConf = getFakeAccessConfig("us-east-1")
|
||||||
c.OMIRegions = []string{"us-east-1", "us-west-1", "us-east-2"}
|
c.OMIRegions = []string{"us-east-1", "us-west-1", "us-east-2"}
|
||||||
c.OMIRegionKMSKeyIDs = nil
|
|
||||||
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
if errs = c.prepareRegions(accessConf); len(errs) > 0 {
|
||||||
t.Fatal("should allow user to have the raw region in omi_regions")
|
t.Fatal("should allow user to have the raw region in omi_regions")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestOMIConfigPrepare_Share_EncryptedBoot(t *testing.T) {
|
|
||||||
c := testOMIConfig()
|
|
||||||
c.OMIUsers = []string{"testAccountID"}
|
|
||||||
c.OMIEncryptBootVolume = true
|
|
||||||
|
|
||||||
accessConf := testAccessConfig()
|
|
||||||
|
|
||||||
c.OMIKmsKeyId = ""
|
|
||||||
if err := c.Prepare(accessConf, nil); err == nil {
|
|
||||||
t.Fatal("shouldn't be able to share omi with encrypted boot volume")
|
|
||||||
}
|
|
||||||
|
|
||||||
c.OMIKmsKeyId = "89c3fb9a-de87-4f2a-aedc-fddc5138193c"
|
|
||||||
if err := c.Prepare(accessConf, nil); err == nil {
|
|
||||||
t.Fatal("shouldn't be able to share omi with encrypted boot volume")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOMIConfigPrepare_ValidateKmsKey(t *testing.T) {
|
|
||||||
c := testOMIConfig()
|
|
||||||
c.OMIEncryptBootVolume = true
|
|
||||||
|
|
||||||
accessConf := testAccessConfig()
|
|
||||||
|
|
||||||
validCases := []string{
|
|
||||||
"abcd1234-e567-890f-a12b-a123b4cd56ef",
|
|
||||||
"alias/foo/bar",
|
|
||||||
"arn:aws:kms:us-east-1:012345678910:key/abcd1234-a123-456a-a12b-a123b4cd56ef",
|
|
||||||
"arn:aws:kms:us-east-1:012345678910:alias/foo/bar",
|
|
||||||
}
|
|
||||||
for _, validCase := range validCases {
|
|
||||||
c.OMIKmsKeyId = validCase
|
|
||||||
if err := c.Prepare(accessConf, nil); err != nil {
|
|
||||||
t.Fatalf("%s should not have failed KMS key validation", validCase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
invalidCases := []string{
|
|
||||||
"ABCD1234-e567-890f-a12b-a123b4cd56ef",
|
|
||||||
"ghij1234-e567-890f-a12b-a123b4cd56ef",
|
|
||||||
"ghij1234+e567_890f-a12b-a123b4cd56ef",
|
|
||||||
"foo/bar",
|
|
||||||
"arn:aws:kms:us-east-1:012345678910:foo/bar",
|
|
||||||
}
|
|
||||||
for _, invalidCase := range invalidCases {
|
|
||||||
c.OMIKmsKeyId = invalidCase
|
|
||||||
if err := c.Prepare(accessConf, nil); err == nil {
|
|
||||||
t.Fatalf("%s should have failed KMS key validation", invalidCase)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestOMINameValidation(t *testing.T) {
|
func TestOMINameValidation(t *testing.T) {
|
||||||
c := testOMIConfig()
|
c := testOMIConfig()
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
package common
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/hashicorp/packer/helper/multistep"
|
||||||
|
"github.com/hashicorp/packer/packer"
|
||||||
|
"github.com/hashicorp/packer/template/interpolate"
|
||||||
|
"github.com/outscale/osc-go/oapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
type StepUpdateOMIAttributes struct {
|
||||||
|
AccountIds []string
|
||||||
|
SnapshotAccountIds []string
|
||||||
|
Ctx interpolate.Context
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepUpdateOMIAttributes) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
|
||||||
|
oapiconn := state.Get("oapi").(*oapi.Client)
|
||||||
|
config := state.Get("config").(*oapi.Config)
|
||||||
|
ui := state.Get("ui").(packer.Ui)
|
||||||
|
omis := state.Get("omis").(map[string]string)
|
||||||
|
snapshots := state.Get("snapshots").(map[string][]string)
|
||||||
|
|
||||||
|
// Determine if there is any work to do.
|
||||||
|
valid := false
|
||||||
|
valid = valid || (s.AccountIds != nil && len(s.AccountIds) > 0)
|
||||||
|
valid = valid || (s.SnapshotAccountIds != nil && len(s.SnapshotAccountIds) > 0)
|
||||||
|
|
||||||
|
if !valid {
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Ctx.Data = extractBuildInfo(oapiconn.GetConfig().Region, state)
|
||||||
|
|
||||||
|
updateSnapshoptRequest := oapi.UpdateSnapshotRequest{
|
||||||
|
PermissionsToCreateVolume: oapi.PermissionsOnResourceCreation{
|
||||||
|
Additions: oapi.PermissionsOnResource{
|
||||||
|
AccountIds: s.AccountIds,
|
||||||
|
GlobalPermission: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
updateImageRequest := oapi.UpdateImageRequest{
|
||||||
|
PermissionsToLaunch: oapi.PermissionsOnResourceCreation{
|
||||||
|
Additions: oapi.PermissionsOnResource{
|
||||||
|
AccountIds: s.AccountIds,
|
||||||
|
GlobalPermission: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updating image attributes
|
||||||
|
for region, omi := range omis {
|
||||||
|
ui.Say(fmt.Sprintf("Updating attributes on OMI (%s)...", omi))
|
||||||
|
newConfig := &oapi.Config{
|
||||||
|
UserAgent: config.UserAgent,
|
||||||
|
SecretKey: config.SecretKey,
|
||||||
|
Service: config.Service,
|
||||||
|
Region: region, //New region
|
||||||
|
URL: config.URL,
|
||||||
|
}
|
||||||
|
|
||||||
|
skipClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
regionconn := oapi.NewClient(newConfig, skipClient)
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Updating: %s", omi))
|
||||||
|
updateImageRequest.ImageId = omi
|
||||||
|
_, err := regionconn.POST_UpdateImage(updateImageRequest)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error updating OMI: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updating snapshot attributes
|
||||||
|
for region, region_snapshots := range snapshots {
|
||||||
|
for _, snapshot := range region_snapshots {
|
||||||
|
ui.Say(fmt.Sprintf("Updating attributes on snapshot (%s)...", snapshot))
|
||||||
|
newConfig := &oapi.Config{
|
||||||
|
UserAgent: config.UserAgent,
|
||||||
|
SecretKey: config.SecretKey,
|
||||||
|
Service: config.Service,
|
||||||
|
Region: region, //New region
|
||||||
|
URL: config.URL,
|
||||||
|
}
|
||||||
|
|
||||||
|
skipClient := &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
regionconn := oapi.NewClient(newConfig, skipClient)
|
||||||
|
|
||||||
|
ui.Message(fmt.Sprintf("Updating: %s", snapshot))
|
||||||
|
updateSnapshoptRequest.SnapshotId = snapshot
|
||||||
|
_, err := regionconn.POST_UpdateSnapshot(updateSnapshoptRequest)
|
||||||
|
if err != nil {
|
||||||
|
err := fmt.Errorf("Error updating snapshot: %s", err)
|
||||||
|
state.Put("error", err)
|
||||||
|
ui.Error(err.Error())
|
||||||
|
return multistep.ActionHalt
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return multistep.ActionContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *StepUpdateOMIAttributes) Cleanup(state multistep.StateBag) {
|
||||||
|
// No cleanup...
|
||||||
|
}
|
Loading…
Reference in New Issue