packer-cn/builder/openstack/image_query.go

121 lines
3.3 KiB
Go

package openstack
import (
"fmt"
"github.com/gophercloud/gophercloud/openstack/imageservice/v2/images"
"github.com/hashicorp/packer/packer"
"reflect"
)
const (
mostRecentSort = "created_at:desc"
)
var validFields = map[string]string{
"Name": "name",
"Visibility": "visibility",
"Owner": "owner",
"Tags": "tags",
}
// Retrieve the specific ImageVisibility using the exported const from images
func getImageVisibility(s string) (images.ImageVisibility, error) {
visibilities := [...]images.ImageVisibility{
images.ImageVisibilityPublic,
images.ImageVisibilityPrivate,
images.ImageVisibilityCommunity,
images.ImageVisibilityShared,
}
for _, visibility := range visibilities {
if string(visibility) == s {
return visibility, nil
}
}
var nilVisibility images.ImageVisibility
return nilVisibility, fmt.Errorf("No valid ImageVisibility found for %s", s)
}
// Allows construction of all supported fields from ListOpts
// The `input` map will be modified but is not reused further in the builder
func buildImageFilters(input map[string]interface{}, listOpts *images.ListOpts) *packer.MultiError {
// fill each field in the ListOpts based on tag/type
metaOpts := reflect.Indirect(reflect.ValueOf(listOpts))
multiErr := packer.MultiError{}
for i := 0; i < metaOpts.Type().NumField(); i++ {
vField := metaOpts.Field(i)
fieldName := metaOpts.Type().Field(i).Name
// check the valid fields map and whether we can set this field
if key, exists := validFields[fieldName]; exists {
// check that this key was provided by the user, then set the field and have compatible types
if val, exists := input[key]; exists {
// non-settable field
if !vField.CanSet() {
multiErr.Errors = append(multiErr.Errors, fmt.Errorf("Unsettable field: %s", fieldName))
// remove key from input filters so we can go over them after
delete(input, key)
continue
}
switch key {
case "owner", "name", "tags":
if valType := reflect.TypeOf(val); valType != vField.Type() {
multiErr.Errors = append(multiErr.Errors,
fmt.Errorf("Invalid type '%v' for field %s (%s)",
valType,
key,
fieldName,
))
break
}
vField.Set(reflect.ValueOf(val))
case "visibility":
visibility, err := getImageVisibility(val.(string))
if err != nil {
multiErr.Errors = append(multiErr.Errors, err)
break
}
vField.Set(reflect.ValueOf(visibility))
}
// remove key from input filters so we can go over them after
delete(input, key)
}
}
}
// error any invalid filters
for key, value := range input {
multiErr.Errors = append(multiErr.Errors, fmt.Errorf("Invalid filter: %s: %v (type: %v)",
key,
value,
reflect.TypeOf(value),
))
}
// Set defaults for status and member_status
listOpts.Status = images.ImageStatusActive
listOpts.MemberStatus = images.ImageMemberStatusAccepted
return &multiErr
}
// Apply most recent filtering logic to ListOpts where user has filled fields.
// See https://developer.openstack.org/api-ref/image/v2/
func applyMostRecent(listOpts *images.ListOpts) {
// Sort isn't supported through our API so there should be no existing values.
// Overwriting ListOpts.Sort is okay.
listOpts.Sort = mostRecentSort
return
}