add support for google host attributes: - project_id (Required): The project ID associated with the service account - zone (Required): The deployment area within a region disable_credential_rotation (Optional): Disables credential rotation by the plugin - client_email (Optional): The email address associated with the service account. The email address used to uniquely identify the service account. It is required for authentication and authorization. If it is not set, authentication will fail. - target_service_account_id (Optional): The unique identifier for the service account that will be impersonated. - disable_credential_rotation (Optional): Disable the rotation of google service account key associated with the plugin
140 lines
3.9 KiB
Go
140 lines
3.9 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package host
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
computepb "cloud.google.com/go/compute/apiv1/computepb"
|
|
cred "github.com/hashicorp/boundary-plugin-gcp/internal/credential"
|
|
"github.com/hashicorp/boundary-plugin-gcp/internal/errors"
|
|
"github.com/hashicorp/boundary-plugin-gcp/internal/values"
|
|
"github.com/mitchellh/mapstructure"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/status"
|
|
"google.golang.org/protobuf/types/known/structpb"
|
|
)
|
|
|
|
// CatalogAttributes defines a set of attributes for the host catalog
|
|
type CatalogAttributes struct {
|
|
*cred.CredentialAttributes
|
|
}
|
|
|
|
func getCatalogAttributes(in *structpb.Struct) (*CatalogAttributes, error) {
|
|
unknownFields := values.StructFields(in)
|
|
badFields := make(map[string]string)
|
|
|
|
var err error
|
|
credAttributes, err := cred.GetCredentialAttributes(in)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for s := range unknownFields {
|
|
switch s {
|
|
// Ignore knownFields from CredentialAttributes
|
|
case cred.ConstProjectId:
|
|
continue
|
|
case cred.ConstZone:
|
|
continue
|
|
case cred.ConstDisableCredentialRotation:
|
|
continue
|
|
case cred.ConstClientEmail:
|
|
continue
|
|
case cred.ConstTargetServiceAccountID:
|
|
continue
|
|
default:
|
|
badFields[fmt.Sprintf("attributes.%s", s)] = "unrecognized field"
|
|
}
|
|
}
|
|
|
|
if len(badFields) > 0 {
|
|
return nil, errors.InvalidArgumentError("Invalid arguments in catalog attributes", badFields)
|
|
}
|
|
|
|
return &CatalogAttributes{
|
|
CredentialAttributes: credAttributes,
|
|
}, nil
|
|
}
|
|
|
|
// SetAttributes defines attributes fro the host set
|
|
type SetAttributes struct {
|
|
Filter string `mapstructure:"filter"`
|
|
InstanceGroup string `mapstructure:"instance_group"`
|
|
}
|
|
|
|
func getSetAttributes(in *structpb.Struct) (*SetAttributes, error) {
|
|
var setAttrs SetAttributes
|
|
|
|
badFields := make(map[string]string)
|
|
unknownFields := values.StructFields(in)
|
|
|
|
if _, filter := unknownFields[ConstListInstancesFilter]; filter {
|
|
if _, ig := unknownFields[ConstInstanceGroup]; ig {
|
|
return nil, errors.InvalidArgumentError("Error in the attributes provided, cannot define both filter and instance group", nil)
|
|
}
|
|
}
|
|
|
|
delete(unknownFields, ConstListInstancesFilter)
|
|
delete(unknownFields, ConstInstanceGroup)
|
|
|
|
for a := range unknownFields {
|
|
badFields[fmt.Sprintf("attributes.%s", a)] = "unrecognized field"
|
|
}
|
|
if len(badFields) > 0 {
|
|
return nil, errors.InvalidArgumentError("Error in the attributes provided", badFields)
|
|
}
|
|
|
|
// 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[ConstListInstancesFilter]; ok {
|
|
switch filterVal := filtersRaw.(type) {
|
|
case string:
|
|
inMap[ConstListInstancesFilter] = string(filterVal)
|
|
}
|
|
}
|
|
|
|
if instanceGroupRaw, ok := inMap[ConstInstanceGroup]; ok {
|
|
switch instanceGroupValue := instanceGroupRaw.(type) {
|
|
case string:
|
|
inMap[ConstInstanceGroup] = string(instanceGroupValue)
|
|
}
|
|
}
|
|
|
|
if err := mapstructure.Decode(inMap, &setAttrs); err != nil {
|
|
return nil, status.Errorf(codes.InvalidArgument, "error decoding set attributes: %s", err)
|
|
}
|
|
|
|
return &setAttrs, nil
|
|
}
|
|
|
|
func buildListInstancesRequest(attributes *SetAttributes, catalog *CatalogAttributes) *computepb.ListInstancesRequest {
|
|
request := &computepb.ListInstancesRequest{
|
|
Project: catalog.ProjectId,
|
|
Zone: catalog.Zone,
|
|
}
|
|
|
|
if len(attributes.Filter) > 1 {
|
|
request.Filter = &attributes.Filter
|
|
}
|
|
|
|
return request
|
|
}
|
|
|
|
func buildListInstanceGroupsRequest(attributes *SetAttributes, catalog *CatalogAttributes) *computepb.ListInstancesInstanceGroupsRequest {
|
|
request := &computepb.ListInstancesInstanceGroupsRequest{
|
|
InstanceGroup: attributes.InstanceGroup,
|
|
Project: catalog.ProjectId,
|
|
Zone: catalog.Zone,
|
|
}
|
|
|
|
if len(attributes.Filter) > 1 {
|
|
request.Filter = &attributes.Filter
|
|
}
|
|
|
|
return request
|
|
}
|