Initial commit
This commit is contained in:
26 files changed
+2809
No files matched your search
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package credential
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/joatmon08/boundary-plugin-google/internal/errors"
|
||||
"github.com/joatmon08/boundary-plugin-google/internal/values"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
type CredentialAttributes struct {
|
||||
Project string
|
||||
Zone string
|
||||
}
|
||||
|
||||
func GetCredentialAttributes(in *structpb.Struct) (*CredentialAttributes, error) {
|
||||
badFields := make(map[string]string)
|
||||
|
||||
project, err := values.GetStringValue(in, ConstProject, true)
|
||||
if err != nil {
|
||||
badFields[fmt.Sprintf("attributes.%s", ConstProject)] = err.Error()
|
||||
}
|
||||
|
||||
zone, err := values.GetStringValue(in, ConstZone, true)
|
||||
if err != nil {
|
||||
badFields[fmt.Sprintf("attributes.%s", ConstZone)] = err.Error()
|
||||
}
|
||||
|
||||
if len(badFields) > 0 {
|
||||
return nil, errors.InvalidArgumentError("Error in the attributes provider", badFields)
|
||||
}
|
||||
|
||||
return &CredentialAttributes{
|
||||
Project: project,
|
||||
Zone: zone,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package credential
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
func TestGetCredentialAttributes(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
in map[string]any
|
||||
expected *CredentialAttributes
|
||||
expectedErrContains string
|
||||
}{
|
||||
{
|
||||
name: "missing project",
|
||||
in: map[string]any{},
|
||||
expectedErrContains: "missing required value \"project\"",
|
||||
},
|
||||
{
|
||||
name: "missing zone",
|
||||
in: map[string]any{},
|
||||
expectedErrContains: "missing required value \"zone\"",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
tc := tc
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require := require.New(t)
|
||||
|
||||
input, err := structpb.NewStruct(tc.in)
|
||||
require.NoError(err)
|
||||
|
||||
actual, err := GetCredentialAttributes(input)
|
||||
if tc.expectedErrContains != "" {
|
||||
require.Error(err)
|
||||
require.Contains(err.Error(), tc.expectedErrContains)
|
||||
require.Equal(status.Code(err), codes.InvalidArgument)
|
||||
return
|
||||
}
|
||||
|
||||
require.NoError(err)
|
||||
require.EqualValues(tc.expected.Project, actual.Project)
|
||||
require.EqualValues(tc.expected.Zone, actual.Zone)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package credential
|
||||
|
||||
const (
|
||||
ConstProject = "project"
|
||||
ConstZone = "zone"
|
||||
)
|
||||
|
||||
var AllowedCatalogFields = map[string]struct{}{
|
||||
ConstProject: {},
|
||||
ConstZone: {},
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package errors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// InvalidArgumentError returns an grpc invalid argument status error.
|
||||
func InvalidArgumentError(msg string, f map[string]string) error {
|
||||
var fieldMsgs []string
|
||||
for field, val := range f {
|
||||
fieldMsgs = append(fieldMsgs, fmt.Sprintf("%s: %s", field, val))
|
||||
}
|
||||
if len(fieldMsgs) > 0 {
|
||||
sort.Strings(fieldMsgs)
|
||||
msg = fmt.Sprintf("%s: [%s]", msg, strings.Join(fieldMsgs, ", "))
|
||||
}
|
||||
return status.Error(codes.InvalidArgument, msg)
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
// Copyright (c) HashiCorp, Inc.
|
||||
// SPDX-License-Identifier: MPL-2.0
|
||||
|
||||
package values
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"google.golang.org/protobuf/types/known/structpb"
|
||||
)
|
||||
|
||||
// GetStringValue returns a string value and no error if the given key
|
||||
// is found in the provided proto struct input. An error is returned
|
||||
// if the key is not found or the value type is not a string. An error is
|
||||
// returned if the parameter argument "required" is set to true
|
||||
// and the value from the proto struct input is empty.
|
||||
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
|
||||
}
|
||||
|
||||
// GetBoolValue returns a boolean value and no error if the given key
|
||||
// is found in the provided proto struct input. An error is returned
|
||||
// if the key is not found or the value type is not a bool.
|
||||
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
|
||||
}
|
||||
|
||||
// GetTimeValue returns a time.Time value and no error if the given key
|
||||
// is found in the provided proto struct input. An error is returned
|
||||
// if the key is not found or the value type is not a parsable. The
|
||||
// expected time layout is RFC3339Nano.
|
||||
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
|
||||
}
|
||||
|
||||
// GetMapStringString returns a map[string]string value and no error if the given key
|
||||
// is found in the provided proto struct input. An error is returned if the key
|
||||
// is not found or the value type is not map[string]string.
|
||||
func GetMapStringString(in *structpb.Struct, k string, required bool) (map[string]string, error) {
|
||||
mv := in.GetFields()
|
||||
v, ok := mv[k]
|
||||
if !ok {
|
||||
if required {
|
||||
return nil, fmt.Errorf("missing required value %q", k)
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
result := map[string]string{}
|
||||
m, ok := v.AsInterface().(map[string]any)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected type for value %q: want map[string]string, got %T", k, v.AsInterface())
|
||||
}
|
||||
for mapKey, mapValue := range m {
|
||||
e, ok := mapValue.(string)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unexpected type for value in map[%q]: want string, got %T", mapKey, mapValue)
|
||||
}
|
||||
result[mapKey] = e
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// StructFields returns a map[string]struct{} of the
|
||||
// proto struct input.
|
||||
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
|
||||
}
|
||||
Reference in new issue
Block a user