Add image filtering on properties.

Initial commit with debugging info.
pull/7597/head
Olaf Seibert 7 years ago
parent ee4f16d3a4
commit 58f8f088e2

@ -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,

@ -48,7 +48,7 @@ type RunConfig struct {
OpenstackProvider string `mapstructure:"openstack_provider"`
UseFloatingIp bool `mapstructure:"use_floating_ip"`
sourceImageOpts images.ListOpts
sourceImageOpts images.ListOpts // derived from .SourceImageFilters.Filters ImageFilterOptions
}
type ImageFilter struct {
@ -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,25 +47,52 @@ 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{}
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
}
ui.Message(fmt.Sprintf("Resulting images: %d", len(imgs)))
count := 0
first := -1
for index, img := range imgs {
ui.Message(fmt.Sprintf("index +%v, image %+v", index, img))
ui.Message(fmt.Sprintf("Metadata %+v", img.Metadata))
ui.Message(fmt.Sprintf("Properties %+v", img.Properties))
// Check if all Properties are satisfied
if PropertiesSatisfied(&img, &s.SourceProperties) {
ui.Message(fmt.Sprintf("Matched properties %+v", s.SourceProperties))
count++
if first < 0 {
first = index
}
// Don't iterate over entries we will never use.
if count > 1 {
break
}
} else {
ui.Message(fmt.Sprintf("FAILED to match properties %+v", s.SourceProperties))
}
}
switch len(i) {
switch count {
case 0:
return true, nil
case 1:
*image = i[0]
*image = imgs[first]
return false, nil
default:
if s.SourceMostRecent {
*image = i[0]
*image = imgs[first]
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",
"Your query returned more than one result. Please try a more specific search, or set most_recent to true. Search filters: %+v",
s.SourceImageOpts)
}
})
@ -67,7 +105,7 @@ 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", s.SourceImageOpts)
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…
Cancel
Save