190 lines
4.6 KiB
Go
190 lines
4.6 KiB
Go
package plugin
|
|
|
|
import (
|
|
"fmt"
|
|
"sort"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/mitchellh/mapstructure"
|
|
"google.golang.org/protobuf/types/known/structpb"
|
|
)
|
|
|
|
// CatalogAttributes is a Go-native representation of the Attributes
|
|
// map.
|
|
type CatalogAttributes struct {
|
|
Region string
|
|
DisableCredentialRotation bool
|
|
}
|
|
|
|
func getCatalogAttributes(in *structpb.Struct) (*CatalogAttributes, error) {
|
|
unknownFields := structFields(in)
|
|
result := new(CatalogAttributes)
|
|
|
|
var err error
|
|
result.Region, err = getStringValue(in, constRegion, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
delete(unknownFields, constRegion)
|
|
|
|
result.DisableCredentialRotation, err = getBoolValue(in, constDisableCredentialRotation, false)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
delete(unknownFields, constDisableCredentialRotation)
|
|
|
|
if len(unknownFields) != 0 {
|
|
return nil, fmt.Errorf("unknown catalog attribute fields provided: %s", keysAsString(unknownFields))
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// CatalogSecrets is a Go-native representation of the Secrets map.
|
|
type CatalogSecrets struct {
|
|
AccessKeyId string
|
|
SecretAccessKey string
|
|
}
|
|
|
|
func getCatalogSecrets(in *structpb.Struct) (*CatalogSecrets, error) {
|
|
unknownFields := structFields(in)
|
|
result := new(CatalogSecrets)
|
|
|
|
var err error
|
|
result.AccessKeyId, err = getStringValue(in, constAccessKeyId, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
delete(unknownFields, constAccessKeyId)
|
|
|
|
result.SecretAccessKey, err = getStringValue(in, constSecretAccessKey, true)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
delete(unknownFields, constSecretAccessKey)
|
|
|
|
if len(unknownFields) != 0 {
|
|
return nil, fmt.Errorf("unknown catalog secret fields provided: %s", keysAsString(unknownFields))
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
// SetAttributes is a Go-native representation of the Attributes map that can be
|
|
// used for decoding the incoming map via mapstructure.
|
|
type SetAttributes struct {
|
|
Filters []string
|
|
}
|
|
|
|
func getSetAttributes(in *structpb.Struct) (*SetAttributes, error) {
|
|
var setAttrs SetAttributes
|
|
|
|
// Quick validation to ensure that there's no non-filter attributes
|
|
// here for now. Make this more complex if we add more attributes
|
|
// to host sets.
|
|
unknownFields := structFields(in)
|
|
delete(unknownFields, constDescribeInstancesFilters)
|
|
if len(unknownFields) != 0 {
|
|
return nil, fmt.Errorf("unknown set attribute fields provided: %s", keysAsString(unknownFields))
|
|
}
|
|
|
|
// Mapstructure complains if it expects a slice as output and sees a scalar
|
|
// value. Rather than use WeakDecode and risk unintended consequences, I'm
|
|
// manually making this change if necessary.
|
|
inMap := in.AsMap()
|
|
if filtersRaw, ok := inMap[constDescribeInstancesFilters]; ok {
|
|
switch filterVal := filtersRaw.(type) {
|
|
case string:
|
|
inMap[constDescribeInstancesFilters] = []string{filterVal}
|
|
}
|
|
}
|
|
|
|
if err := mapstructure.Decode(inMap, &setAttrs); err != nil {
|
|
return nil, fmt.Errorf("error decoding set attributes: %w", err)
|
|
}
|
|
|
|
return &setAttrs, nil
|
|
}
|
|
|
|
func getStringValue(in *structpb.Struct, k string, required bool) (string, error) {
|
|
mv := in.GetFields()
|
|
v, ok := mv[k]
|
|
if !ok {
|
|
if required {
|
|
return "", fmt.Errorf("missing required value %q", k)
|
|
}
|
|
|
|
return "", nil
|
|
}
|
|
|
|
s, ok := v.AsInterface().(string)
|
|
if !ok {
|
|
return "", fmt.Errorf("unexpected type for value %q: want string, got %T", k, v.AsInterface())
|
|
}
|
|
|
|
if s == "" && required {
|
|
return "", fmt.Errorf("value %q cannot be empty", k)
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func getBoolValue(in *structpb.Struct, k string, required bool) (bool, error) {
|
|
mv := in.GetFields()
|
|
v, ok := mv[k]
|
|
if !ok {
|
|
if required {
|
|
return false, fmt.Errorf("missing required value %q", k)
|
|
}
|
|
|
|
return false, nil
|
|
}
|
|
|
|
b, ok := v.AsInterface().(bool)
|
|
if !ok {
|
|
return false, fmt.Errorf("unexpected type for value %q: want bool, got %T", k, v.AsInterface())
|
|
}
|
|
|
|
return b, nil
|
|
}
|
|
|
|
func getTimeValue(in *structpb.Struct, k string) (time.Time, error) {
|
|
mv := in.GetFields()
|
|
v, ok := mv[k]
|
|
if !ok {
|
|
return time.Time{}, nil
|
|
}
|
|
|
|
tRaw, ok := v.AsInterface().(string)
|
|
if !ok {
|
|
return time.Time{}, fmt.Errorf("unexpected type for value %q: want string, got %T", k, v.AsInterface())
|
|
}
|
|
|
|
t, err := time.Parse(time.RFC3339Nano, tRaw)
|
|
if err != nil {
|
|
return time.Time{}, fmt.Errorf("could not parse time in value %q: %w", k, err)
|
|
}
|
|
|
|
return t, nil
|
|
}
|
|
|
|
func structFields(s *structpb.Struct) map[string]struct{} {
|
|
m := make(map[string]struct{}, len(s.GetFields()))
|
|
for k := range s.GetFields() {
|
|
m[k] = struct{}{}
|
|
}
|
|
|
|
return m
|
|
}
|
|
|
|
func keysAsString(m map[string]struct{}) string {
|
|
s := make([]string, 0, len(m))
|
|
for k := range m {
|
|
s = append(s, k)
|
|
}
|
|
|
|
sort.Strings(s)
|
|
return strings.Join(s, ", ")
|
|
}
|