Merge pull request #7597 from oseiberts11/add-openstack-image-properties
Add image filtering on properties.
This commit is contained in:
commit
a145804795
|
@ -97,6 +97,7 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
SourceImageName: b.config.RunConfig.SourceImageName,
|
||||
SourceImageOpts: b.config.RunConfig.sourceImageOpts,
|
||||
SourceMostRecent: b.config.SourceImageFilters.MostRecent,
|
||||
SourceProperties: b.config.SourceImageFilters.Filters.Properties,
|
||||
},
|
||||
&StepCreateVolume{
|
||||
UseBlockStorageVolume: b.config.UseBlockStorageVolume,
|
||||
|
|
|
@ -57,14 +57,15 @@ type ImageFilter struct {
|
|||
}
|
||||
|
||||
type ImageFilterOptions struct {
|
||||
Name string `mapstructure:"name"`
|
||||
Owner string `mapstructure:"owner"`
|
||||
Tags []string `mapstructure:"tags"`
|
||||
Visibility string `mapstructure:"visibility"`
|
||||
Name string `mapstructure:"name"`
|
||||
Owner string `mapstructure:"owner"`
|
||||
Tags []string `mapstructure:"tags"`
|
||||
Visibility string `mapstructure:"visibility"`
|
||||
Properties map[string]string `mapstructure:"properties"`
|
||||
}
|
||||
|
||||
func (f *ImageFilterOptions) Empty() bool {
|
||||
return f.Name == "" && f.Owner == "" && len(f.Tags) == 0 && f.Visibility == ""
|
||||
return f.Name == "" && f.Owner == "" && len(f.Tags) == 0 && f.Visibility == "" && len(f.Properties) == 0
|
||||
}
|
||||
|
||||
func (f *ImageFilterOptions) Build() (*images.ListOpts, error) {
|
||||
|
|
|
@ -139,6 +139,7 @@ func TestBuildImageFilter(t *testing.T) {
|
|||
Visibility: "public",
|
||||
Owner: "1234567890",
|
||||
Tags: []string{"prod", "ready"},
|
||||
Properties: map[string]string{"os_distro": "ubuntu", "os_version": "16.04"},
|
||||
}
|
||||
|
||||
listOpts, err := filters.Build()
|
||||
|
@ -198,6 +199,7 @@ func TestImageFiltersEmpty(t *testing.T) {
|
|||
Visibility: "public",
|
||||
Owner: "1234567890",
|
||||
Tags: []string{"prod", "ready"},
|
||||
Properties: map[string]string{"os_distro": "ubuntu", "os_version": "16.04"},
|
||||
}
|
||||
|
||||
if filledFilters.Empty() {
|
||||
|
|
|
@ -16,6 +16,17 @@ type StepSourceImageInfo struct {
|
|||
SourceImageName string
|
||||
SourceImageOpts images.ListOpts
|
||||
SourceMostRecent bool
|
||||
SourceProperties map[string]string
|
||||
}
|
||||
|
||||
func PropertiesSatisfied(image *images.Image, props *map[string]string) bool {
|
||||
for key, value := range *props {
|
||||
if image.Properties[key] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *StepSourceImageInfo) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
|
@ -36,26 +47,45 @@ func (s *StepSourceImageInfo) Run(ctx context.Context, state multistep.StateBag)
|
|||
}
|
||||
}
|
||||
|
||||
log.Printf("Using Image Filters %v", s.SourceImageOpts)
|
||||
log.Printf("Using Image Filters %+v", s.SourceImageOpts)
|
||||
image := &images.Image{}
|
||||
count := 0
|
||||
err = images.List(client, s.SourceImageOpts).EachPage(func(page pagination.Page) (bool, error) {
|
||||
i, err := images.ExtractImages(page)
|
||||
imgs, err := images.ExtractImages(page)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
switch len(i) {
|
||||
case 1:
|
||||
*image = i[0]
|
||||
return false, nil
|
||||
default:
|
||||
for _, img := range imgs {
|
||||
// Check if all Properties are satisfied
|
||||
if PropertiesSatisfied(&img, &s.SourceProperties) {
|
||||
count++
|
||||
if count == 1 {
|
||||
// Tentatively return this result.
|
||||
*image = img
|
||||
}
|
||||
// Don't iterate over entries we will never use.
|
||||
if count > 1 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch count {
|
||||
case 0: // Continue looking at next page.
|
||||
return true, nil
|
||||
case 1: // Maybe we're done, maybe there is another result in a later page and it is an error.
|
||||
if s.SourceMostRecent {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
default: // By now we should know if getting 2+ results is an error or not.
|
||||
if s.SourceMostRecent {
|
||||
*image = i[0]
|
||||
return false, nil
|
||||
}
|
||||
return false, fmt.Errorf(
|
||||
"Your query returned more than one result. Please try a more specific search, or set most_recent to true. Search filters: %v",
|
||||
s.SourceImageOpts)
|
||||
"Your query returned more than one result. Please try a more specific search, or set most_recent to true. Search filters: %+v properties %+v",
|
||||
s.SourceImageOpts, s.SourceProperties)
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -67,7 +97,8 @@ func (s *StepSourceImageInfo) Run(ctx context.Context, state multistep.StateBag)
|
|||
}
|
||||
|
||||
if image.ID == "" {
|
||||
err := fmt.Errorf("No image was found matching filters: %v", s.SourceImageOpts)
|
||||
err := fmt.Errorf("No image was found matching filters: %+v properties %+v",
|
||||
s.SourceImageOpts, s.SourceProperties)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
|
|
|
@ -202,7 +202,10 @@ builder.
|
|||
"name": "ubuntu-16.04",
|
||||
"visibility": "protected",
|
||||
"owner": "d1a588cf4b0743344508dc145649372d1",
|
||||
"tags": ["prod", "ready"]
|
||||
"tags": ["prod", "ready"],
|
||||
"properties": {
|
||||
"os_distro": "ubuntu"
|
||||
}
|
||||
},
|
||||
"most_recent": true
|
||||
}
|
||||
|
@ -229,6 +232,9 @@ builder.
|
|||
|
||||
- visibility (string)
|
||||
|
||||
- properties (map of strings to strings) (fields that can be set
|
||||
with `openstack image set --property key=value`)
|
||||
|
||||
- `most_recent` (boolean) - Selects the newest created image when true.
|
||||
This is most useful for selecting a daily distro build.
|
||||
|
||||
|
|
Loading…
Reference in New Issue