mirror of https://github.com/hashicorp/consul
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
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.Upstream |
|
upstreamTCP *topology.Upstream |
|
} |
|
|
|
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.Upstream{ |
|
ID: topology.ID{ |
|
Name: httpServerSID.Name, |
|
Partition: partition, |
|
}, |
|
LocalPort: 5001, |
|
Peer: peer, |
|
} |
|
upstreamTCP := &topology.Upstream{ |
|
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.Upstreams = []*topology.Upstream{ |
|
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, |
|
) |
|
}) |
|
} |
|
}
|
|
|