Skip to content

Commit

Permalink
sidecar-proxy controller: Add support for transparent proxy
Browse files Browse the repository at this point in the history
This currently does not support inferring destinations from intentions.
  • Loading branch information
ishustava committed Aug 14, 2023
1 parent d6000f3 commit 6ed3012
Show file tree
Hide file tree
Showing 32 changed files with 1,854 additions and 478 deletions.
1 change: 1 addition & 0 deletions agent/consul/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,7 @@ func (s *Server) registerControllers(deps Deps) {

return s.getTrustDomain(caConfig)
},
LocalDatacenter: s.config.Datacenter,
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import (
"github.com/hashicorp/consul/proto-public/pbresource"
)

// Cache stores information needed for the sidecar-proxy controller to reconcile efficiently.
// DestinationsCache stores information needed for the sidecar-proxy controller to reconcile efficiently.
// This currently means storing a list of all destinations for easy look up
// as well as indices of source proxies where those destinations are referenced.
//
// It is the responsibility of the controller and its subcomponents (like mapper and data fetcher)
// to keep this cache up-to-date as we're observing new data.
type Cache struct {
type DestinationsCache struct {
lock sync.RWMutex

// store is a map from destination service reference and port as a reference key
Expand All @@ -30,8 +30,8 @@ type Cache struct {

type storeKeys map[ReferenceKeyWithPort]struct{}

func New() *Cache {
return &Cache{
func NewDestinationsCache() *DestinationsCache {
return &DestinationsCache{
store: make(map[ReferenceKeyWithPort]intermediate.CombinedDestinationRef),
sourceProxiesIndex: make(map[resource.ReferenceKey]storeKeys),
}
Expand All @@ -48,7 +48,7 @@ func KeyFromRefAndPort(ref *pbresource.Reference, port string) ReferenceKeyWithP
}

// WriteDestination adds destination reference to the cache.
func (c *Cache) WriteDestination(d intermediate.CombinedDestinationRef) {
func (c *DestinationsCache) WriteDestination(d intermediate.CombinedDestinationRef) {
// Check that reference is a catalog.Service type.
if !resource.EqualType(catalog.ServiceType, d.ServiceRef.Type) {
panic("ref must of type catalog.Service")
Expand All @@ -68,7 +68,7 @@ func (c *Cache) WriteDestination(d intermediate.CombinedDestinationRef) {
}

// DeleteDestination deletes a given destination reference and port from cache.
func (c *Cache) DeleteDestination(ref *pbresource.Reference, port string) {
func (c *DestinationsCache) DeleteDestination(ref *pbresource.Reference, port string) {
// Check that reference is a catalog.Service type.
if !resource.EqualType(catalog.ServiceType, ref.Type) {
panic("ref must of type catalog.Service")
Expand All @@ -80,7 +80,7 @@ func (c *Cache) DeleteDestination(ref *pbresource.Reference, port string) {
c.deleteLocked(ref, port)
}

func (c *Cache) addLocked(d intermediate.CombinedDestinationRef) {
func (c *DestinationsCache) addLocked(d intermediate.CombinedDestinationRef) {
key := KeyFromRefAndPort(d.ServiceRef, d.Port)

c.store[key] = d
Expand All @@ -96,7 +96,7 @@ func (c *Cache) addLocked(d intermediate.CombinedDestinationRef) {
}
}

func (c *Cache) deleteLocked(ref *pbresource.Reference, port string) {
func (c *DestinationsCache) deleteLocked(ref *pbresource.Reference, port string) {
key := KeyFromRefAndPort(ref, port)

// First get it from the store.
Expand All @@ -117,7 +117,7 @@ func (c *Cache) deleteLocked(ref *pbresource.Reference, port string) {
}

// DeleteSourceProxy deletes the source proxy given by id from the cache.
func (c *Cache) DeleteSourceProxy(id *pbresource.ID) {
func (c *DestinationsCache) DeleteSourceProxy(id *pbresource.ID) {
// Check that id is the ProxyStateTemplate type.
if !resource.EqualType(types.ProxyStateTemplateType, id.Type) {
panic("id must of type mesh.ProxyStateTemplate")
Expand Down Expand Up @@ -148,7 +148,7 @@ func (c *Cache) DeleteSourceProxy(id *pbresource.ID) {
}

// ReadDestination returns a destination reference for the given service reference and port.
func (c *Cache) ReadDestination(ref *pbresource.Reference, port string) (intermediate.CombinedDestinationRef, bool) {
func (c *DestinationsCache) ReadDestination(ref *pbresource.Reference, port string) (intermediate.CombinedDestinationRef, bool) {
// Check that reference is a catalog.Service type.
if !resource.EqualType(catalog.ServiceType, ref.Type) {
panic("ref must of type catalog.Service")
Expand All @@ -164,7 +164,7 @@ func (c *Cache) ReadDestination(ref *pbresource.Reference, port string) (interme
}

// DestinationsBySourceProxy returns all destinations that are a referenced by the given source proxy id.
func (c *Cache) DestinationsBySourceProxy(id *pbresource.ID) []intermediate.CombinedDestinationRef {
func (c *DestinationsCache) DestinationsBySourceProxy(id *pbresource.ID) []intermediate.CombinedDestinationRef {
// Check that id is the ProxyStateTemplate type.
if !resource.EqualType(types.ProxyStateTemplateType, id.Type) {
panic("id must of type mesh.ProxyStateTemplate")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
)

func TestWrite_Create(t *testing.T) {
cache := New()
cache := NewDestinationsCache()

proxyID := resourcetest.Resource(types.ProxyStateTemplateType, "service-workload-abc").ID()
destination := testDestination(proxyID)
Expand All @@ -34,7 +34,7 @@ func TestWrite_Create(t *testing.T) {
}

func TestWrite_Update(t *testing.T) {
cache := New()
cache := NewDestinationsCache()

proxyID := resourcetest.Resource(types.ProxyStateTemplateType, "service-workload-abc").ID()
destination1 := testDestination(proxyID)
Expand Down Expand Up @@ -91,7 +91,7 @@ func TestWrite_Update(t *testing.T) {
}

func TestWrite_Delete(t *testing.T) {
cache := New()
cache := NewDestinationsCache()

proxyID := resourcetest.Resource(types.ProxyStateTemplateType, "service-workload-abc").ID()
destination1 := testDestination(proxyID)
Expand Down Expand Up @@ -125,7 +125,7 @@ func TestWrite_Delete(t *testing.T) {
}

func TestDeleteSourceProxy(t *testing.T) {
cache := New()
cache := NewDestinationsCache()

proxyID := resourcetest.Resource(types.ProxyStateTemplateType, "service-workload-abc").ID()
destination1 := testDestination(proxyID)
Expand Down Expand Up @@ -160,7 +160,7 @@ func TestDeleteSourceProxy(t *testing.T) {
}

func TestDestinationsBySourceProxy(t *testing.T) {
cache := New()
cache := NewDestinationsCache()

proxyID := resourcetest.Resource(types.ProxyStateTemplateType, "service-workload-abc").ID()
destination1 := testDestination(proxyID)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package sidecarproxycache

import (
"github.com/hashicorp/consul/internal/mesh/internal/types"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/mappers/bimapper"
"github.com/hashicorp/consul/proto-public/pbresource"
)

// ProxyConfigurationCache tracks mappings between proxy configurations and proxy IDs
// that a configuration applies to. It is the responsibility of the controller to
// keep this cache up-to-date.
type ProxyConfigurationCache struct {
mapper *bimapper.Mapper
}

func NewProxyConfigurationCache() *ProxyConfigurationCache {
return &ProxyConfigurationCache{
mapper: bimapper.New(types.ProxyConfigurationType, types.ProxyStateTemplateType),
}
}

// ProxyConfigurationsByProxyID returns proxy configuration IDs given the id of the proxy state template.
func (c *ProxyConfigurationCache) ProxyConfigurationsByProxyID(id *pbresource.ID) []*pbresource.ID {
return c.mapper.ItemIDsForLink(id)
}

// TrackProxyConfiguration tracks given proxy configuration ID and the linked proxy state template IDs.
func (c *ProxyConfigurationCache) TrackProxyConfiguration(proxyCfgID *pbresource.ID, proxyIDs []resource.ReferenceOrID) {
c.mapper.TrackItem(proxyCfgID, proxyIDs)
}

// UntrackProxyConfiguration removes tracking for the given proxy configuration ID.
func (c *ProxyConfigurationCache) UntrackProxyConfiguration(proxyCfgID *pbresource.ID) {
c.mapper.UntrackItem(proxyCfgID)
}

// UntrackProxyID removes tracking for the given proxy state template ID.
func (c *ProxyConfigurationCache) UntrackProxyID(proxyID *pbresource.ID) {
c.mapper.UntrackLink(proxyID)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package sidecarproxycache

import (
"testing"

"github.com/hashicorp/consul/internal/mesh/internal/types"
"github.com/hashicorp/consul/internal/resource"
"github.com/hashicorp/consul/internal/resource/resourcetest"
"github.com/hashicorp/consul/proto-public/pbresource"
"github.com/hashicorp/consul/proto/private/prototest"
"github.com/stretchr/testify/require"
)

func TestProxyConfigurationCache(t *testing.T) {
cache := NewProxyConfigurationCache()

// Create some proxy configurations.
proxyCfg1 := resourcetest.Resource(types.ProxyConfigurationType, "test-cfg-1").ID()
proxyCfg2 := resourcetest.Resource(types.ProxyConfigurationType, "test-cfg-2").ID()
proxyCfg3 := resourcetest.Resource(types.ProxyConfigurationType, "test-cfg-3").ID()

// Create some proxy state templates.
p1 := resourcetest.Resource(types.ProxyStateTemplateType, "w-111").ID()
p2 := resourcetest.Resource(types.ProxyStateTemplateType, "w-222").ID()
p3 := resourcetest.Resource(types.ProxyStateTemplateType, "w-333").ID()
p4 := resourcetest.Resource(types.ProxyStateTemplateType, "w-444").ID()
p5 := resourcetest.Resource(types.ProxyStateTemplateType, "w-555").ID()

// Track these and make sure there's some overlap.
cache.TrackProxyConfiguration(proxyCfg1, []resource.ReferenceOrID{p1, p2, p4})
cache.TrackProxyConfiguration(proxyCfg2, []resource.ReferenceOrID{p3, p4, p5})
cache.TrackProxyConfiguration(proxyCfg3, []resource.ReferenceOrID{p1, p3})

// Read proxy configurations by proxy.
requireProxyConfigurations(t, cache, p1, proxyCfg1, proxyCfg3)
requireProxyConfigurations(t, cache, p2, proxyCfg1)
requireProxyConfigurations(t, cache, p3, proxyCfg2, proxyCfg3)
requireProxyConfigurations(t, cache, p4, proxyCfg1, proxyCfg2)
requireProxyConfigurations(t, cache, p5, proxyCfg2)

// Untrack some proxy IDs.
cache.UntrackProxyID(p1)

requireProxyConfigurations(t, cache, p1)

// Untrack some proxy IDs.
cache.UntrackProxyID(p3)

requireProxyConfigurations(t, cache, p3)

// Untrack proxy cfg.
cache.UntrackProxyConfiguration(proxyCfg1)

requireProxyConfigurations(t, cache, p1) // no-op because we untracked it earlier
requireProxyConfigurations(t, cache, p2)
requireProxyConfigurations(t, cache, p3) // no-op because we untracked it earlier
requireProxyConfigurations(t, cache, p4, proxyCfg2)
requireProxyConfigurations(t, cache, p5, proxyCfg2)
}

func requireProxyConfigurations(t *testing.T, cache *ProxyConfigurationCache, proxyID *pbresource.ID, proxyCfgs ...*pbresource.ID) {
t.Helper()

actualProxyCfgs := cache.ProxyConfigurationsByProxyID(proxyID)

require.Len(t, actualProxyCfgs, len(proxyCfgs))
prototest.AssertElementsMatch(t, proxyCfgs, actualProxyCfgs)
}
5 changes: 3 additions & 2 deletions internal/mesh/internal/controllers/register.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import (

type Dependencies struct {
TrustDomainFetcher sidecarproxy.TrustDomainFetcher
LocalDatacenter string
}

func Register(mgr *controller.Manager, deps Dependencies) {
c := sidecarproxycache.New()
c := sidecarproxycache.NewDestinationsCache()
m := sidecarproxymapper.New(c)
mgr.Register(sidecarproxy.Controller(c, m, deps.TrustDomainFetcher))
mgr.Register(sidecarproxy.Controller(c, m, deps.TrustDomainFetcher, deps.LocalDatacenter))
}
16 changes: 13 additions & 3 deletions internal/mesh/internal/controllers/sidecarproxy/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,23 @@ import (
type Builder struct {
id *pbresource.ID
proxyStateTemplate *pbmesh.ProxyStateTemplate
proxyCfg *pbmesh.ProxyConfiguration
trustDomain string
localDatacenter string
}

func New(id *pbresource.ID, identity *pbresource.Reference, trustDomain string) *Builder {
func New(id *pbresource.ID,
identity *pbresource.Reference,
trustDomain string,
dc string,
proxyCfg *pbmesh.ProxyConfiguration,
) *Builder {

return &Builder{
id: id,
trustDomain: trustDomain,
id: id,
trustDomain: trustDomain,
localDatacenter: dc,
proxyCfg: proxyCfg,
proxyStateTemplate: &pbmesh.ProxyStateTemplate{
ProxyState: &pbmesh.ProxyState{
Identity: identity,
Expand Down
Loading

0 comments on commit 6ed3012

Please sign in to comment.