Initial commit

This commit is contained in:
Rosemary Wang committed 2024-07-11 11:15:47 -04:00
1 parent 2a9356fc04
commit e3daac2ce8
26 files changed
+2809

No files matched your search

+40
View File
@@ -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
}
+55
View File
@@ -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)
})
}
}
+14
View File
@@ -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: {},
}
+26
View File
@@ -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)
}
+123
View File
@@ -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
}