Skip to content

Commit

Permalink
Merge branch 'main' of github.com:hashicorp/consul into api-gateway-i…
Browse files Browse the repository at this point in the history
…nline
  • Loading branch information
Andrew Stucki committed Feb 17, 2023
2 parents 37502d4 + 2460ac9 commit 1945da2
Show file tree
Hide file tree
Showing 20 changed files with 1,145 additions and 303 deletions.
3 changes: 3 additions & 0 deletions .changelog/16257.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:bug
peering: Fix issue where mesh gateways would use the wrong address when contacting a remote peer with the same datacenter name.
```
3 changes: 3 additions & 0 deletions .changelog/16292.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:feature
server: added server side RPC requests global read/write rate-limiter.
```
171 changes: 91 additions & 80 deletions agent/proxycfg/testing_api_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,28 +3,35 @@ package proxycfg
import (
"fmt"

"github.com/mitchellh/go-testing-interface"

"github.com/hashicorp/consul/agent/connect"
"github.com/hashicorp/consul/agent/consul/discoverychain"
"github.com/mitchellh/go-testing-interface"

"github.com/hashicorp/consul/agent/structs"
)

func TestConfigSnapshotAPIGateway(t testing.T) *ConfigSnapshot {
func TestConfigSnapshotAPIGateway(
t testing.T,
variation string,
nsFn func(ns *structs.NodeService),
configFn func(entry *structs.APIGatewayConfigEntry, boundEntry *structs.BoundAPIGatewayConfigEntry),
routes []structs.BoundRoute,
extraUpdates []UpdateEvent,
additionalEntries ...structs.ConfigEntry,
) *ConfigSnapshot {
roots, placeholderLeaf := TestCerts(t)

entries := []structs.ConfigEntry{
&structs.ProxyConfigEntry{
Kind: structs.ProxyDefaults,
Name: structs.ProxyConfigGlobal,
Config: map[string]interface{}{
"protocol": "tcp",
},
},
&structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "api-gateway",
},
entry := &structs.APIGatewayConfigEntry{
Kind: structs.APIGateway,
Name: "api-gateway",
}
boundEntry := &structs.BoundAPIGatewayConfigEntry{
Kind: structs.BoundAPIGateway,
Name: "api-gateway",
}

if configFn != nil {
configFn(entry, boundEntry)
}

baseEvents := []UpdateEvent{
Expand All @@ -39,95 +46,99 @@ func TestConfigSnapshotAPIGateway(t testing.T) *ConfigSnapshot {
{
CorrelationID: gatewayConfigWatchID,
Result: &structs.ConfigEntryResponse{
Entry: &structs.APIGatewayConfigEntry{
Kind: structs.APIGateway,
Name: "api-gateway",
Listeners: []structs.APIGatewayListener{
{
Name: "",
Hostname: "",
Port: 8080,
Protocol: structs.ListenerProtocolTCP,
TLS: structs.APIGatewayTLSConfiguration{
Certificates: []structs.ResourceReference{
{
Kind: structs.InlineCertificate,
Name: "my-inline-certificate",
},
},
},
},
},
},
Entry: entry,
},
},
{
CorrelationID: gatewayConfigWatchID,
Result: &structs.ConfigEntryResponse{
Entry: &structs.BoundAPIGatewayConfigEntry{
Kind: structs.BoundAPIGateway,
Name: "api-gateway",
Listeners: []structs.BoundAPIGatewayListener{
{
Name: "",
Certificates: []structs.ResourceReference{
{
Kind: structs.InlineCertificate,
Name: "my-inline-certificate",
},
},
Routes: []structs.ResourceReference{
{
Kind: structs.TCPRoute,
Name: "my-tcp-route",
},
},
},
},
},
Entry: boundEntry,
},
},
{
}

for _, route := range routes {
// Add the watch event for the route.
watch := UpdateEvent{
CorrelationID: routeConfigWatchID,
Result: &structs.ConfigEntryResponse{
Entry: &structs.TCPRouteConfigEntry{
Kind: structs.TCPRoute,
Name: "my-tcp-route",
Parents: []structs.ResourceReference{
{
Kind: structs.APIGateway,
Name: "api-gateway",
},
},
Services: []structs.TCPService{
{Name: "my-tcp-service"},
},
Entry: route,
},
}
baseEvents = append(baseEvents, watch)

// Add the watch event for the discovery chain.
entries := []structs.ConfigEntry{
&structs.ProxyConfigEntry{
Kind: structs.ProxyDefaults,
Name: structs.ProxyConfigGlobal,
Config: map[string]interface{}{
"protocol": route.GetProtocol(),
},
},
&structs.ServiceResolverConfigEntry{
Kind: structs.ServiceResolver,
Name: "api-gateway",
},
}

// Add a discovery chain watch event for each service.
for _, serviceName := range route.GetServiceNames() {
discoChain := UpdateEvent{
CorrelationID: fmt.Sprintf("discovery-chain:%s", UpstreamIDString("", "", serviceName.Name, &serviceName.EnterpriseMeta, "")),
Result: &structs.DiscoveryChainResponse{
Chain: discoverychain.TestCompileConfigEntries(t, serviceName.Name, "default", "default", "dc1", connect.TestClusterID+".consul", nil, entries...),
},
}
baseEvents = append(baseEvents, discoChain)
}
}

upstreams := structs.TestUpstreams(t)

baseEvents = testSpliceEvents(baseEvents, setupTestVariationConfigEntriesAndSnapshot(
t, variation, upstreams, additionalEntries...,
))

return testConfigSnapshotFixture(t, &structs.NodeService{
Kind: structs.ServiceKindAPIGateway,
Service: "api-gateway",
Address: "1.2.3.4",
Meta: nil,
TaggedAddresses: nil,
}, nsFn, nil, testSpliceEvents(baseEvents, extraUpdates))
}

// TestConfigSnapshotAPIGateway_NilConfigEntry is used to test when
// the update event for the config entry returns nil
// since this always happens on the first watch if it doesn't exist.
func TestConfigSnapshotAPIGateway_NilConfigEntry(
t testing.T,
) *ConfigSnapshot {
roots, _ := TestCerts(t)

baseEvents := []UpdateEvent{
{
CorrelationID: rootsWatchID,
Result: roots,
},
{
CorrelationID: inlineCertificateConfigWatchID,
CorrelationID: gatewayConfigWatchID,
Result: &structs.ConfigEntryResponse{
Entry: &structs.InlineCertificateConfigEntry{
Kind: structs.InlineCertificate,
Name: "my-inline-certificate",
Certificate: "certificate",
PrivateKey: "private key",
},
Entry: nil, // The first watch on a config entry will return nil if the config entry doesn't exist.
},
},
{
CorrelationID: fmt.Sprintf("discovery-chain:%s", UpstreamIDString("","","my-tcp-service",nil, "")),
Result: &structs.DiscoveryChainResponse{
Chain: discoverychain.TestCompileConfigEntries(t,"my-tcp-service","default","default","dc1", connect.TestClusterID+".consul",nil,entries...),
CorrelationID: gatewayConfigWatchID,
Result: &structs.ConfigEntryResponse{
Entry: nil, // The first watch on a config entry will return nil if the config entry doesn't exist.
},
},
}

return testConfigSnapshotFixture(t, &structs.NodeService{
Kind: structs.ServiceKindAPIGateway,
Service: "api-gateway",
Port: 9999,
Address: "1.2.3.4",
Meta: nil,
TaggedAddresses: nil,
Expand Down
8 changes: 4 additions & 4 deletions agent/proxycfg/testing_mesh_gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -659,17 +659,17 @@ func TestConfigSnapshotPeeredMeshGateway(t testing.T, variant string, nsFn func(
CorrelationID: "peering-connect-service:peer-a:db",
Result: &structs.IndexedCheckServiceNodes{
Nodes: structs.CheckServiceNodes{
structs.TestCheckNodeServiceWithNameInPeer(t, "db", "peer-a", "10.40.1.1", false),
structs.TestCheckNodeServiceWithNameInPeer(t, "db", "peer-a", "10.40.1.2", false),
structs.TestCheckNodeServiceWithNameInPeer(t, "db", "dc1", "peer-a", "10.40.1.1", false),
structs.TestCheckNodeServiceWithNameInPeer(t, "db", "dc1", "peer-a", "10.40.1.2", false),
},
},
},
UpdateEvent{
CorrelationID: "peering-connect-service:peer-b:alt",
Result: &structs.IndexedCheckServiceNodes{
Nodes: structs.CheckServiceNodes{
structs.TestCheckNodeServiceWithNameInPeer(t, "alt", "peer-b", "10.40.2.1", false),
structs.TestCheckNodeServiceWithNameInPeer(t, "alt", "peer-b", "10.40.2.2", true),
structs.TestCheckNodeServiceWithNameInPeer(t, "alt", "remote-dc", "peer-b", "10.40.2.1", false),
structs.TestCheckNodeServiceWithNameInPeer(t, "alt", "remote-dc", "peer-b", "10.40.2.2", true),
},
},
},
Expand Down
4 changes: 2 additions & 2 deletions agent/proxycfg/testing_upstreams.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func setupTestVariationConfigEntriesAndSnapshot(
events = append(events, UpdateEvent{
CorrelationID: "upstream-peer:db?peer=cluster-01",
Result: &structs.IndexedCheckServiceNodes{
Nodes: structs.CheckServiceNodes{structs.TestCheckNodeServiceWithNameInPeer(t, "db", "cluster-01", "10.40.1.1", false)},
Nodes: structs.CheckServiceNodes{structs.TestCheckNodeServiceWithNameInPeer(t, "db", "dc1", "cluster-01", "10.40.1.1", false)},
},
})
case "redirect-to-cluster-peer":
Expand All @@ -112,7 +112,7 @@ func setupTestVariationConfigEntriesAndSnapshot(
events = append(events, UpdateEvent{
CorrelationID: "upstream-peer:db?peer=cluster-01",
Result: &structs.IndexedCheckServiceNodes{
Nodes: structs.CheckServiceNodes{structs.TestCheckNodeServiceWithNameInPeer(t, "db", "cluster-01", "10.40.1.1", false)},
Nodes: structs.CheckServiceNodes{structs.TestCheckNodeServiceWithNameInPeer(t, "db", "dc2", "cluster-01", "10.40.1.1", false)},
},
})
case "failover-through-double-remote-gateway-triggered":
Expand Down
27 changes: 19 additions & 8 deletions agent/structs/testing_catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,11 +55,13 @@ func TestNodeServiceWithName(t testing.T, name string) *NodeService {

const peerTrustDomain = "1c053652-8512-4373-90cf-5a7f6263a994.consul"

func TestCheckNodeServiceWithNameInPeer(t testing.T, name, peer, ip string, useHostname bool) CheckServiceNode {
func TestCheckNodeServiceWithNameInPeer(t testing.T, name, dc, peer, ip string, useHostname bool) CheckServiceNode {
service := &NodeService{
Kind: ServiceKindTypical,
Service: name,
Port: 8080,
Kind: ServiceKindTypical,
Service: name,
// We should not see this port number appear in most xds golden tests,
// because the WAN addr should typically be used.
Port: 9090,
PeerName: peer,
Connect: ServiceConnect{
PeerMeta: &PeeringServiceMeta{
Expand All @@ -72,6 +74,13 @@ func TestCheckNodeServiceWithNameInPeer(t testing.T, name, peer, ip string, useH
Protocol: "tcp",
},
},
// This value should typically be seen in golden file output, since this is a peered service.
TaggedAddresses: map[string]ServiceAddress{
TaggedAddressWAN: {
Address: ip,
Port: 8080,
},
},
}

if useHostname {
Expand All @@ -89,10 +98,12 @@ func TestCheckNodeServiceWithNameInPeer(t testing.T, name, peer, ip string, useH

return CheckServiceNode{
Node: &Node{
ID: "test1",
Node: "test1",
Address: ip,
Datacenter: "cloud-dc",
ID: "test1",
Node: "test1",
// We should not see this address appear in most xds golden tests,
// because the WAN addr should typically be used.
Address: "1.23.45.67",
Datacenter: dc,
},
Service: service,
}
Expand Down
4 changes: 3 additions & 1 deletion agent/xds/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -449,7 +449,9 @@ func (s *ResourceGenerator) makeEndpointsForOutgoingPeeredServices(
la := makeLoadAssignment(
clusterName,
groups,
cfgSnap.Locality,
// Use an empty key here so that it never matches. This will force the mesh gateway to always
// reference the remote mesh gateway's wan addr.
proxycfg.GatewayKey{},
)
resources = append(resources, la)
}
Expand Down
Loading

0 comments on commit 1945da2

Please sign in to comment.