2022-05-02 18:49:05 +00:00
|
|
|
package api
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
2022-05-05 21:15:42 +00:00
|
|
|
"reflect"
|
2022-05-02 18:49:05 +00:00
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"github.com/hashicorp/consul/sdk/testutil"
|
2022-05-05 21:15:42 +00:00
|
|
|
"github.com/hashicorp/consul/sdk/testutil/retry"
|
2022-05-02 18:49:05 +00:00
|
|
|
)
|
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
const DefaultCtxDuration = 15 * time.Second
|
|
|
|
|
|
|
|
func peerExistsInPeerListings(peer *Peering, peerings []*Peering) bool {
|
|
|
|
for _, aPeer := range peerings {
|
|
|
|
isEqual := (peer.PeerID == aPeer.PeerID) &&
|
|
|
|
(reflect.DeepEqual(peer.PeerCAPems, aPeer.PeerCAPems)) &&
|
|
|
|
(peer.PeerServerName == aPeer.PeerServerName) &&
|
|
|
|
(peer.Partition == aPeer.Partition) &&
|
|
|
|
(peer.Name == aPeer.Name) &&
|
|
|
|
(reflect.DeepEqual(peer.PeerServerAddresses, aPeer.PeerServerAddresses)) &&
|
|
|
|
(peer.State == aPeer.State) &&
|
|
|
|
(peer.CreateIndex == aPeer.CreateIndex) &&
|
2022-06-29 21:07:30 +00:00
|
|
|
(peer.ModifyIndex == aPeer.ModifyIndex) &&
|
|
|
|
(peer.ImportedServiceCount == aPeer.ImportedServiceCount) &&
|
|
|
|
(peer.ExportedServiceCount == aPeer.ExportedServiceCount)
|
2022-05-05 21:15:42 +00:00
|
|
|
|
|
|
|
if isEqual {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPI_Peering_Read_ErrorHandling(t *testing.T) {
|
|
|
|
t.Parallel()
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
c, s := makeClientWithCA(t)
|
|
|
|
defer s.Stop()
|
|
|
|
s.WaitForSerfCheck(t)
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), DefaultCtxDuration)
|
|
|
|
defer cancel()
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
peerings := c.Peerings()
|
|
|
|
|
|
|
|
t.Run("call Read with no name", func(t *testing.T) {
|
2022-05-25 18:43:35 +00:00
|
|
|
_, _, err := peerings.Read(ctx, "", nil)
|
2022-05-05 21:15:42 +00:00
|
|
|
require.EqualError(t, err, "peering name cannot be empty")
|
|
|
|
})
|
|
|
|
|
|
|
|
t.Run("read peer that does not exist on server", func(t *testing.T) {
|
2022-05-25 18:43:35 +00:00
|
|
|
resp, qm, err := peerings.Read(ctx, "peer1", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, qm)
|
|
|
|
require.Nil(t, resp)
|
2022-05-05 21:15:42 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestAPI_Peering_List
|
|
|
|
func TestAPI_Peering_List(t *testing.T) {
|
|
|
|
t.Parallel()
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
c, s := makeClientWithCA(t)
|
|
|
|
defer s.Stop()
|
|
|
|
s.WaitForSerfCheck(t)
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), DefaultCtxDuration)
|
|
|
|
defer cancel()
|
|
|
|
|
2022-05-25 18:43:35 +00:00
|
|
|
peerings := c.Peerings()
|
2022-05-05 21:15:42 +00:00
|
|
|
|
2022-05-25 18:43:35 +00:00
|
|
|
testutil.RunStep(t, "list with no peers", func(t *testing.T) {
|
2022-06-29 21:07:30 +00:00
|
|
|
// call List when no peers should exist
|
2022-05-25 18:43:35 +00:00
|
|
|
resp, qm, err := peerings.List(ctx, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, qm)
|
|
|
|
require.Empty(t, resp) // no peerings so this should be empty
|
|
|
|
})
|
2022-05-05 21:15:42 +00:00
|
|
|
|
2022-05-25 18:43:35 +00:00
|
|
|
testutil.RunStep(t, "list with some peers", func(t *testing.T) {
|
2022-06-29 21:07:30 +00:00
|
|
|
// call List when peers are present
|
2022-05-25 18:43:35 +00:00
|
|
|
resp1, wm, err := peerings.GenerateToken(ctx, PeeringGenerateTokenRequest{PeerName: "peer1"}, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, wm)
|
|
|
|
require.NotNil(t, resp1)
|
|
|
|
|
|
|
|
resp2, wm, err := peerings.GenerateToken(ctx, PeeringGenerateTokenRequest{PeerName: "peer2"}, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, wm)
|
|
|
|
require.NotNil(t, resp2)
|
|
|
|
|
|
|
|
peering1, qm, err := peerings.Read(ctx, "peer1", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, qm)
|
|
|
|
require.NotNil(t, peering1)
|
|
|
|
|
|
|
|
peering2, qm, err := peerings.Read(ctx, "peer2", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, qm)
|
|
|
|
require.NotNil(t, peering2)
|
|
|
|
|
|
|
|
peeringsList, qm, err := peerings.List(ctx, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, qm)
|
|
|
|
|
|
|
|
require.Len(t, peeringsList, 2)
|
|
|
|
require.True(t, peerExistsInPeerListings(peering1, peeringsList), "expected to find peering in list response")
|
|
|
|
require.True(t, peerExistsInPeerListings(peering2, peeringsList), "expected to find peering in list response")
|
|
|
|
})
|
2022-05-05 21:15:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestAPI_Peering_GenerateToken(t *testing.T) {
|
|
|
|
t.Parallel()
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
c, s := makeClientWithCA(t)
|
|
|
|
defer s.Stop()
|
|
|
|
s.WaitForSerfCheck(t)
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), DefaultCtxDuration)
|
|
|
|
defer cancel()
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-05-05 21:15:42 +00:00
|
|
|
peerings := c.Peerings()
|
|
|
|
|
|
|
|
t.Run("cannot have GenerateToken forward DC requests", func(t *testing.T) {
|
|
|
|
// Try to generate a token in dc2
|
2022-05-25 18:43:35 +00:00
|
|
|
_, _, err := peerings.GenerateToken(ctx, PeeringGenerateTokenRequest{PeerName: "peer2", Datacenter: "dc2"}, nil)
|
2022-05-05 21:15:42 +00:00
|
|
|
require.Error(t, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2022-05-02 18:49:05 +00:00
|
|
|
// TODO(peering): cover the following test cases: bad/ malformed input, peering with wrong token,
|
|
|
|
// peering with the wrong PeerName
|
|
|
|
|
2022-06-10 16:10:46 +00:00
|
|
|
// TestAPI_Peering_GenerateToken_Read_Establish_Delete tests the following use case:
|
|
|
|
// a server creates a peering token, reads the token, then another server calls establish peering
|
2022-05-02 18:49:05 +00:00
|
|
|
// finally, we delete the token on the first server
|
2022-06-10 16:10:46 +00:00
|
|
|
func TestAPI_Peering_GenerateToken_Read_Establish_Delete(t *testing.T) {
|
2022-05-02 18:49:05 +00:00
|
|
|
t.Parallel()
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-06-29 16:43:50 +00:00
|
|
|
c, s := makeClient(t) // this is "dc1"
|
2022-05-02 18:49:05 +00:00
|
|
|
defer s.Stop()
|
|
|
|
s.WaitForSerfCheck(t)
|
2022-05-25 18:43:35 +00:00
|
|
|
|
2022-06-29 16:43:50 +00:00
|
|
|
// make a "client" server in second DC for peering
|
|
|
|
c2, s2 := makeClientWithConfig(t, nil, func(conf *testutil.TestServerConfig) {
|
|
|
|
conf.Datacenter = "dc2"
|
|
|
|
})
|
|
|
|
defer s2.Stop()
|
|
|
|
|
|
|
|
testutil.RunStep(t, "register services to get synced dc2", func(t *testing.T) {
|
|
|
|
testNodeServiceCheckRegistrations(t, c2, "dc2")
|
|
|
|
})
|
|
|
|
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
2022-05-05 21:15:42 +00:00
|
|
|
defer cancel()
|
2022-05-02 18:49:05 +00:00
|
|
|
|
|
|
|
var token1 string
|
2022-05-25 18:43:35 +00:00
|
|
|
testutil.RunStep(t, "generate token", func(t *testing.T) {
|
|
|
|
// Generate a token happy path
|
|
|
|
p1 := PeeringGenerateTokenRequest{
|
|
|
|
PeerName: "peer1",
|
|
|
|
Meta: map[string]string{"foo": "bar"},
|
|
|
|
}
|
|
|
|
resp, wm, err := c.Peerings().GenerateToken(ctx, p1, nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, wm)
|
|
|
|
require.NotNil(t, resp)
|
2022-05-02 18:49:05 +00:00
|
|
|
|
2022-05-25 18:43:35 +00:00
|
|
|
token1 = resp.PeeringToken
|
|
|
|
})
|
2022-05-02 18:49:05 +00:00
|
|
|
|
2022-05-25 18:43:35 +00:00
|
|
|
testutil.RunStep(t, "verify token", func(t *testing.T) {
|
|
|
|
// Read token generated on server
|
|
|
|
resp, qm, err := c.Peerings().Read(ctx, "peer1", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, qm)
|
|
|
|
require.NotNil(t, resp)
|
|
|
|
|
|
|
|
// token specific assertions on the "server"
|
|
|
|
require.Equal(t, "peer1", resp.Name)
|
|
|
|
require.Equal(t, PeeringStateInitial, resp.State)
|
|
|
|
require.Equal(t, map[string]string{"foo": "bar"}, resp.Meta)
|
|
|
|
})
|
2022-05-02 18:49:05 +00:00
|
|
|
|
2022-06-10 16:10:46 +00:00
|
|
|
testutil.RunStep(t, "establish peering", func(t *testing.T) {
|
|
|
|
i := PeeringEstablishRequest{
|
2022-05-25 18:43:35 +00:00
|
|
|
Datacenter: c2.config.Datacenter,
|
|
|
|
PeerName: "peer1",
|
|
|
|
PeeringToken: token1,
|
|
|
|
Meta: map[string]string{"foo": "bar"},
|
|
|
|
}
|
2022-05-02 18:49:05 +00:00
|
|
|
|
2022-06-10 16:10:46 +00:00
|
|
|
_, wm, err := c2.Peerings().Establish(ctx, i, nil)
|
2022-05-25 18:43:35 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, wm)
|
2022-05-02 18:49:05 +00:00
|
|
|
|
2022-05-25 18:43:35 +00:00
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
resp, qm, err := c2.Peerings().Read(ctx, "peer1", nil)
|
|
|
|
require.NoError(r, err)
|
|
|
|
require.NotNil(r, qm)
|
2022-05-02 18:49:05 +00:00
|
|
|
|
2022-05-25 18:43:35 +00:00
|
|
|
// require that the peering state is not undefined
|
|
|
|
require.Equal(r, PeeringStateInitial, resp.State)
|
|
|
|
require.Equal(r, map[string]string{"foo": "bar"}, resp.Meta)
|
2022-06-29 16:43:50 +00:00
|
|
|
})
|
|
|
|
})
|
2022-05-02 18:49:05 +00:00
|
|
|
|
2022-06-29 16:43:50 +00:00
|
|
|
testutil.RunStep(t, "look for active state of peering in dc2", func(t *testing.T) {
|
|
|
|
// read and list the peer to make sure the status transitions to active
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
peering, qm, err := c2.Peerings().Read(ctx, "peer1", nil)
|
|
|
|
require.NoError(r, err)
|
|
|
|
require.NotNil(r, qm)
|
|
|
|
require.NotNil(r, peering)
|
|
|
|
require.Equal(r, PeeringStateActive, peering.State)
|
|
|
|
|
|
|
|
peerings, qm, err := c2.Peerings().List(ctx, nil)
|
|
|
|
|
|
|
|
require.NoError(r, err)
|
|
|
|
require.NotNil(r, qm)
|
|
|
|
require.NotNil(r, peerings)
|
|
|
|
require.Equal(r, PeeringStateActive, peerings[0].State)
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
testutil.RunStep(t, "look for active state of peering in dc1", func(t *testing.T) {
|
|
|
|
// read and list the peer to make sure the status transitions to active
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
peering, qm, err := c.Peerings().Read(ctx, "peer1", nil)
|
|
|
|
require.NoError(r, err)
|
|
|
|
require.NotNil(r, qm)
|
|
|
|
require.NotNil(r, peering)
|
|
|
|
require.Equal(r, PeeringStateActive, peering.State)
|
|
|
|
|
|
|
|
peerings, qm, err := c.Peerings().List(ctx, nil)
|
|
|
|
|
|
|
|
require.NoError(r, err)
|
|
|
|
require.NotNil(r, qm)
|
|
|
|
require.NotNil(r, peerings)
|
|
|
|
require.Equal(r, PeeringStateActive, peerings[0].State)
|
2022-05-25 18:43:35 +00:00
|
|
|
})
|
2022-05-05 21:15:42 +00:00
|
|
|
})
|
2022-05-02 18:49:05 +00:00
|
|
|
|
2022-05-25 18:43:35 +00:00
|
|
|
testutil.RunStep(t, "delete peering at source", func(t *testing.T) {
|
|
|
|
// Delete the token on server 1
|
|
|
|
wm, err := c.Peerings().Delete(ctx, "peer1", nil)
|
|
|
|
require.NoError(t, err)
|
|
|
|
require.NotNil(t, wm)
|
|
|
|
|
2022-06-14 01:50:59 +00:00
|
|
|
// Read to see if the token is gone
|
|
|
|
retry.Run(t, func(r *retry.R) {
|
|
|
|
resp, qm, err := c.Peerings().Read(ctx, "peer1", nil)
|
|
|
|
require.NoError(r, err)
|
|
|
|
require.NotNil(r, qm)
|
|
|
|
require.Nil(r, resp)
|
|
|
|
})
|
2022-05-25 18:43:35 +00:00
|
|
|
})
|
2022-05-02 18:49:05 +00:00
|
|
|
}
|