From 33d1671e4cbcff8a4277686dbe450c43a8cc427a Mon Sep 17 00:00:00 2001 From: Marin Salinas Date: Wed, 30 Jan 2019 18:33:56 -0600 Subject: [PATCH] feature: bsusurrogate, add Source OMI Info step --- builder/osc/bsusurrogate/builder.go | 7 ++ builder/osc/common/build_filters.go | 39 ++++++++ builder/osc/common/run_config.go | 4 +- builder/osc/common/run_config_test.go | 4 +- builder/osc/common/step_source_omi_info.go | 102 +++++++++++++++++++++ 5 files changed, 152 insertions(+), 4 deletions(-) create mode 100644 builder/osc/common/build_filters.go create mode 100644 builder/osc/common/step_source_omi_info.go diff --git a/builder/osc/bsusurrogate/builder.go b/builder/osc/bsusurrogate/builder.go index d4f52ac40..21e43b6db 100644 --- a/builder/osc/bsusurrogate/builder.go +++ b/builder/osc/bsusurrogate/builder.go @@ -137,6 +137,13 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe DestOmiName: b.config.OMIName, ForceDeregister: b.config.OMIForceDeregister, }, + &osccommon.StepSourceOMIInfo{ + SourceOmi: b.config.SourceOmi, + EnableOMISriovNetSupport: b.config.OMISriovNetSupport, + EnableOMIENASupport: b.config.OMIENASupport, + OmiFilters: b.config.SourceOmiFilter, + OMIVirtType: b.config.OMIVirtType, //TODO: Remove if it is not used + }, } b.runner = common.NewRunner(steps, b.config.PackerConfig, ui) diff --git a/builder/osc/common/build_filters.go b/builder/osc/common/build_filters.go new file mode 100644 index 000000000..67e7ecc1e --- /dev/null +++ b/builder/osc/common/build_filters.go @@ -0,0 +1,39 @@ +package common + +import ( + "log" + + "github.com/outscale/osc-go/oapi" +) + +func buildOMIFilters(input map[string]string) oapi.FiltersImage { + var filters oapi.FiltersImage + for k, v := range input { + filterValue := []string{v} + + switch name := k; name { + case "account_aliases": + filters.AccountAliases = filterValue + case "account_ids": + filters.AccountIds = filterValue + case "architectures": + filters.Architectures = filterValue + case "image_ids": + filters.ImageIds = filterValue + case "image_names": + filters.ImageNames = filterValue + case "image_types": + filters.ImageTypes = filterValue + case "virtualization_types": + filters.VirtualizationTypes = filterValue + case "root_device_types": + filters.RootDeviceTypes = filterValue + case "block_device_mapping_volume_type": + filters.BlockDeviceMappingVolumeType = filterValue + //Some params are missing. + default: + log.Printf("[Debug] Unknown Filter Name: %s.", name) + } + } + return filters +} diff --git a/builder/osc/common/run_config.go b/builder/osc/common/run_config.go index 44b64b01e..4ac088572 100644 --- a/builder/osc/common/run_config.go +++ b/builder/osc/common/run_config.go @@ -16,8 +16,8 @@ import ( var reShutdownBehavior = regexp.MustCompile("^(stop|terminate)$") type OmiFilterOptions struct { - Filters map[*string]*string - Owners []*string + Filters map[string]string + Owners []string MostRecent bool `mapstructure:"most_recent"` } diff --git a/builder/osc/common/run_config_test.go b/builder/osc/common/run_config_test.go index 5bdc977b7..b6416d522 100644 --- a/builder/osc/common/run_config_test.go +++ b/builder/osc/common/run_config_test.go @@ -71,7 +71,7 @@ func TestRunConfigPrepare_SourceOmiFilterOwnersBlank(t *testing.T) { c := testConfigFilter() filter_key := "name" filter_value := "foo" - c.SourceOmiFilter = OmiFilterOptions{Filters: map[*string]*string{&filter_key: &filter_value}} + c.SourceOmiFilter = OmiFilterOptions{Filters: map[string]string{filter_key: filter_value}} if err := c.Prepare(nil); len(err) != 1 { t.Fatalf("Should error if Owners is not specified)") } @@ -82,7 +82,7 @@ func TestRunConfigPrepare_SourceOmiFilterGood(t *testing.T) { owner := "123" filter_key := "name" filter_value := "foo" - goodFilter := OmiFilterOptions{Owners: []*string{&owner}, Filters: map[*string]*string{&filter_key: &filter_value}} + goodFilter := OmiFilterOptions{Owners: []string{owner}, Filters: map[string]string{filter_key: filter_value}} c.SourceOmiFilter = goodFilter if err := c.Prepare(nil); len(err) != 0 { t.Fatalf("err: %s", err) diff --git a/builder/osc/common/step_source_omi_info.go b/builder/osc/common/step_source_omi_info.go new file mode 100644 index 000000000..05c9e7d41 --- /dev/null +++ b/builder/osc/common/step_source_omi_info.go @@ -0,0 +1,102 @@ +package common + +import ( + "context" + "fmt" + "log" + "sort" + "time" + + "github.com/hashicorp/packer/helper/multistep" + "github.com/hashicorp/packer/packer" + "github.com/outscale/osc-go/oapi" +) + +// StepSourceOMIInfo extracts critical information from the source OMI +// that is used throughout the OMI creation process. +// +// Produces: +// source_image *oapi.Image - the source OMI info +type StepSourceOMIInfo struct { + SourceOmi string + EnableOMISriovNetSupport bool + EnableOMIENASupport *bool + OMIVirtType string + OmiFilters OmiFilterOptions +} + +type imageSort []oapi.Image + +func (a imageSort) Len() int { return len(a) } +func (a imageSort) Swap(i, j int) { a[i], a[j] = a[j], a[i] } +func (a imageSort) Less(i, j int) bool { + itime, _ := time.Parse(time.RFC3339, a[i].CreationDate) + jtime, _ := time.Parse(time.RFC3339, a[j].CreationDate) + return itime.Unix() < jtime.Unix() +} + +// Returns the most recent OMI out of a slice of images. +func mostRecentOmi(images []oapi.Image) oapi.Image { + sortedImages := images + sort.Sort(imageSort(sortedImages)) + return sortedImages[len(sortedImages)-1] +} + +func (s *StepSourceOMIInfo) Run(_ context.Context, state multistep.StateBag) multistep.StepAction { + oapiconn := state.Get("oapi").(*oapi.Client) + ui := state.Get("ui").(packer.Ui) + + params := oapi.ReadImagesRequest{ + Filters: oapi.FiltersImage{}, + } + + if s.SourceOmi != "" { + params.Filters.ImageIds = []string{s.SourceOmi} + } + + // We have filters to apply + if len(s.OmiFilters.Filters) > 0 { + params.Filters = buildOMIFilters(s.OmiFilters.Filters) + } + //TODO:Check if AccountIds correspond to Owners. + if len(s.OmiFilters.Owners) > 0 { + params.Filters.AccountIds = s.OmiFilters.Owners + } + + log.Printf("Using OMI Filters %v", params) + imageResp, err := oapiconn.POST_ReadImages(params) + if err != nil { + err := fmt.Errorf("Error querying OMI: %s", err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + if len(imageResp.OK.Images) == 0 { + err := fmt.Errorf("No OMI was found matching filters: %v", params) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + if len(imageResp.OK.Images) > 1 && !s.OmiFilters.MostRecent { + err := fmt.Errorf("Your query returned more than one result. Please try a more specific search, or set most_recent to true.") + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt + } + + var image oapi.Image + if s.OmiFilters.MostRecent { + image = mostRecentOmi(imageResp.OK.Images) + } else { + image = imageResp.OK.Images[0] + } + + ui.Message(fmt.Sprintf("Found Image ID: %s", image.ImageId)) + + state.Put("source_image", image) + return multistep.ActionContinue +} + +func (s *StepSourceOMIInfo) Cleanup(multistep.StateBag) {}