Updated tag to slice, docs, comments, only active images, source_image_name supercedes filter name
This commit is contained in:
parent
e776ad51a9
commit
de9999ecb9
|
@ -59,19 +59,9 @@ func getImageVisibility(s string) (images.ImageVisibility, error) {
|
||||||
|
|
||||||
// Retrieve the specific ImageVisibility using the exported const from images
|
// Retrieve the specific ImageVisibility using the exported const from images
|
||||||
func getImageStatus(s string) (images.ImageStatus, error) {
|
func getImageStatus(s string) (images.ImageStatus, error) {
|
||||||
statuses := [...]images.ImageStatus{
|
activeStatus := images.ImageStatusActive
|
||||||
images.ImageStatusActive,
|
if string(activeStatus) == s {
|
||||||
images.ImageStatusDeactivated,
|
return activeStatus, nil
|
||||||
images.ImageStatusDeleted,
|
|
||||||
images.ImageStatusPendingDelete,
|
|
||||||
images.ImageStatusQueued,
|
|
||||||
images.ImageStatusSaving,
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, status := range statuses {
|
|
||||||
if string(status) == s {
|
|
||||||
return status, nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var nilStatus images.ImageStatus
|
var nilStatus images.ImageStatus
|
||||||
|
@ -80,7 +70,7 @@ func getImageStatus(s string) (images.ImageStatus, error) {
|
||||||
|
|
||||||
// Allows construction of all fields from ListOpts using the "q" tags and
|
// Allows construction of all fields from ListOpts using the "q" tags and
|
||||||
// type detection to set all fields within a provided ListOpts struct
|
// type detection to set all fields within a provided ListOpts struct
|
||||||
func buildImageFilters(input map[string]string, listOpts *images.ListOpts) *packer.MultiError {
|
func buildImageFilters(input map[string]interface{}, listOpts *images.ListOpts) *packer.MultiError {
|
||||||
|
|
||||||
// fill each field in the ListOpts based on tag/type
|
// fill each field in the ListOpts based on tag/type
|
||||||
metaOpts := reflect.Indirect(reflect.ValueOf(listOpts))
|
metaOpts := reflect.Indirect(reflect.ValueOf(listOpts))
|
||||||
|
@ -99,7 +89,7 @@ func buildImageFilters(input map[string]string, listOpts *images.ListOpts) *pack
|
||||||
|
|
||||||
// Handles integer types used in ListOpts
|
// Handles integer types used in ListOpts
|
||||||
case reflect.Int64, reflect.Int:
|
case reflect.Int64, reflect.Int:
|
||||||
iVal, err := strconv.Atoi(val)
|
iVal, err := strconv.Atoi(val.(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierror.Append(err, multiErr.Errors...)
|
multierror.Append(err, multiErr.Errors...)
|
||||||
continue
|
continue
|
||||||
|
@ -120,7 +110,7 @@ func buildImageFilters(input map[string]string, listOpts *images.ListOpts) *pack
|
||||||
vField.Set(reflect.ValueOf(val))
|
vField.Set(reflect.ValueOf(val))
|
||||||
|
|
||||||
case reflect.TypeOf(images.ImageVisibility("")):
|
case reflect.TypeOf(images.ImageVisibility("")):
|
||||||
iv, err := getImageVisibility(val)
|
iv, err := getImageVisibility(val.(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierror.Append(err, multiErr.Errors...)
|
multierror.Append(err, multiErr.Errors...)
|
||||||
continue
|
continue
|
||||||
|
@ -128,7 +118,7 @@ func buildImageFilters(input map[string]string, listOpts *images.ListOpts) *pack
|
||||||
vField.Set(reflect.ValueOf(iv))
|
vField.Set(reflect.ValueOf(iv))
|
||||||
|
|
||||||
case reflect.TypeOf(images.ImageStatus("")):
|
case reflect.TypeOf(images.ImageStatus("")):
|
||||||
is, err := getImageStatus(val)
|
is, err := getImageStatus(val.(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierror.Append(err, multiErr.Errors...)
|
multierror.Append(err, multiErr.Errors...)
|
||||||
continue
|
continue
|
||||||
|
@ -138,14 +128,7 @@ func buildImageFilters(input map[string]string, listOpts *images.ListOpts) *pack
|
||||||
|
|
||||||
// Generates slice of strings for Tags
|
// Generates slice of strings for Tags
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
typeOfSlice := reflect.TypeOf(vField).Elem()
|
vField.Set(reflect.ValueOf(val))
|
||||||
fieldArray := reflect.MakeSlice(reflect.SliceOf(typeOfSlice), 0, 0)
|
|
||||||
for _, s := range strings.Split(val, ",") {
|
|
||||||
if len(s) > 0 {
|
|
||||||
fieldArray = reflect.Append(fieldArray, reflect.ValueOf(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
vField.Set(fieldArray)
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
multierror.Append(
|
multierror.Append(
|
||||||
|
@ -158,7 +141,7 @@ func buildImageFilters(input map[string]string, listOpts *images.ListOpts) *pack
|
||||||
fieldName == reflect.TypeOf(listOpts.UpdatedAtQuery).Name() {
|
fieldName == reflect.TypeOf(listOpts.UpdatedAtQuery).Name() {
|
||||||
|
|
||||||
// get ImageDateQuery from string and set to this field
|
// get ImageDateQuery from string and set to this field
|
||||||
query, err := dateToImageDateQuery(key, val)
|
query, err := dateToImageDateQuery(key, val.(string))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
multierror.Append(err, multiErr.Errors...)
|
multierror.Append(err, multiErr.Errors...)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -30,7 +30,7 @@ func TestGetImageFilter(t *testing.T) {
|
||||||
func TestBuildImageFilter(t *testing.T) {
|
func TestBuildImageFilter(t *testing.T) {
|
||||||
testOpts := images.ListOpts{}
|
testOpts := images.ListOpts{}
|
||||||
|
|
||||||
filters := map[string]string{
|
filters := map[string]interface{}{
|
||||||
"limit": "3",
|
"limit": "3",
|
||||||
"name": "Ubuntu 16.04",
|
"name": "Ubuntu 16.04",
|
||||||
"visibility": "public",
|
"visibility": "public",
|
||||||
|
@ -127,12 +127,14 @@ func TestImageFilterOptionsDecode(t *testing.T) {
|
||||||
"most_recent": true,
|
"most_recent": true,
|
||||||
"filters": map[string]interface{}{
|
"filters": map[string]interface{}{
|
||||||
"visibility": "protected",
|
"visibility": "protected",
|
||||||
"tag": "prod",
|
"tag": []string{"prod","ready"},
|
||||||
"name": "ubuntu 16.04",
|
"name": "ubuntu 16.04",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
err := mapstructure.Decode(input, &opts)
|
err := mapstructure.Decode(input, &opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("Did not successfully generate ImageFilterOptions from %v. Contains %v", input, opts)
|
t.Errorf("Did not successfully generate ImageFilterOptions from %v.\nContains %v", input, opts)
|
||||||
|
} else {
|
||||||
|
t.Logf("Successfully generate ImageFilterOptions from %v.\nContains %v", input, opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (c *RunConfig) Prepare(ctx *interpolate.Context) []error {
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.SourceImage == "" && c.SourceImageName == "" && c.SourceImageFilters.Filters == nil {
|
if c.SourceImage == "" && c.SourceImageName == "" && c.SourceImageFilters.Filters == nil {
|
||||||
errs = append(errs, errors.New("Either a source_image, a source_image_name, or must be specified"))
|
errs = append(errs, errors.New("Either a source_image, a source_image_name, or source_image_filter must be specified"))
|
||||||
} else if len(c.SourceImage) > 0 && len(c.SourceImageName) > 0 {
|
} else if len(c.SourceImage) > 0 && len(c.SourceImageName) > 0 {
|
||||||
errs = append(errs, errors.New("Only a source_image or a source_image_name can be specified, not both."))
|
errs = append(errs, errors.New("Only a source_image or a source_image_name can be specified, not both."))
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ type StepSourceImageInfo struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ImageFilterOptions struct {
|
type ImageFilterOptions struct {
|
||||||
Filters map[string]string `mapstructure:"filters"`
|
Filters map[string]interface{} `mapstructure:"filters"`
|
||||||
MostRecent bool `mapstructure:"most_recent"`
|
MostRecent bool `mapstructure:"most_recent"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ func (s *StepSourceImageInfo) Run(_ context.Context, state multistep.StateBag) m
|
||||||
|
|
||||||
client, err := config.computeV2Client()
|
client, err := config.computeV2Client()
|
||||||
|
|
||||||
// if an ID is provided we skip the filter since that will return a single image
|
// if an ID is provided we skip the filter since that will return a single or no image
|
||||||
if s.SourceImage != "" {
|
if s.SourceImage != "" {
|
||||||
state.Put("source_image", s.SourceImage)
|
state.Put("source_image", s.SourceImage)
|
||||||
return multistep.ActionContinue
|
return multistep.ActionContinue
|
||||||
|
@ -47,6 +47,12 @@ func (s *StepSourceImageInfo) Run(_ context.Context, state multistep.StateBag) m
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// override the "name" provided in filters if "s.SourceImageName" was filled
|
||||||
|
if s.SourceImageName != "" {
|
||||||
|
params.Name = s.SourceImageName
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply "most_recent" logic to the sort fields and allow OpenStack to return the latest qualified image
|
||||||
if s.ImageFilters.MostRecent {
|
if s.ImageFilters.MostRecent {
|
||||||
applyMostRecent(params)
|
applyMostRecent(params)
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,11 +184,11 @@ builder.
|
||||||
```
|
```
|
||||||
|
|
||||||
This selects the most recent production Ubuntu 16.04 shared to you by the given owner.
|
This selects the most recent production Ubuntu 16.04 shared to you by the given owner.
|
||||||
NOTE: This will fail unless *exactly* one image is returned. In the above
|
NOTE: This will fail unless *exactly* one image is returned, or `most_recent` is set to true.
|
||||||
example, `most_recent` will cause this to succeed by selecting the newest image.
|
In the example, `most_recent` will cause this to succeed by selecting the newest image.
|
||||||
|
|
||||||
- `filters` (map of strings) - filters used to select a `source_image`.
|
- `filters` (map of strings) - filters used to select a `source_image`.
|
||||||
NOTE: This will fail unless *exactly* one image is returned.
|
NOTE: This will fail unless *exactly* one image is returned, or `most_recent` is set to true.
|
||||||
Any filter described in the docs for [ImageService](https://developer.openstack.org/api-ref/image/v2/)
|
Any filter described in the docs for [ImageService](https://developer.openstack.org/api-ref/image/v2/)
|
||||||
is valid.
|
is valid.
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue