Implement APIGateway proxycfg snapshot (#16194)

* Stub proxycfg handler for API gateway

* Add Service Kind constants/handling for API Gateway

* Begin stubbing for SDS

* Add new Secret type to xDS order of operations

* Continue stubbing of SDS

* Iterate on proxycfg handler for API gateway

* Handle BoundAPIGateway config entry subscription in proxycfg-glue

* Add API gateway to config snapshot validation

* Add API gateway to config snapshot clone, leaf, etc.

* Subscribe to bound route + cert config entries on bound-api-gateway

* Track routes + certs on API gateway config snapshot

* Generate DeepCopy() for types used in watch.Map

* Watch all active references on api-gateway, unwatch inactive

* Track loading of initial bound-api-gateway config entry

* Use proper proto package for SDS mapping

* Use ResourceReference instead of ServiceName, collect resources

* Fix typo, add + remove TODOs

* Watch discovery chains for TCPRoute

* Add TODO for updating gateway services for api-gateway

* make proto

* Regenerate deep-copy for proxycfg

* Set datacenter on upstream ID from query source

* Watch discovery chains for http-route service backends

* Add ServiceName getter to HTTP+TCP Service structs

* Clean up unwatched discovery chains on API Gateway

* Implement watch for ingress leaf certificate

* Collect upstreams on http-route + tcp-route updates

* Remove unused GatewayServices update handler

* Remove unnecessary gateway services logic for API Gateway

* Remove outdate TODO

* Use .ToIngress where appropriate, including TODO for cleaning up

* Cancel before returning error

* Remove GatewayServices subscription

* Add godoc for handlerAPIGateway functions

* Update terminology from Connect => Consul Service Mesh

Consistent with terminology changes in https://github.com/hashicorp/consul/pull/12690

* Add missing TODO

* Remove duplicate switch case

* Rerun deep-copy generator

* Use correct property on config snapshot

* Remove unnecessary leaf cert watch

* Clean up based on code review feedback

* Note handler properties that are initialized but set elsewhere

* Add TODO for moving helper func into structs pkg

* Update generated DeepCopy code

* gofmt

* Generate DeepCopy() for API gateway listener types

* Improve variable name

* Regenerate DeepCopy() code

* Fix linting issue

* Temporarily remove the secret type from resource generation
This commit is contained in:
Nathan Coleman 2023-02-08 16:52:12 -05:00 committed by GitHub
parent bc7badae9f
commit 423257c473
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 971 additions and 76 deletions

View File

@ -1715,6 +1715,8 @@ func (b *builder) serviceKindVal(v *string) structs.ServiceKind {
return structs.ServiceKindTerminatingGateway
case string(structs.ServiceKindIngressGateway):
return structs.ServiceKindIngressGateway
case string(structs.ServiceKindAPIGateway):
return structs.ServiceKindAPIGateway
default:
return structs.ServiceKindTypical
}

View File

@ -462,9 +462,9 @@ func insertConfigEntryWithTxn(tx WriteTxn, idx uint64, conf structs.ConfigEntry)
if conf == nil {
return fmt.Errorf("cannot insert nil config entry")
}
// If the config entry is for a terminating or ingress gateway we update the memdb table
// that associates gateways <-> services.
if conf.GetKind() == structs.TerminatingGateway || conf.GetKind() == structs.IngressGateway {
err := updateGatewayServices(tx, idx, conf, conf.GetEnterpriseMeta())
if err != nil {

View File

@ -126,6 +126,8 @@ func convertToResponseServiceKind(serviceKind structs.ServiceKind) (respKind pbd
respKind = pbdataplane.ServiceKind_SERVICE_KIND_TERMINATING_GATEWAY
case structs.ServiceKindIngressGateway:
respKind = pbdataplane.ServiceKind_SERVICE_KIND_INGRESS_GATEWAY
case structs.ServiceKindAPIGateway:
respKind = pbdataplane.ServiceKind_SERVICE_KIND_API_GATEWAY
case structs.ServiceKindTypical:
respKind = pbdataplane.ServiceKind_SERVICE_KIND_TYPICAL
}

View File

@ -0,0 +1,426 @@
package proxycfg
import (
"context"
"fmt"
"github.com/hashicorp/consul/agent/proxycfg/internal/watch"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/proto/pbpeering"
)
var _ kindHandler = (*handlerAPIGateway)(nil)
// handlerAPIGateway generates a new ConfigSnapshot in response to
// changes related to an api-gateway.
type handlerAPIGateway struct {
handlerState
}
// initialize sets up the initial watches needed based on the api-gateway registration
func (h *handlerAPIGateway) initialize(ctx context.Context) (ConfigSnapshot, error) {
snap := newConfigSnapshotFromServiceInstance(h.serviceInstance, h.stateConfig)
// Watch for root changes
err := h.dataSources.CARoots.Notify(ctx, &structs.DCSpecificRequest{
Datacenter: h.source.Datacenter,
QueryOptions: structs.QueryOptions{Token: h.token},
Source: *h.source,
}, rootsWatchID, h.ch)
if err != nil {
return snap, err
}
// Get information about the entire service mesh.
err = h.dataSources.ConfigEntry.Notify(ctx, &structs.ConfigEntryQuery{
Kind: structs.MeshConfig,
Name: structs.MeshConfigMesh,
Datacenter: h.source.Datacenter,
QueryOptions: structs.QueryOptions{Token: h.token},
EnterpriseMeta: *structs.DefaultEnterpriseMetaInPartition(h.proxyID.PartitionOrDefault()),
}, meshConfigEntryID, h.ch)
if err != nil {
return snap, err
}
// Watch the api-gateway's config entry
err = h.subscribeToConfigEntry(ctx, structs.APIGateway, h.service, gatewayConfigWatchID)
if err != nil {
return snap, err
}
// Watch the bound-api-gateway's config entry
err = h.subscribeToConfigEntry(ctx, structs.BoundAPIGateway, h.service, gatewayConfigWatchID)
if err != nil {
return snap, err
}
snap.APIGateway.Listeners = make(map[string]structs.APIGatewayListener)
snap.APIGateway.BoundListeners = make(map[string]structs.BoundAPIGatewayListener)
snap.APIGateway.HTTPRoutes = watch.NewMap[structs.ResourceReference, *structs.HTTPRouteConfigEntry]()
snap.APIGateway.TCPRoutes = watch.NewMap[structs.ResourceReference, *structs.TCPRouteConfigEntry]()
snap.APIGateway.Certificates = watch.NewMap[structs.ResourceReference, *structs.InlineCertificateConfigEntry]()
// These need to be initialized here but are set by handlerUpstreams
snap.APIGateway.DiscoveryChain = make(map[UpstreamID]*structs.CompiledDiscoveryChain)
snap.APIGateway.PeerUpstreamEndpoints = watch.NewMap[UpstreamID, structs.CheckServiceNodes]()
snap.APIGateway.PeerUpstreamEndpointsUseHostnames = make(map[UpstreamID]struct{})
snap.APIGateway.UpstreamPeerTrustBundles = watch.NewMap[string, *pbpeering.PeeringTrustBundle]()
snap.APIGateway.WatchedDiscoveryChains = make(map[UpstreamID]context.CancelFunc)
snap.APIGateway.WatchedGateways = make(map[UpstreamID]map[string]context.CancelFunc)
snap.APIGateway.WatchedGatewayEndpoints = make(map[UpstreamID]map[string]structs.CheckServiceNodes)
snap.APIGateway.WatchedUpstreams = make(map[UpstreamID]map[string]context.CancelFunc)
snap.APIGateway.WatchedUpstreamEndpoints = make(map[UpstreamID]map[string]structs.CheckServiceNodes)
return snap, nil
}
func (h *handlerAPIGateway) subscribeToConfigEntry(ctx context.Context, kind, name, watchID string) error {
return h.dataSources.ConfigEntry.Notify(ctx, &structs.ConfigEntryQuery{
Kind: kind,
Name: name,
Datacenter: h.source.Datacenter,
QueryOptions: structs.QueryOptions{Token: h.token},
EnterpriseMeta: h.proxyID.EnterpriseMeta,
}, watchID, h.ch)
}
// handleUpdate responds to changes in the api-gateway. In general, we want
// to crawl the various resources related to or attached to the gateway and
// collect the list of things need to generate xDS. This list of resources
// includes the bound-api-gateway, http-routes, tcp-routes, and inline-certificates.
func (h *handlerAPIGateway) handleUpdate(ctx context.Context, u UpdateEvent, snap *ConfigSnapshot) error {
if u.Err != nil {
return fmt.Errorf("error filling agent cache: %v", u.Err)
}
switch {
case u.CorrelationID == rootsWatchID:
// Handle change in the CA roots
if err := h.handleRootCAUpdate(u, snap); err != nil {
return err
}
case u.CorrelationID == gatewayConfigWatchID:
// Handle change in the api-gateway or bound-api-gateway config entry
if err := h.handleGatewayConfigUpdate(ctx, u, snap); err != nil {
return err
}
case u.CorrelationID == inlineCertificateConfigWatchID:
// Handle change in an attached inline-certificate config entry
if err := h.handleInlineCertConfigUpdate(ctx, u, snap); err != nil {
return err
}
case u.CorrelationID == routeConfigWatchID:
// Handle change in an attached http-route or tcp-route config entry
if err := h.handleRouteConfigUpdate(ctx, u, snap); err != nil {
return err
}
default:
return (*handlerUpstreams)(h).handleUpdateUpstreams(ctx, u, snap)
}
return nil
}
// handleRootCAUpdate responds to changes in the watched root CA for a gateway
func (h *handlerAPIGateway) handleRootCAUpdate(u UpdateEvent, snap *ConfigSnapshot) error {
roots, ok := u.Result.(*structs.IndexedCARoots)
if !ok {
return fmt.Errorf("invalid type for response: %T", u.Result)
}
snap.Roots = roots
return nil
}
// handleGatewayConfigUpdate responds to changes in the watched config entry for a gateway.
// In particular, we want to make sure that we're subscribing to any attached resources such
// as routes and certificates. These additional subscriptions will enable us to update the
// config snapshot appropriately for any route or certificate changes.
func (h *handlerAPIGateway) handleGatewayConfigUpdate(ctx context.Context, u UpdateEvent, snap *ConfigSnapshot) error {
resp, ok := u.Result.(*structs.ConfigEntryResponse)
if !ok {
return fmt.Errorf("invalid type for response: %T", u.Result)
} else if resp.Entry == nil {
return nil
}
switch gwConf := resp.Entry.(type) {
case *structs.BoundAPIGatewayConfigEntry:
snap.APIGateway.BoundGatewayConfig = gwConf
seenRefs := make(map[structs.ResourceReference]any)
for _, listener := range gwConf.Listeners {
snap.APIGateway.BoundListeners[listener.Name] = listener
// Subscribe to changes in each attached x-route config entry
for _, ref := range listener.Routes {
seenRefs[ref] = struct{}{}
ctx, cancel := context.WithCancel(ctx)
switch ref.Kind {
case structs.HTTPRoute:
snap.APIGateway.HTTPRoutes.InitWatch(ref, cancel)
case structs.TCPRoute:
snap.APIGateway.TCPRoutes.InitWatch(ref, cancel)
default:
cancel()
return fmt.Errorf("unexpected route kind on gateway: %s", ref.Kind)
}
err := h.subscribeToConfigEntry(ctx, ref.Kind, ref.Name, routeConfigWatchID)
if err != nil {
// TODO May want to continue
return err
}
}
// Subscribe to changes in each attached inline-certificate config entry
for _, ref := range listener.Certificates {
ctx, cancel := context.WithCancel(ctx)
seenRefs[ref] = struct{}{}
snap.APIGateway.Certificates.InitWatch(ref, cancel)
err := h.subscribeToConfigEntry(ctx, ref.Kind, ref.Name, inlineCertificateConfigWatchID)
if err != nil {
// TODO May want to continue
return err
}
}
}
// Unsubscribe from any config entries that are no longer attached
snap.APIGateway.HTTPRoutes.ForEachKey(func(ref structs.ResourceReference) bool {
if _, ok := seenRefs[ref]; !ok {
snap.APIGateway.HTTPRoutes.CancelWatch(ref)
}
return true
})
snap.APIGateway.TCPRoutes.ForEachKey(func(ref structs.ResourceReference) bool {
if _, ok := seenRefs[ref]; !ok {
snap.APIGateway.TCPRoutes.CancelWatch(ref)
}
return true
})
snap.APIGateway.Certificates.ForEachKey(func(ref structs.ResourceReference) bool {
if _, ok := seenRefs[ref]; !ok {
snap.APIGateway.Certificates.CancelWatch(ref)
}
return true
})
snap.APIGateway.BoundGatewayConfigLoaded = true
break
case *structs.APIGatewayConfigEntry:
snap.APIGateway.GatewayConfig = gwConf
for _, listener := range gwConf.Listeners {
snap.APIGateway.Listeners[listener.Name] = listener
}
snap.APIGateway.GatewayConfigLoaded = true
break
default:
return fmt.Errorf("invalid type for config entry: %T", resp.Entry)
}
return nil
}
// handleInlineCertConfigUpdate stores the certificate for the gateway
func (h *handlerAPIGateway) handleInlineCertConfigUpdate(_ context.Context, u UpdateEvent, snap *ConfigSnapshot) error {
resp, ok := u.Result.(*structs.ConfigEntryResponse)
if !ok {
return fmt.Errorf("invalid type for response: %T", u.Result)
} else if resp.Entry == nil {
return nil
}
cfg, ok := resp.Entry.(*structs.InlineCertificateConfigEntry)
if !ok {
return fmt.Errorf("invalid type for config entry: %T", resp.Entry)
}
// TODO Consider if unset SectionName and acl.EnterpriseMeta could trip us up
ref := structs.ResourceReference{
Kind: cfg.GetKind(),
Name: cfg.GetName(),
}
snap.APIGateway.Certificates.Set(ref, cfg)
return nil
}
// handleRouteConfigUpdate builds the list of upstreams for services on
// the route and watches the related discovery chains.
func (h *handlerAPIGateway) handleRouteConfigUpdate(ctx context.Context, u UpdateEvent, snap *ConfigSnapshot) error {
resp, ok := u.Result.(*structs.ConfigEntryResponse)
if !ok {
return fmt.Errorf("invalid type for response: %T", u.Result)
} else if resp.Entry == nil {
return nil
}
// TODO Consider if unset SectionName and acl.EnterpriseMeta could trip us up
ref := structs.ResourceReference{
Kind: resp.Entry.GetKind(),
Name: resp.Entry.GetName(),
}
seenUpstreamIDs := make(map[UpstreamID]struct{})
upstreams := make(map[APIGatewayListenerKey]structs.Upstreams)
switch route := resp.Entry.(type) {
case *structs.HTTPRouteConfigEntry:
snap.APIGateway.HTTPRoutes.Set(ref, route)
for _, rule := range route.Rules {
for _, service := range rule.Services {
for _, listener := range snap.APIGateway.Listeners {
shouldBind := false
for _, parent := range route.Parents {
if h.referenceIsForListener(parent, listener, snap) {
shouldBind = true
break
}
}
if !shouldBind {
continue
}
upstream := structs.Upstream{
DestinationName: service.Name,
DestinationNamespace: service.NamespaceOrDefault(),
DestinationPartition: service.PartitionOrDefault(),
LocalBindPort: listener.Port,
// TODO IngressHosts: g.Hosts,
// Pass the protocol that was configured on the listener in order
// to force that protocol on the Envoy listener.
Config: map[string]interface{}{
"protocol": "http",
},
}
listenerKey := APIGatewayListenerKey{Protocol: string(listener.Protocol), Port: listener.Port}
upstreams[listenerKey] = append(upstreams[listenerKey], upstream)
}
upstreamID := NewUpstreamIDFromServiceName(service.ServiceName())
seenUpstreamIDs[upstreamID] = struct{}{}
watchOpts := discoveryChainWatchOpts{
id: upstreamID,
name: service.Name,
namespace: service.NamespaceOrDefault(),
partition: service.PartitionOrDefault(),
datacenter: h.stateConfig.source.Datacenter,
}
handler := &handlerUpstreams{handlerState: h.handlerState}
if err := handler.watchDiscoveryChain(ctx, snap, watchOpts); err != nil {
return fmt.Errorf("failed to watch discovery chain for %s: %w", upstreamID, err)
}
}
}
case *structs.TCPRouteConfigEntry:
snap.APIGateway.TCPRoutes.Set(ref, route)
for _, service := range route.Services {
upstreamID := NewUpstreamIDFromServiceName(service.ServiceName())
seenUpstreamIDs[upstreamID] = struct{}{}
// For each listener, check if this route should bind and, if so, create an upstream.
for _, listener := range snap.APIGateway.Listeners {
shouldBind := false
for _, parent := range route.Parents {
if h.referenceIsForListener(parent, listener, snap) {
shouldBind = true
break
}
}
if !shouldBind {
continue
}
upstream := structs.Upstream{
DestinationName: service.Name,
DestinationNamespace: service.NamespaceOrDefault(),
DestinationPartition: service.PartitionOrDefault(),
LocalBindPort: listener.Port,
//IngressHosts: g.Hosts,
// Pass the protocol that was configured on the ingress listener in order
// to force that protocol on the Envoy listener.
Config: map[string]interface{}{
"protocol": "tcp",
},
}
listenerKey := APIGatewayListenerKey{Protocol: string(listener.Protocol), Port: listener.Port}
upstreams[listenerKey] = append(upstreams[listenerKey], upstream)
}
watchOpts := discoveryChainWatchOpts{
id: upstreamID,
name: service.Name,
namespace: service.NamespaceOrDefault(),
partition: service.PartitionOrDefault(),
datacenter: h.stateConfig.source.Datacenter,
}
handler := &handlerUpstreams{handlerState: h.handlerState}
if err := handler.watchDiscoveryChain(ctx, snap, watchOpts); err != nil {
return fmt.Errorf("failed to watch discovery chain for %s: %w", upstreamID, err)
}
}
default:
return fmt.Errorf("invalid type for config entry: %T", resp.Entry)
}
snap.APIGateway.Upstreams = upstreams
snap.APIGateway.UpstreamsSet = seenUpstreamIDs
//snap.APIGateway.Hosts = TODO
snap.APIGateway.AreHostsSet = true
// Stop watching any upstreams and discovery chains that have become irrelevant
for upstreamID, cancelDiscoChain := range snap.APIGateway.WatchedDiscoveryChains {
if _, ok := seenUpstreamIDs[upstreamID]; ok {
continue
}
for targetID, cancelUpstream := range snap.APIGateway.WatchedUpstreams[upstreamID] {
cancelUpstream()
delete(snap.APIGateway.WatchedUpstreams[upstreamID], targetID)
delete(snap.APIGateway.WatchedUpstreamEndpoints[upstreamID], targetID)
if targetUID := NewUpstreamIDFromTargetID(targetID); targetUID.Peer != "" {
snap.APIGateway.PeerUpstreamEndpoints.CancelWatch(targetUID)
snap.APIGateway.UpstreamPeerTrustBundles.CancelWatch(targetUID.Peer)
}
}
cancelDiscoChain()
delete(snap.APIGateway.WatchedDiscoveryChains, upstreamID)
}
return nil
}
// referenceIsForListener returns whether the provided structs.ResourceReference
// targets the provided structs.APIGatewayListener. For this to be true, the kind
// and name must match the structs.APIGatewayConfigEntry containing the listener,
// and the reference must specify either no section name or the name of the listener
// as the section name.
//
// TODO This would probably be more generally useful as a helper in the structs pkg
func (h *handlerAPIGateway) referenceIsForListener(ref structs.ResourceReference, listener structs.APIGatewayListener, snap *ConfigSnapshot) bool {
if ref.Kind != snap.APIGateway.GatewayConfig.Kind {
return false
}
if ref.Name != snap.APIGateway.GatewayConfig.Name {
return false
}
return ref.SectionName == "" || ref.SectionName == listener.Name
}

View File

@ -10,6 +10,7 @@ deep-copy -pointer-receiver \
-type ConfigSnapshotUpstreams \
-type PeerServersValue \
-type PeeringServiceValue \
-type configSnapshotAPIGateway \
-type configSnapshotConnectProxy \
-type configSnapshotIngressGateway \
-type configSnapshotMeshGateway \

View File

@ -1,4 +1,4 @@
// generated by deep-copy -pointer-receiver -o ./proxycfg.deepcopy.go -type ConfigSnapshot -type ConfigSnapshotUpstreams -type PeerServersValue -type PeeringServiceValue -type configSnapshotConnectProxy -type configSnapshotIngressGateway -type configSnapshotMeshGateway -type configSnapshotTerminatingGateway ./; DO NOT EDIT.
// generated by deep-copy -pointer-receiver -o ./proxycfg.deepcopy.go -type ConfigSnapshot -type ConfigSnapshotUpstreams -type PeerServersValue -type PeeringServiceValue -type configSnapshotAPIGateway -type configSnapshotConnectProxy -type configSnapshotIngressGateway -type configSnapshotMeshGateway -type configSnapshotTerminatingGateway ./; DO NOT EDIT.
package proxycfg
@ -47,6 +47,10 @@ func (o *ConfigSnapshot) DeepCopy() *ConfigSnapshot {
retV := o.IngressGateway.DeepCopy()
cp.IngressGateway = *retV
}
{
retV := o.APIGateway.DeepCopy()
cp.APIGateway = *retV
}
return &cp
}
@ -209,6 +213,103 @@ func (o *PeeringServiceValue) DeepCopy() *PeeringServiceValue {
return &cp
}
// DeepCopy generates a deep copy of *configSnapshotAPIGateway
func (o *configSnapshotAPIGateway) DeepCopy() *configSnapshotAPIGateway {
var cp configSnapshotAPIGateway = *o
{
retV := o.ConfigSnapshotUpstreams.DeepCopy()
cp.ConfigSnapshotUpstreams = *retV
}
if o.TLSConfig.SDS != nil {
cp.TLSConfig.SDS = new(structs.GatewayTLSSDSConfig)
*cp.TLSConfig.SDS = *o.TLSConfig.SDS
}
if o.TLSConfig.CipherSuites != nil {
cp.TLSConfig.CipherSuites = make([]types.TLSCipherSuite, len(o.TLSConfig.CipherSuites))
copy(cp.TLSConfig.CipherSuites, o.TLSConfig.CipherSuites)
}
if o.GatewayConfig != nil {
cp.GatewayConfig = new(structs.APIGatewayConfigEntry)
*cp.GatewayConfig = *o.GatewayConfig
if o.GatewayConfig.Listeners != nil {
cp.GatewayConfig.Listeners = make([]structs.APIGatewayListener, len(o.GatewayConfig.Listeners))
copy(cp.GatewayConfig.Listeners, o.GatewayConfig.Listeners)
for i4 := range o.GatewayConfig.Listeners {
{
retV := o.GatewayConfig.Listeners[i4].DeepCopy()
cp.GatewayConfig.Listeners[i4] = *retV
}
}
}
{
retV := o.GatewayConfig.Status.DeepCopy()
cp.GatewayConfig.Status = *retV
}
if o.GatewayConfig.Meta != nil {
cp.GatewayConfig.Meta = make(map[string]string, len(o.GatewayConfig.Meta))
for k4, v4 := range o.GatewayConfig.Meta {
cp.GatewayConfig.Meta[k4] = v4
}
}
}
if o.BoundGatewayConfig != nil {
cp.BoundGatewayConfig = o.BoundGatewayConfig.DeepCopy()
}
if o.Hosts != nil {
cp.Hosts = make([]string, len(o.Hosts))
copy(cp.Hosts, o.Hosts)
}
if o.Upstreams != nil {
cp.Upstreams = make(map[IngressListenerKey]structs.Upstreams, len(o.Upstreams))
for k2, v2 := range o.Upstreams {
var cp_Upstreams_v2 structs.Upstreams
if v2 != nil {
cp_Upstreams_v2 = make([]structs.Upstream, len(v2))
copy(cp_Upstreams_v2, v2)
for i3 := range v2 {
{
retV := v2[i3].DeepCopy()
cp_Upstreams_v2[i3] = *retV
}
}
}
cp.Upstreams[k2] = cp_Upstreams_v2
}
}
if o.UpstreamsSet != nil {
cp.UpstreamsSet = make(map[UpstreamID]struct{}, len(o.UpstreamsSet))
for k2, v2 := range o.UpstreamsSet {
cp.UpstreamsSet[k2] = v2
}
}
cp.HTTPRoutes = o.HTTPRoutes.DeepCopy()
cp.TCPRoutes = o.TCPRoutes.DeepCopy()
cp.Certificates = o.Certificates.DeepCopy()
if o.Listeners != nil {
cp.Listeners = make(map[string]structs.APIGatewayListener, len(o.Listeners))
for k2, v2 := range o.Listeners {
var cp_Listeners_v2 structs.APIGatewayListener
{
retV := v2.DeepCopy()
cp_Listeners_v2 = *retV
}
cp.Listeners[k2] = cp_Listeners_v2
}
}
if o.BoundListeners != nil {
cp.BoundListeners = make(map[string]structs.BoundAPIGatewayListener, len(o.BoundListeners))
for k2, v2 := range o.BoundListeners {
var cp_BoundListeners_v2 structs.BoundAPIGatewayListener
{
retV := v2.DeepCopy()
cp_BoundListeners_v2 = *retV
}
cp.BoundListeners[k2] = cp_BoundListeners_v2
}
}
return &cp
}
// DeepCopy generates a deep copy of *configSnapshotConnectProxy
func (o *configSnapshotConnectProxy) DeepCopy() *configSnapshotConnectProxy {
var cp configSnapshotConnectProxy = *o

View File

@ -639,6 +639,65 @@ func (c *configSnapshotMeshGateway) isEmptyPeering() bool {
!c.PeeringTrustBundlesSet
}
type configSnapshotAPIGateway struct {
ConfigSnapshotUpstreams
TLSConfig structs.GatewayTLSConfig
// GatewayConfigLoaded is used to determine if we have received the initial
// api-gateway config entry yet.
GatewayConfigLoaded bool
GatewayConfig *structs.APIGatewayConfigEntry
// BoundGatewayConfigLoaded is used to determine if we have received the initial
// bound-api-gateway config entry yet.
BoundGatewayConfigLoaded bool
BoundGatewayConfig *structs.BoundAPIGatewayConfigEntry
// Hosts is the list of extra host entries to add to our leaf cert's DNS SANs
Hosts []string
AreHostsSet bool
// LeafCertWatchCancel is a CancelFunc to use when refreshing this gateway's
// leaf cert watch with different parameters.
//LeafCertWatchCancel context.CancelFunc
// Upstreams is a list of upstreams this ingress gateway should serve traffic
// to. This is constructed from the ingress-gateway config entry, and uses
// the GatewayServices RPC to retrieve them.
// TODO Determine if this is updated "for free" or not. If not, we might need
// to do some work to populate it in handlerAPIGateway
Upstreams map[IngressListenerKey]structs.Upstreams
// UpstreamsSet is the unique set of UpstreamID the gateway routes to.
UpstreamsSet map[UpstreamID]struct{}
HTTPRoutes watch.Map[structs.ResourceReference, *structs.HTTPRouteConfigEntry]
TCPRoutes watch.Map[structs.ResourceReference, *structs.TCPRouteConfigEntry]
Certificates watch.Map[structs.ResourceReference, *structs.InlineCertificateConfigEntry]
// Listeners is the original listener config from the api-gateway config
// entry to save us trying to pass fields through Upstreams
Listeners map[string]structs.APIGatewayListener
BoundListeners map[string]structs.BoundAPIGatewayListener
}
// ToIngress converts a configSnapshotAPIGateway to a configSnapshotIngressGateway.
// This is temporary, for the sake of re-using existing codepaths when integrating
// Consul API Gateway into Consul core.
//
// FUTURE: Remove when API gateways have custom snapshot generation
func (c *configSnapshotAPIGateway) ToIngress() configSnapshotIngressGateway {
return configSnapshotIngressGateway{
ConfigSnapshotUpstreams: c.ConfigSnapshotUpstreams,
// TODO Build from c.Listeners
// Listeners:
Defaults: structs.IngressServiceConfig{},
}
}
type configSnapshotIngressGateway struct {
ConfigSnapshotUpstreams
@ -687,6 +746,8 @@ func (c *configSnapshotIngressGateway) isEmpty() bool {
!c.MeshConfigSet
}
type APIGatewayListenerKey = IngressListenerKey
type IngressListenerKey struct {
Protocol string
Port int
@ -734,6 +795,9 @@ type ConfigSnapshot struct {
// ingress-gateway specific
IngressGateway configSnapshotIngressGateway
// api-gateway specific
APIGateway configSnapshotAPIGateway
}
// Valid returns whether or not the snapshot has all required fields filled yet.
@ -773,6 +837,14 @@ func (s *ConfigSnapshot) Valid() bool {
s.IngressGateway.GatewayConfigLoaded &&
s.IngressGateway.HostsSet &&
s.IngressGateway.MeshConfigSet
case structs.ServiceKindAPIGateway:
// TODO Is this the proper set of things to validate?
return s.Roots != nil &&
s.APIGateway.GatewayConfigLoaded &&
s.APIGateway.BoundGatewayConfigLoaded &&
s.APIGateway.AreHostsSet &&
s.APIGateway.MeshConfigSet
default:
return false
}
@ -806,6 +878,15 @@ func (s *ConfigSnapshot) Clone() *ConfigSnapshot {
snap.IngressGateway.WatchedDiscoveryChains = nil
// only ingress-gateway
snap.IngressGateway.LeafCertWatchCancel = nil
case structs.ServiceKindAPIGateway:
// common with connect-proxy and api-gateway
snap.APIGateway.WatchedUpstreams = nil
snap.APIGateway.WatchedGateways = nil
snap.APIGateway.WatchedDiscoveryChains = nil
// only api-gateway
//snap.APIGateway.LeafCertWatchCancel = nil
//snap.APIGateway.
}
return snap
@ -817,6 +898,8 @@ func (s *ConfigSnapshot) Leaf() *structs.IssuedCert {
return s.ConnectProxy.Leaf
case structs.ServiceKindIngressGateway:
return s.IngressGateway.Leaf
case structs.ServiceKindAPIGateway:
return s.APIGateway.Leaf
case structs.ServiceKindMeshGateway:
return s.MeshGateway.Leaf
default:
@ -850,6 +933,8 @@ func (s *ConfigSnapshot) MeshConfig() *structs.MeshConfigEntry {
return s.ConnectProxy.MeshConfig
case structs.ServiceKindIngressGateway:
return s.IngressGateway.MeshConfig
case structs.ServiceKindAPIGateway:
return s.APIGateway.MeshConfig
case structs.ServiceKindTerminatingGateway:
return s.TerminatingGateway.MeshConfig
case structs.ServiceKindMeshGateway:
@ -881,6 +966,8 @@ func (s *ConfigSnapshot) ToConfigSnapshotUpstreams() (*ConfigSnapshotUpstreams,
return &s.ConnectProxy.ConfigSnapshotUpstreams, nil
case structs.ServiceKindIngressGateway:
return &s.IngressGateway.ConfigSnapshotUpstreams, nil
case structs.ServiceKindAPIGateway:
return &s.APIGateway.ConfigSnapshotUpstreams, nil
default:
// This is a coherence check and should never fail
return nil, fmt.Errorf("No upstream snapshot for gateway mode %q", s.Kind)

View File

@ -32,6 +32,8 @@ const (
serviceResolversWatchID = "service-resolvers"
gatewayServicesWatchID = "gateway-services"
gatewayConfigWatchID = "gateway-config"
inlineCertificateConfigWatchID = "inline-certificate-config"
routeConfigWatchID = "route-config"
externalServiceIDPrefix = "external-service:"
serviceLeafIDPrefix = "service-leaf:"
serviceConfigIDPrefix = "service-config:"
@ -198,6 +200,8 @@ func newKindHandler(config stateConfig, s serviceInstance, ch chan UpdateEvent)
handler = &handlerMeshGateway{handlerState: h}
case structs.ServiceKindIngressGateway:
handler = &handlerIngressGateway{handlerState: h}
case structs.ServiceKindAPIGateway:
handler = &handlerAPIGateway{handlerState: h}
default:
return nil, errors.New("not a connect-proxy, terminating-gateway, mesh-gateway, or ingress-gateway")
}

View File

@ -63,6 +63,14 @@ func (s *handlerUpstreams) handleUpdateUpstreams(ctx context.Context, u UpdateEv
uid := UpstreamIDFromString(uidString)
switch snap.Kind {
case structs.ServiceKindAPIGateway:
if _, ok := snap.APIGateway.UpstreamsSet[uid]; !ok {
// Discovery chain is not associated with a known explicit or implicit upstream so it is purged/skipped.
// The associated watch was likely cancelled.
delete(upstreamsSnapshot.DiscoveryChain, uid)
s.logger.Trace("discovery-chain watch fired for unknown upstream", "upstream", uid)
return nil
}
case structs.ServiceKindIngressGateway:
if _, ok := snap.IngressGateway.UpstreamsSet[uid]; !ok {
// Discovery chain is not associated with a known explicit or implicit upstream so it is purged/skipped.
@ -533,6 +541,8 @@ type discoveryChainWatchOpts struct {
func (s *handlerUpstreams) watchDiscoveryChain(ctx context.Context, snap *ConfigSnapshot, opts discoveryChainWatchOpts) error {
var watchedDiscoveryChains map[UpstreamID]context.CancelFunc
switch s.kind {
case structs.ServiceKindAPIGateway:
watchedDiscoveryChains = snap.APIGateway.WatchedDiscoveryChains
case structs.ServiceKindIngressGateway:
watchedDiscoveryChains = snap.IngressGateway.WatchedDiscoveryChains
case structs.ServiceKindConnectProxy:

View File

@ -704,6 +704,7 @@ type APIGatewayConfigEntry struct {
// Listeners is the set of listener configuration to which an API Gateway
// might bind.
Listeners []APIGatewayListener
// Status is the asynchronous status which an APIGateway propagates to the user.
Status Status
@ -862,16 +863,16 @@ const (
// APIGatewayListener represents an individual listener for an APIGateway
type APIGatewayListener struct {
// Name is the optional name of the listener in a given gateway. This is
// optional, however, it must be unique. Therefore, if a gateway has more
// than a single listener, all but one must specify a Name.
// optional but must be unique within a gateway; therefore, if a gateway
// has more than a single listener, all but one must specify a Name.
Name string
// Hostname is the host name that a listener should be bound to, if
// Hostname is the host name that a listener should be bound to. If
// unspecified, the listener accepts requests for all hostnames.
Hostname string
// Port is the port at which this listener should bind.
Port int
// Protocol is the protocol that a listener should use, it must
// either be http or tcp
// Protocol is the protocol that a listener should use. It must
// either be http or tcp.
Protocol APIGatewayListenerProtocol
// TLS is the TLS settings for the listener.
TLS APIGatewayTLSConfiguration

View File

@ -244,6 +244,10 @@ type HTTPService struct {
acl.EnterpriseMeta
}
func (s HTTPService) ServiceName() ServiceName {
return NewServiceName(s.Name, &s.EnterpriseMeta)
}
var _ ControlledConfigEntry = (*HTTPRouteConfigEntry)(nil)
func (e *HTTPRouteConfigEntry) GetStatus() Status {
@ -398,3 +402,7 @@ type TCPService struct {
acl.EnterpriseMeta
}
func (s TCPService) ServiceName() ServiceName {
return NewServiceName(s.Name, &s.EnterpriseMeta)
}

View File

@ -7,6 +7,8 @@ cd $PACKAGE_DIR
deep-copy \
-pointer-receiver \
-o ./structs.deepcopy.go \
-type APIGatewayListener \
-type BoundAPIGatewayListener \
-type CARoot \
-type CheckServiceNode \
-type CheckType \
@ -21,10 +23,12 @@ deep-copy \
-type GatewayService \
-type GatewayServiceTLSConfig \
-type HTTPHeaderModifiers \
-type HTTPRouteConfigEntry \
-type HashPolicy \
-type HealthCheck \
-type IndexedCARoots \
-type IngressListener \
-type InlineCertificateConfigEntry \
-type Intention \
-type IntentionPermission \
-type LoadBalancer \
@ -43,6 +47,7 @@ deep-copy \
-type ServiceRoute \
-type ServiceRouteDestination \
-type ServiceRouteMatch \
-type TCPRouteConfigEntry \
-type Upstream \
-type UpstreamConfiguration \
-type Status \

View File

@ -1,4 +1,4 @@
// generated by deep-copy -pointer-receiver -o ./structs.deepcopy.go -type CARoot -type CheckServiceNode -type CheckType -type CompiledDiscoveryChain -type ConnectProxyConfig -type DiscoveryFailover -type DiscoveryGraphNode -type DiscoveryResolver -type DiscoveryRoute -type DiscoverySplit -type ExposeConfig -type GatewayService -type GatewayServiceTLSConfig -type HTTPHeaderModifiers -type HashPolicy -type HealthCheck -type IndexedCARoots -type IngressListener -type Intention -type IntentionPermission -type LoadBalancer -type MeshConfigEntry -type MeshDirectionalTLSConfig -type MeshTLSConfig -type Node -type NodeService -type PeeringServiceMeta -type ServiceConfigEntry -type ServiceConfigResponse -type ServiceConnect -type ServiceDefinition -type ServiceResolverConfigEntry -type ServiceResolverFailover -type ServiceRoute -type ServiceRouteDestination -type ServiceRouteMatch -type Upstream -type UpstreamConfiguration -type Status -type BoundAPIGatewayConfigEntry ./; DO NOT EDIT.
// generated by deep-copy -pointer-receiver -o ./structs.deepcopy.go -type APIGatewayListener -type BoundAPIGatewayListener -type CARoot -type CheckServiceNode -type CheckType -type CompiledDiscoveryChain -type ConnectProxyConfig -type DiscoveryFailover -type DiscoveryGraphNode -type DiscoveryResolver -type DiscoveryRoute -type DiscoverySplit -type ExposeConfig -type GatewayService -type GatewayServiceTLSConfig -type HTTPHeaderModifiers -type HTTPRouteConfigEntry -type HashPolicy -type HealthCheck -type IndexedCARoots -type IngressListener -type InlineCertificateConfigEntry -type Intention -type IntentionPermission -type LoadBalancer -type MeshConfigEntry -type MeshDirectionalTLSConfig -type MeshTLSConfig -type Node -type NodeService -type PeeringServiceMeta -type ServiceConfigEntry -type ServiceConfigResponse -type ServiceConnect -type ServiceDefinition -type ServiceResolverConfigEntry -type ServiceResolverFailover -type ServiceRoute -type ServiceRouteDestination -type ServiceRouteMatch -type TCPRouteConfigEntry -type Upstream -type UpstreamConfiguration -type Status -type BoundAPIGatewayConfigEntry ./; DO NOT EDIT.
package structs
@ -7,6 +7,34 @@ import (
"time"
)
// DeepCopy generates a deep copy of *APIGatewayListener
func (o *APIGatewayListener) DeepCopy() *APIGatewayListener {
var cp APIGatewayListener = *o
if o.TLS.Certificates != nil {
cp.TLS.Certificates = make([]ResourceReference, len(o.TLS.Certificates))
copy(cp.TLS.Certificates, o.TLS.Certificates)
}
if o.TLS.CipherSuites != nil {
cp.TLS.CipherSuites = make([]types.TLSCipherSuite, len(o.TLS.CipherSuites))
copy(cp.TLS.CipherSuites, o.TLS.CipherSuites)
}
return &cp
}
// DeepCopy generates a deep copy of *BoundAPIGatewayListener
func (o *BoundAPIGatewayListener) DeepCopy() *BoundAPIGatewayListener {
var cp BoundAPIGatewayListener = *o
if o.Routes != nil {
cp.Routes = make([]ResourceReference, len(o.Routes))
copy(cp.Routes, o.Routes)
}
if o.Certificates != nil {
cp.Certificates = make([]ResourceReference, len(o.Certificates))
copy(cp.Certificates, o.Certificates)
}
return &cp
}
// DeepCopy generates a deep copy of *CARoot
func (o *CARoot) DeepCopy() *CARoot {
var cp CARoot = *o
@ -268,6 +296,100 @@ func (o *HTTPHeaderModifiers) DeepCopy() *HTTPHeaderModifiers {
return &cp
}
// DeepCopy generates a deep copy of *HTTPRouteConfigEntry
func (o *HTTPRouteConfigEntry) DeepCopy() *HTTPRouteConfigEntry {
var cp HTTPRouteConfigEntry = *o
if o.Parents != nil {
cp.Parents = make([]ResourceReference, len(o.Parents))
copy(cp.Parents, o.Parents)
}
if o.Rules != nil {
cp.Rules = make([]HTTPRouteRule, len(o.Rules))
copy(cp.Rules, o.Rules)
for i2 := range o.Rules {
if o.Rules[i2].Filters.Headers != nil {
cp.Rules[i2].Filters.Headers = make([]HTTPHeaderFilter, len(o.Rules[i2].Filters.Headers))
copy(cp.Rules[i2].Filters.Headers, o.Rules[i2].Filters.Headers)
for i5 := range o.Rules[i2].Filters.Headers {
if o.Rules[i2].Filters.Headers[i5].Add != nil {
cp.Rules[i2].Filters.Headers[i5].Add = make(map[string]string, len(o.Rules[i2].Filters.Headers[i5].Add))
for k7, v7 := range o.Rules[i2].Filters.Headers[i5].Add {
cp.Rules[i2].Filters.Headers[i5].Add[k7] = v7
}
}
if o.Rules[i2].Filters.Headers[i5].Remove != nil {
cp.Rules[i2].Filters.Headers[i5].Remove = make([]string, len(o.Rules[i2].Filters.Headers[i5].Remove))
copy(cp.Rules[i2].Filters.Headers[i5].Remove, o.Rules[i2].Filters.Headers[i5].Remove)
}
if o.Rules[i2].Filters.Headers[i5].Set != nil {
cp.Rules[i2].Filters.Headers[i5].Set = make(map[string]string, len(o.Rules[i2].Filters.Headers[i5].Set))
for k7, v7 := range o.Rules[i2].Filters.Headers[i5].Set {
cp.Rules[i2].Filters.Headers[i5].Set[k7] = v7
}
}
}
}
if o.Rules[i2].Matches != nil {
cp.Rules[i2].Matches = make([]HTTPMatch, len(o.Rules[i2].Matches))
copy(cp.Rules[i2].Matches, o.Rules[i2].Matches)
for i4 := range o.Rules[i2].Matches {
if o.Rules[i2].Matches[i4].Headers != nil {
cp.Rules[i2].Matches[i4].Headers = make([]HTTPHeaderMatch, len(o.Rules[i2].Matches[i4].Headers))
copy(cp.Rules[i2].Matches[i4].Headers, o.Rules[i2].Matches[i4].Headers)
}
if o.Rules[i2].Matches[i4].Query != nil {
cp.Rules[i2].Matches[i4].Query = make([]HTTPQueryMatch, len(o.Rules[i2].Matches[i4].Query))
copy(cp.Rules[i2].Matches[i4].Query, o.Rules[i2].Matches[i4].Query)
}
}
}
if o.Rules[i2].Services != nil {
cp.Rules[i2].Services = make([]HTTPService, len(o.Rules[i2].Services))
copy(cp.Rules[i2].Services, o.Rules[i2].Services)
for i4 := range o.Rules[i2].Services {
if o.Rules[i2].Services[i4].Filters.Headers != nil {
cp.Rules[i2].Services[i4].Filters.Headers = make([]HTTPHeaderFilter, len(o.Rules[i2].Services[i4].Filters.Headers))
copy(cp.Rules[i2].Services[i4].Filters.Headers, o.Rules[i2].Services[i4].Filters.Headers)
for i7 := range o.Rules[i2].Services[i4].Filters.Headers {
if o.Rules[i2].Services[i4].Filters.Headers[i7].Add != nil {
cp.Rules[i2].Services[i4].Filters.Headers[i7].Add = make(map[string]string, len(o.Rules[i2].Services[i4].Filters.Headers[i7].Add))
for k9, v9 := range o.Rules[i2].Services[i4].Filters.Headers[i7].Add {
cp.Rules[i2].Services[i4].Filters.Headers[i7].Add[k9] = v9
}
}
if o.Rules[i2].Services[i4].Filters.Headers[i7].Remove != nil {
cp.Rules[i2].Services[i4].Filters.Headers[i7].Remove = make([]string, len(o.Rules[i2].Services[i4].Filters.Headers[i7].Remove))
copy(cp.Rules[i2].Services[i4].Filters.Headers[i7].Remove, o.Rules[i2].Services[i4].Filters.Headers[i7].Remove)
}
if o.Rules[i2].Services[i4].Filters.Headers[i7].Set != nil {
cp.Rules[i2].Services[i4].Filters.Headers[i7].Set = make(map[string]string, len(o.Rules[i2].Services[i4].Filters.Headers[i7].Set))
for k9, v9 := range o.Rules[i2].Services[i4].Filters.Headers[i7].Set {
cp.Rules[i2].Services[i4].Filters.Headers[i7].Set[k9] = v9
}
}
}
}
}
}
}
}
if o.Hostnames != nil {
cp.Hostnames = make([]string, len(o.Hostnames))
copy(cp.Hostnames, o.Hostnames)
}
if o.Meta != nil {
cp.Meta = make(map[string]string, len(o.Meta))
for k2, v2 := range o.Meta {
cp.Meta[k2] = v2
}
}
{
retV := o.Status.DeepCopy()
cp.Status = *retV
}
return &cp
}
// DeepCopy generates a deep copy of *HashPolicy
func (o *HashPolicy) DeepCopy() *HashPolicy {
var cp HashPolicy = *o
@ -369,6 +491,18 @@ func (o *IngressListener) DeepCopy() *IngressListener {
return &cp
}
// DeepCopy generates a deep copy of *InlineCertificateConfigEntry
func (o *InlineCertificateConfigEntry) DeepCopy() *InlineCertificateConfigEntry {
var cp InlineCertificateConfigEntry = *o
if o.Meta != nil {
cp.Meta = make(map[string]string, len(o.Meta))
for k2, v2 := range o.Meta {
cp.Meta[k2] = v2
}
}
return &cp
}
// DeepCopy generates a deep copy of *Intention
func (o *Intention) DeepCopy() *Intention {
var cp Intention = *o
@ -809,6 +943,30 @@ func (o *ServiceRouteMatch) DeepCopy() *ServiceRouteMatch {
return &cp
}
// DeepCopy generates a deep copy of *TCPRouteConfigEntry
func (o *TCPRouteConfigEntry) DeepCopy() *TCPRouteConfigEntry {
var cp TCPRouteConfigEntry = *o
if o.Parents != nil {
cp.Parents = make([]ResourceReference, len(o.Parents))
copy(cp.Parents, o.Parents)
}
if o.Services != nil {
cp.Services = make([]TCPService, len(o.Services))
copy(cp.Services, o.Services)
}
if o.Meta != nil {
cp.Meta = make(map[string]string, len(o.Meta))
for k2, v2 := range o.Meta {
cp.Meta[k2] = v2
}
}
{
retV := o.Status.DeepCopy()
cp.Status = *retV
}
return &cp
}
// DeepCopy generates a deep copy of *Upstream
func (o *Upstream) DeepCopy() *Upstream {
var cp Upstream = *o
@ -920,13 +1078,9 @@ func (o *BoundAPIGatewayConfigEntry) DeepCopy() *BoundAPIGatewayConfigEntry {
cp.Listeners = make([]BoundAPIGatewayListener, len(o.Listeners))
copy(cp.Listeners, o.Listeners)
for i2 := range o.Listeners {
if o.Listeners[i2].Routes != nil {
cp.Listeners[i2].Routes = make([]ResourceReference, len(o.Listeners[i2].Routes))
copy(cp.Listeners[i2].Routes, o.Listeners[i2].Routes)
}
if o.Listeners[i2].Certificates != nil {
cp.Listeners[i2].Certificates = make([]ResourceReference, len(o.Listeners[i2].Certificates))
copy(cp.Listeners[i2].Certificates, o.Listeners[i2].Certificates)
{
retV := o.Listeners[i2].DeepCopy()
cp.Listeners[i2] = *retV
}
}
}

View File

@ -1193,7 +1193,8 @@ func (k ServiceKind) IsProxy() bool {
case ServiceKindConnectProxy,
ServiceKindMeshGateway,
ServiceKindTerminatingGateway,
ServiceKindIngressGateway:
ServiceKindIngressGateway,
ServiceKindAPIGateway:
return true
}
return false
@ -1206,26 +1207,31 @@ const (
// default to the typical service.
ServiceKindTypical ServiceKind = ""
// ServiceKindConnectProxy is a proxy for the Connect feature. This
// ServiceKindConnectProxy is a proxy for the Consul Service Mesh. This
// service proxies another service within Consul and speaks the connect
// protocol.
ServiceKindConnectProxy ServiceKind = "connect-proxy"
// ServiceKindMeshGateway is a Mesh Gateway for the Connect feature. This
// service will proxy connections based off the SNI header set by other
// ServiceKindMeshGateway is a Mesh Gateway for the Consul Service Mesh.
// This service will proxy connections based off the SNI header set by other
// connect proxies
ServiceKindMeshGateway ServiceKind = "mesh-gateway"
// ServiceKindTerminatingGateway is a Terminating Gateway for the Connect
// feature. This service will proxy connections to services outside the mesh.
// ServiceKindTerminatingGateway is a Terminating Gateway for the Consul Service
// Mesh feature. This service will proxy connections to services outside the mesh.
ServiceKindTerminatingGateway ServiceKind = "terminating-gateway"
// ServiceKindIngressGateway is an Ingress Gateway for the Connect feature.
// ServiceKindIngressGateway is an Ingress Gateway for the Consul Service Mesh.
// This service allows external traffic to enter the mesh based on
// centralized configuration.
ServiceKindIngressGateway ServiceKind = "ingress-gateway"
// ServiceKindDestination is a Destination for the Connect feature.
// ServiceKindAPIGateway is an API Gateway for the Consul Service Mesh.
// This service allows external traffic to enter the mesh based on
// centralized configuration.
ServiceKindAPIGateway ServiceKind = "api-gateway"
// ServiceKindDestination is a Destination for the Consul Service Mesh feature.
// This service allows external traffic to exit the mesh through a terminating gateway
// based on centralized configuration.
ServiceKindDestination ServiceKind = "destination"
@ -1424,7 +1430,8 @@ func (s *NodeService) IsSidecarProxy() bool {
func (s *NodeService) IsGateway() bool {
return s.Kind == ServiceKindMeshGateway ||
s.Kind == ServiceKindTerminatingGateway ||
s.Kind == ServiceKindIngressGateway
s.Kind == ServiceKindIngressGateway ||
s.Kind == ServiceKindAPIGateway
}
// Validate validates the node service configuration.

View File

@ -61,6 +61,14 @@ func (s *ResourceGenerator) clustersFromSnapshot(cfgSnap *proxycfg.ConfigSnapsho
return nil, err
}
return res, nil
case structs.ServiceKindAPIGateway:
// TODO Find a cleaner solution, can't currently pass unexported property types
cfgSnap.IngressGateway = cfgSnap.APIGateway.ToIngress()
res, err := s.clustersFromSnapshotIngressGateway(cfgSnap)
if err != nil {
return nil, err
}
return res, nil
default:
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
}

View File

@ -129,19 +129,24 @@ func (s *Server) processDelta(stream ADSDeltaStream, reqCh <-chan *envoy_discove
// Configure handlers for each type of request we currently care about.
handlers := map[string]*xDSDeltaType{
xdscommon.ListenerType: newDeltaType(generator, stream, xdscommon.ListenerType, func(kind structs.ServiceKind) bool {
return cfgSnap.Kind == structs.ServiceKindIngressGateway
// Ingress and API gateways are allowed to inform LDS of no listeners.
return cfgSnap.Kind == structs.ServiceKindIngressGateway ||
cfgSnap.Kind == structs.ServiceKindAPIGateway
}),
xdscommon.RouteType: newDeltaType(generator, stream, xdscommon.RouteType, func(kind structs.ServiceKind) bool {
return cfgSnap.Kind == structs.ServiceKindIngressGateway
// Ingress and API gateways are allowed to inform RDS of no routes.
return cfgSnap.Kind == structs.ServiceKindIngressGateway ||
cfgSnap.Kind == structs.ServiceKindAPIGateway
}),
xdscommon.ClusterType: newDeltaType(generator, stream, xdscommon.ClusterType, func(kind structs.ServiceKind) bool {
// Mesh, Ingress, and Terminating gateways are allowed to inform CDS of
// no clusters.
// Mesh, Ingress, API and Terminating gateways are allowed to inform CDS of no clusters.
return cfgSnap.Kind == structs.ServiceKindMeshGateway ||
cfgSnap.Kind == structs.ServiceKindTerminatingGateway ||
cfgSnap.Kind == structs.ServiceKindIngressGateway
cfgSnap.Kind == structs.ServiceKindIngressGateway ||
cfgSnap.Kind == structs.ServiceKindAPIGateway
}),
xdscommon.EndpointType: newDeltaType(generator, stream, xdscommon.EndpointType, nil),
xdscommon.SecretType: newDeltaType(generator, stream, xdscommon.SecretType, nil), // TODO allowEmptyFn
}
// Endpoints are stored within a Cluster (and Routes
@ -332,7 +337,7 @@ func (s *Server) processDelta(stream ADSDeltaStream, reqCh <-chan *envoy_discove
generator.Logger.Trace("Got initial config snapshot")
// Lets actually process the config we just got or we'll mis responding
// Let's actually process the config we just got, or we'll miss responding
fallthrough
case stateDeltaRunning:
// Check ACLs on every Discovery{Request,Response}.
@ -462,6 +467,8 @@ func (s *Server) applyEnvoyExtensions(resources *xdscommon.IndexedResources, cfg
}
var xDSUpdateOrder = []xDSUpdateOperation{
// TODO Update comments
{TypeUrl: xdscommon.SecretType, Upsert: true},
// 1. CDS updates (if any) must always be pushed first.
{TypeUrl: xdscommon.ClusterType, Upsert: true},
// 2. EDS updates (if any) must arrive after CDS updates for the respective clusters.
@ -472,9 +479,10 @@ var xDSUpdateOrder = []xDSUpdateOperation{
{TypeUrl: xdscommon.RouteType, Upsert: true, Remove: true},
// 5. (NOT IMPLEMENTED YET IN CONSUL) VHDS updates (if any) related to the newly added RouteConfigurations must arrive after RDS updates.
// {},
// 6. Stale CDS clusters and related EDS endpoints (ones no longer being referenced) can then be removed.
// 6. Stale CDS clusters, related EDS endpoints (ones no longer being referenced) and SDS secrets can then be removed.
{TypeUrl: xdscommon.ClusterType, Remove: true},
{TypeUrl: xdscommon.EndpointType, Remove: true},
{TypeUrl: xdscommon.SecretType, Remove: true},
// xDS updates can be pushed independently if no new
// clusters/routes/listeners are added or if its acceptable to
// temporarily drop traffic during updates. Note that in case of

View File

@ -37,6 +37,10 @@ func (s *ResourceGenerator) endpointsFromSnapshot(cfgSnap *proxycfg.ConfigSnapsh
return s.endpointsFromSnapshotMeshGateway(cfgSnap)
case structs.ServiceKindIngressGateway:
return s.endpointsFromSnapshotIngressGateway(cfgSnap)
case structs.ServiceKindAPIGateway:
// TODO Find a cleaner solution, can't currently pass unexported property types
cfgSnap.IngressGateway = cfgSnap.APIGateway.ToIngress()
return s.endpointsFromSnapshotIngressGateway(cfgSnap)
default:
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
}

View File

@ -58,11 +58,10 @@ func (s *ResourceGenerator) listenersFromSnapshot(cfgSnap *proxycfg.ConfigSnapsh
switch cfgSnap.Kind {
case structs.ServiceKindConnectProxy:
return s.listenersFromSnapshotConnectProxy(cfgSnap)
case structs.ServiceKindTerminatingGateway:
return s.listenersFromSnapshotGateway(cfgSnap)
case structs.ServiceKindMeshGateway:
return s.listenersFromSnapshotGateway(cfgSnap)
case structs.ServiceKindIngressGateway:
case structs.ServiceKindTerminatingGateway,
structs.ServiceKindMeshGateway,
structs.ServiceKindIngressGateway,
structs.ServiceKindAPIGateway:
return s.listenersFromSnapshotGateway(cfgSnap)
default:
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
@ -849,6 +848,14 @@ func (s *ResourceGenerator) listenersFromSnapshotGateway(cfgSnap *proxycfg.Confi
if err != nil {
return nil, err
}
case structs.ServiceKindAPIGateway:
// TODO Find a cleaner solution, can't currently pass unexported property types
cfgSnap.IngressGateway = cfgSnap.APIGateway.ToIngress()
listeners, err := s.makeIngressGatewayListeners(a.Address, cfgSnap)
if err != nil {
return nil, err
}
resources = append(resources, listeners...)
case structs.ServiceKindIngressGateway:
listeners, err := s.makeIngressGatewayListeners(a.Address, cfgSnap)
if err != nil {

View File

@ -3,10 +3,11 @@ package xds
import (
"fmt"
"github.com/hashicorp/consul/envoyextensions/xdscommon"
"github.com/hashicorp/go-hclog"
"google.golang.org/protobuf/proto"
"github.com/hashicorp/consul/envoyextensions/xdscommon"
"github.com/hashicorp/consul/agent/proxycfg"
)
@ -34,6 +35,7 @@ func NewResourceGenerator(
func (g *ResourceGenerator) AllResourcesFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) (map[string][]proto.Message, error) {
all := make(map[string][]proto.Message)
// TODO Add xdscommon.SecretType
for _, typeUrl := range []string{xdscommon.ListenerType, xdscommon.RouteType, xdscommon.ClusterType, xdscommon.EndpointType} {
res, err := g.resourcesFromSnapshot(typeUrl, cfgSnap)
if err != nil {
@ -54,6 +56,8 @@ func (g *ResourceGenerator) resourcesFromSnapshot(typeUrl string, cfgSnap *proxy
return g.clustersFromSnapshot(cfgSnap)
case xdscommon.EndpointType:
return g.endpointsFromSnapshot(cfgSnap)
case xdscommon.SecretType:
return g.secretsFromSnapshot(cfgSnap)
default:
return nil, fmt.Errorf("unknown typeUrl: %s", typeUrl)
}

View File

@ -32,6 +32,10 @@ func (s *ResourceGenerator) routesFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot)
return s.routesForConnectProxy(cfgSnap)
case structs.ServiceKindIngressGateway:
return s.routesForIngressGateway(cfgSnap)
case structs.ServiceKindAPIGateway:
// TODO Find a cleaner solution, can't currently pass unexported property types
cfgSnap.IngressGateway = cfgSnap.APIGateway.ToIngress()
return s.routesForIngressGateway(cfgSnap)
case structs.ServiceKindTerminatingGateway:
return s.routesForTerminatingGateway(cfgSnap)
case structs.ServiceKindMeshGateway:

38
agent/xds/secrets.go Normal file
View File

@ -0,0 +1,38 @@
package xds
import (
"errors"
"fmt"
"google.golang.org/protobuf/proto"
"github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs"
)
// secretsFromSnapshot returns the xDS API representation of the "secrets"
// in the snapshot
func (s *ResourceGenerator) secretsFromSnapshot(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
if cfgSnap == nil {
return nil, errors.New("nil config given")
}
switch cfgSnap.Kind {
case structs.ServiceKindConnectProxy,
structs.ServiceKindTerminatingGateway,
structs.ServiceKindMeshGateway,
structs.ServiceKindIngressGateway:
return nil, nil
// Only API gateways utilize secrets
case structs.ServiceKindAPIGateway:
return s.secretsFromSnapshotAPIGateway(cfgSnap)
default:
return nil, fmt.Errorf("Invalid service kind: %v", cfgSnap.Kind)
}
}
func (s *ResourceGenerator) secretsFromSnapshotAPIGateway(cfgSnap *proxycfg.ConfigSnapshot) ([]proto.Message, error) {
var res []proto.Message
// TODO
return res, nil
}

View File

@ -229,7 +229,7 @@ func (s *Server) authorize(ctx context.Context, cfgSnap *proxycfg.ConfigSnapshot
if err := authz.ToAllowAuthorizer().ServiceWriteAllowed(cfgSnap.Proxy.DestinationServiceName, &authzContext); err != nil {
return status.Errorf(codes.PermissionDenied, err.Error())
}
case structs.ServiceKindMeshGateway, structs.ServiceKindTerminatingGateway, structs.ServiceKindIngressGateway:
case structs.ServiceKindMeshGateway, structs.ServiceKindTerminatingGateway, structs.ServiceKindIngressGateway, structs.ServiceKindAPIGateway:
cfgSnap.ProxyID.EnterpriseMeta.FillAuthzContext(&authzContext)
if err := authz.ToAllowAuthorizer().ServiceWriteAllowed(cfgSnap.Service, &authzContext); err != nil {
return status.Errorf(codes.PermissionDenied, err.Error())

View File

@ -46,6 +46,9 @@ const (
// ListenerType is the TypeURL for Listener discovery responses.
ListenerType = apiTypePrefix + "envoy.config.listener.v3.Listener"
// SecretType is the TypeURL for Secret discovery responses.
SecretType = apiTypePrefix + "envoy.extensions.transport_sockets.tls.v3.Secret"
)
type IndexedResources struct {

View File

@ -102,6 +102,9 @@ const (
// ServiceKind Ingress Gateway is an Ingress Gateway for the Connect feature.
// This service will ingress connections into the service mesh.
ServiceKind_SERVICE_KIND_INGRESS_GATEWAY ServiceKind = 5
// ServiceKind API Gateway is an API Gateway for the Connect feature.
// This service will ingress connections in to the service mesh.
ServiceKind_SERVICE_KIND_API_GATEWAY ServiceKind = 6
)
// Enum value maps for ServiceKind.
@ -113,6 +116,7 @@ var (
3: "SERVICE_KIND_MESH_GATEWAY",
4: "SERVICE_KIND_TERMINATING_GATEWAY",
5: "SERVICE_KIND_INGRESS_GATEWAY",
6: "SERVICE_KIND_API_GATEWAY",
}
ServiceKind_value = map[string]int32{
"SERVICE_KIND_UNSPECIFIED": 0,
@ -121,6 +125,7 @@ var (
"SERVICE_KIND_MESH_GATEWAY": 3,
"SERVICE_KIND_TERMINATING_GATEWAY": 4,
"SERVICE_KIND_INGRESS_GATEWAY": 5,
"SERVICE_KIND_API_GATEWAY": 6,
}
)
@ -593,7 +598,7 @@ var file_proto_public_pbdataplane_dataplane_proto_rawDesc = []byte{
0x4e, 0x54, 0x10, 0x02, 0x12, 0x34, 0x0a, 0x30, 0x44, 0x41, 0x54, 0x41, 0x50, 0x4c, 0x41, 0x4e,
0x45, 0x5f, 0x46, 0x45, 0x41, 0x54, 0x55, 0x52, 0x45, 0x53, 0x5f, 0x45, 0x4e, 0x56, 0x4f, 0x59,
0x5f, 0x42, 0x4f, 0x4f, 0x54, 0x53, 0x54, 0x52, 0x41, 0x50, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49,
0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x2a, 0xcc, 0x01, 0x0a, 0x0b, 0x53,
0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x2a, 0xea, 0x01, 0x0a, 0x0b, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45,
0x52, 0x56, 0x49, 0x43, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45,
0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x45, 0x52, 0x56,
@ -606,45 +611,47 @@ var file_proto_public_pbdataplane_dataplane_proto_rawDesc = []byte{
0x44, 0x5f, 0x54, 0x45, 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x49, 0x4e, 0x47, 0x5f, 0x47, 0x41,
0x54, 0x45, 0x57, 0x41, 0x59, 0x10, 0x04, 0x12, 0x20, 0x0a, 0x1c, 0x53, 0x45, 0x52, 0x56, 0x49,
0x43, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x49, 0x4e, 0x47, 0x52, 0x45, 0x53, 0x53, 0x5f,
0x47, 0x41, 0x54, 0x45, 0x57, 0x41, 0x59, 0x10, 0x05, 0x32, 0xde, 0x02, 0x0a, 0x10, 0x44, 0x61,
0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xac,
0x01, 0x0a, 0x1d, 0x47, 0x65, 0x74, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x44,
0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73,
0x12, 0x40, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e,
0x47, 0x41, 0x54, 0x45, 0x57, 0x41, 0x59, 0x10, 0x05, 0x12, 0x1c, 0x0a, 0x18, 0x53, 0x45, 0x52,
0x56, 0x49, 0x43, 0x45, 0x5f, 0x4b, 0x49, 0x4e, 0x44, 0x5f, 0x41, 0x50, 0x49, 0x5f, 0x47, 0x41,
0x54, 0x45, 0x57, 0x41, 0x59, 0x10, 0x06, 0x32, 0xde, 0x02, 0x0a, 0x10, 0x44, 0x61, 0x74, 0x61,
0x70, 0x6c, 0x61, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xac, 0x01, 0x0a,
0x1d, 0x47, 0x65, 0x74, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74,
0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x40,
0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75,
0x6c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x53,
0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e,
0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x41, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e,
0x73, 0x75, 0x6c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x47, 0x65,
0x74, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c,
0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x41, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63,
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e,
0x47, 0x65, 0x74, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61,
0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73,
0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x06, 0xe2, 0x86, 0x04, 0x02, 0x08, 0x02, 0x12, 0x9a, 0x01,
0x0a, 0x17, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74,
0x72, 0x61, 0x70, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68,
0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x64, 0x61, 0x74,
0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x42,
0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61,
0x6e, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x42, 0x6f, 0x6f, 0x74, 0x73,
0x74, 0x72, 0x61, 0x70, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x06, 0xe2, 0x86, 0x04, 0x02, 0x08, 0x02, 0x42, 0xf0, 0x01, 0x0a, 0x1e, 0x63,
0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e,
0x73, 0x75, 0x6c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x42, 0x0e, 0x44,
0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a,
0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68,
0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x64, 0x61, 0x74, 0x61,
0x70, 0x6c, 0x61, 0x6e, 0x65, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x44, 0xaa, 0x02, 0x1a, 0x48, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x44,
0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0xca, 0x02, 0x1a, 0x48, 0x61, 0x73, 0x68, 0x69,
0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x44, 0x61, 0x74, 0x61,
0x70, 0x6c, 0x61, 0x6e, 0x65, 0xe2, 0x02, 0x26, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61,
0x6e, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02,
0x1c, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73,
0x75, 0x6c, 0x3a, 0x3a, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x22, 0x06, 0xe2, 0x86, 0x04, 0x02, 0x08, 0x02, 0x12, 0x9a, 0x01, 0x0a, 0x17,
0x47, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72, 0x61,
0x70, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70,
0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x42, 0x6f, 0x6f,
0x74, 0x73, 0x74, 0x72, 0x61, 0x70, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x3b, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65,
0x2e, 0x47, 0x65, 0x74, 0x45, 0x6e, 0x76, 0x6f, 0x79, 0x42, 0x6f, 0x6f, 0x74, 0x73, 0x74, 0x72,
0x61, 0x70, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
0x22, 0x06, 0xe2, 0x86, 0x04, 0x02, 0x08, 0x02, 0x42, 0xf0, 0x01, 0x0a, 0x1e, 0x63, 0x6f, 0x6d,
0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75,
0x6c, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x42, 0x0e, 0x44, 0x61, 0x74,
0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x34, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c,
0x61, 0x6e, 0x65, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x44, 0xaa, 0x02, 0x1a, 0x48, 0x61, 0x73, 0x68,
0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x44, 0x61, 0x74,
0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0xca, 0x02, 0x1a, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c,
0x61, 0x6e, 0x65, 0xe2, 0x02, 0x26, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c,
0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65,
0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x1c, 0x48,
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x3a, 0x3a, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x33,
}
var (

View File

@ -65,6 +65,10 @@ enum ServiceKind {
// ServiceKind Ingress Gateway is an Ingress Gateway for the Connect feature.
// This service will ingress connections into the service mesh.
SERVICE_KIND_INGRESS_GATEWAY = 5;
// ServiceKind API Gateway is an API Gateway for the Connect feature.
// This service will ingress connections in to the service mesh.
SERVICE_KIND_API_GATEWAY = 6;
}
message GetEnvoyBootstrapParamsResponse {