open-consul/agent/grpc-external/services/dataplane/get_envoy_bootstrap_params.go
Dan Upton 20c87d235f
dataplane: update envoy bootstrap params for consul-dataplane (#14017)
Contains 2 changes to the GetEnvoyBootstrapParams response to support
consul-dataplane.

Exposing node_name and node_id:

consul-dataplane will support providing either the node_id or node_name in its
configuration. Unfortunately, supporting both in the xDS meta adds a fair amount
of complexity (partly because most tables are currently indexed on node_name)
so for now we're going to return them both from the bootstrap params endpoint,
allowing consul-dataplane to exchange a node_id for a node_name (which it will
supply in the xDS meta).

Properly setting service for gateways:

To avoid the need to special case gateways in consul-dataplane, service will now
either be the destination service name for connect proxies, or the gateway
service name. This means it can be used as-is in Envoy configuration (i.e. as a
cluster name or in metric tags).
2022-08-24 12:03:15 +01:00

97 lines
3.4 KiB
Go

package dataplane
import (
"context"
"errors"
"strings"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/structpb"
acl "github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/consul/state"
external "github.com/hashicorp/consul/agent/grpc-external"
structs "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/proto-public/pbdataplane"
)
func (s *Server) GetEnvoyBootstrapParams(ctx context.Context, req *pbdataplane.GetEnvoyBootstrapParamsRequest) (*pbdataplane.GetEnvoyBootstrapParamsResponse, error) {
logger := s.Logger.Named("get-envoy-bootstrap-params").With("service_id", req.GetServiceId(), "request_id", external.TraceID())
logger.Trace("Started processing request")
defer logger.Trace("Finished processing request")
token := external.TokenFromContext(ctx)
var authzContext acl.AuthorizerContext
entMeta := acl.NewEnterpriseMetaWithPartition(req.GetPartition(), req.GetNamespace())
authz, err := s.ACLResolver.ResolveTokenAndDefaultMeta(token, &entMeta, &authzContext)
if err != nil {
return nil, status.Error(codes.Unauthenticated, err.Error())
}
store := s.GetStore()
_, svc, err := store.ServiceNode(req.GetNodeId(), req.GetNodeName(), req.GetServiceId(), &entMeta, structs.DefaultPeerKeyword)
if err != nil {
logger.Error("Error looking up service", "error", err)
if errors.Is(err, state.ErrNodeNotFound) {
return nil, status.Error(codes.NotFound, err.Error())
} else if strings.Contains(err.Error(), "Node ID or name required") {
return nil, status.Error(codes.InvalidArgument, err.Error())
} else {
return nil, status.Error(codes.Internal, "Failure looking up service")
}
}
if svc == nil {
return nil, status.Error(codes.NotFound, "Service not found")
}
if err := authz.ToAllowAuthorizer().ServiceReadAllowed(svc.ServiceName, &authzContext); err != nil {
return nil, status.Error(codes.PermissionDenied, err.Error())
}
// Build out the response
var serviceName string
if svc.ServiceKind == structs.ServiceKindConnectProxy {
serviceName = svc.ServiceProxy.DestinationServiceName
} else {
serviceName = svc.ServiceName
}
resp := &pbdataplane.GetEnvoyBootstrapParamsResponse{
Service: serviceName,
Partition: svc.EnterpriseMeta.PartitionOrDefault(),
Namespace: svc.EnterpriseMeta.NamespaceOrDefault(),
Datacenter: s.Datacenter,
ServiceKind: convertToResponseServiceKind(svc.ServiceKind),
NodeName: svc.Node,
NodeId: string(svc.ID),
}
bootstrapConfig, err := structpb.NewStruct(svc.ServiceProxy.Config)
if err != nil {
logger.Error("Error creating the envoy boostrap params config", "error", err)
return nil, status.Error(codes.Unknown, "Error creating the envoy boostrap params config")
}
resp.Config = bootstrapConfig
return resp, nil
}
func convertToResponseServiceKind(serviceKind structs.ServiceKind) (respKind pbdataplane.ServiceKind) {
switch serviceKind {
case structs.ServiceKindConnectProxy:
respKind = pbdataplane.ServiceKind_SERVICE_KIND_CONNECT_PROXY
case structs.ServiceKindMeshGateway:
respKind = pbdataplane.ServiceKind_SERVICE_KIND_MESH_GATEWAY
case structs.ServiceKindTerminatingGateway:
respKind = pbdataplane.ServiceKind_SERVICE_KIND_TERMINATING_GATEWAY
case structs.ServiceKindIngressGateway:
respKind = pbdataplane.ServiceKind_SERVICE_KIND_INGRESS_GATEWAY
case structs.ServiceKindTypical:
respKind = pbdataplane.ServiceKind_SERVICE_KIND_TYPICAL
}
return
}