Consul is a distributed, highly available, and data center aware solution to connect and configure applications across dynamic, distributed infrastructure.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

272 lines
6.8 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package peering
import (
"fmt"
"testing"
"github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/testing/deployer/topology"
)
type ac1BasicSuite struct {
// inputs
DC string
Peer string
// test points
sidServerHTTP topology.ID
sidServerTCP topology.ID
nodeServerHTTP topology.NodeID
nodeServerTCP topology.NodeID
// 1.1
sidClientTCP topology.ID
nodeClientTCP topology.NodeID
// 1.2
sidClientHTTP topology.ID
nodeClientHTTP topology.NodeID
upstreamHTTP *topology.Destination
upstreamTCP *topology.Destination
}
var ac1BasicSuites []sharedTopoSuite = []sharedTopoSuite{
&ac1BasicSuite{DC: "dc1", Peer: "dc2"},
&ac1BasicSuite{DC: "dc2", Peer: "dc1"},
}
func TestAC1Basic(t *testing.T) {
runShareableSuites(t, ac1BasicSuites)
}
func (s *ac1BasicSuite) testName() string {
return fmt.Sprintf("ac1 basic %s->%s", s.DC, s.Peer)
}
// creates clients in s.DC and servers in s.Peer
func (s *ac1BasicSuite) setup(t *testing.T, ct *commonTopo) {
clu := ct.ClusterByDatacenter(t, s.DC)
peerClu := ct.ClusterByDatacenter(t, s.Peer)
partition := "default"
peer := LocalPeerName(peerClu, "default")
cluPeerName := LocalPeerName(clu, "default")
const prefix = "ac1-"
tcpServerSID := topology.ID{
Name: prefix + "server-tcp",
Partition: partition,
}
httpServerSID := topology.ID{
Name: prefix + "server-http",
Partition: partition,
}
upstreamHTTP := &topology.Destination{
ID: topology.ID{
Name: httpServerSID.Name,
Partition: partition,
},
LocalPort: 5001,
Peer: peer,
}
upstreamTCP := &topology.Destination{
ID: topology.ID{
Name: tcpServerSID.Name,
Partition: partition,
},
LocalPort: 5000,
Peer: peer,
}
// Make clients which have server upstreams
setupClientServiceAndConfigs := func(protocol string) (serviceExt, *topology.Node) {
sid := topology.ID{
Name: prefix + "client-" + protocol,
Partition: partition,
}
svc := serviceExt{
Workload: NewFortioServiceWithDefaults(
clu.Datacenter,
sid,
func(s *topology.Workload) {
s.Destinations = []*topology.Destination{
upstreamTCP,
upstreamHTTP,
}
},
),
Config: &api.ServiceConfigEntry{
Kind: api.ServiceDefaults,
Name: sid.Name,
Partition: ConfigEntryPartition(sid.Partition),
Protocol: protocol,
UpstreamConfig: &api.UpstreamConfiguration{
Defaults: &api.UpstreamConfig{
MeshGateway: api.MeshGatewayConfig{
Mode: api.MeshGatewayModeLocal,
},
},
},
},
}
node := ct.AddServiceNode(clu, svc)
return svc, node
}
tcpClient, tcpClientNode := setupClientServiceAndConfigs("tcp")
httpClient, httpClientNode := setupClientServiceAndConfigs("http")
httpServer := serviceExt{
Workload: NewFortioServiceWithDefaults(
peerClu.Datacenter,
httpServerSID,
nil,
),
Config: &api.ServiceConfigEntry{
Kind: api.ServiceDefaults,
Name: httpServerSID.Name,
Partition: ConfigEntryPartition(httpServerSID.Partition),
Protocol: "http",
},
Exports: []api.ServiceConsumer{{Peer: cluPeerName}},
Intentions: &api.ServiceIntentionsConfigEntry{
Kind: api.ServiceIntentions,
Name: httpServerSID.Name,
Partition: ConfigEntryPartition(httpServerSID.Partition),
Sources: []*api.SourceIntention{
{
Name: tcpClient.ID.Name,
Peer: cluPeerName,
Action: api.IntentionActionAllow,
},
{
Name: httpClient.ID.Name,
Peer: cluPeerName,
Action: api.IntentionActionAllow,
},
},
},
}
tcpServer := serviceExt{
Workload: NewFortioServiceWithDefaults(
peerClu.Datacenter,
tcpServerSID,
nil,
),
Config: &api.ServiceConfigEntry{
Kind: api.ServiceDefaults,
Name: tcpServerSID.Name,
Partition: ConfigEntryPartition(tcpServerSID.Partition),
Protocol: "tcp",
},
Exports: []api.ServiceConsumer{{Peer: cluPeerName}},
Intentions: &api.ServiceIntentionsConfigEntry{
Kind: api.ServiceIntentions,
Name: tcpServerSID.Name,
Partition: ConfigEntryPartition(tcpServerSID.Partition),
Sources: []*api.SourceIntention{
{
Name: tcpClient.ID.Name,
Peer: cluPeerName,
Action: api.IntentionActionAllow,
},
{
Name: httpClient.ID.Name,
Peer: cluPeerName,
Action: api.IntentionActionAllow,
},
},
},
}
httpServerNode := ct.AddServiceNode(peerClu, httpServer)
tcpServerNode := ct.AddServiceNode(peerClu, tcpServer)
s.sidClientHTTP = httpClient.ID
s.nodeClientHTTP = httpClientNode.ID()
s.sidClientTCP = tcpClient.ID
s.nodeClientTCP = tcpClientNode.ID()
s.upstreamHTTP = upstreamHTTP
s.upstreamTCP = upstreamTCP
// these are references in Peer
s.sidServerHTTP = httpServerSID
s.nodeServerHTTP = httpServerNode.ID()
s.sidServerTCP = tcpServerSID
s.nodeServerTCP = tcpServerNode.ID()
}
// implements https://docs.google.com/document/d/1Fs3gNMhCqE4zVNMFcbzf02ZrB0kxxtJpI2h905oKhrs/edit#heading=h.wtzvyryyb56v
func (s *ac1BasicSuite) test(t *testing.T, ct *commonTopo) {
dc := ct.Sprawl.Topology().Clusters[s.DC]
peer := ct.Sprawl.Topology().Clusters[s.Peer]
ac := s
// refresh this from Topology
svcClientTCP := dc.WorkloadByID(
ac.nodeClientTCP,
ac.sidClientTCP,
)
svcClientHTTP := dc.WorkloadByID(
ac.nodeClientHTTP,
ac.sidClientHTTP,
)
// our ac has the node/sid for server in the peer DC
svcServerHTTP := peer.WorkloadByID(
ac.nodeServerHTTP,
ac.sidServerHTTP,
)
svcServerTCP := peer.WorkloadByID(
ac.nodeServerTCP,
ac.sidServerTCP,
)
// preconditions
// these could be done parallel with each other, but complexity
// probably not worth the speed boost
ct.Assert.HealthyWithPeer(t, dc.Name, svcServerHTTP.ID, LocalPeerName(peer, "default"))
ct.Assert.HealthyWithPeer(t, dc.Name, svcServerTCP.ID, LocalPeerName(peer, "default"))
tcs := []struct {
acSub int
proto string
svc *topology.Workload
}{
{1, "tcp", svcClientTCP},
{2, "http", svcClientHTTP},
}
for _, tc := range tcs {
tc := tc
t.Run(fmt.Sprintf("1.%d. %s in A can call HTTP upstream", tc.acSub, tc.proto), func(t *testing.T) {
t.Parallel()
ct.Assert.FortioFetch2HeaderEcho(t, tc.svc, ac.upstreamHTTP)
})
t.Run(fmt.Sprintf("1.%d. %s in A can call TCP upstream", tc.acSub, tc.proto), func(t *testing.T) {
t.Parallel()
ct.Assert.FortioFetch2HeaderEcho(t, tc.svc, ac.upstreamTCP)
})
t.Run(fmt.Sprintf("1.%d. via %s in A, FORTIO_NAME of HTTP upstream", tc.acSub, tc.proto), func(t *testing.T) {
t.Parallel()
ct.Assert.FortioFetch2FortioName(t,
tc.svc,
ac.upstreamHTTP,
peer.Name,
svcServerHTTP.ID,
)
})
t.Run(fmt.Sprintf("1.%d. via %s in A, FORTIO_NAME of TCP upstream", tc.acSub, tc.proto), func(t *testing.T) {
t.Parallel()
ct.Assert.FortioFetch2FortioName(t,
tc.svc,
ac.upstreamTCP,
peer.Name,
svcServerTCP.ID,
)
})
}
}