github.com/zhyoulun/cilium@v1.6.12/pkg/clustermesh/clustermesh_test.go (about)

     1  // Copyright 2018-2019 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // +build !privileged_tests
    16  
    17  package clustermesh
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"io/ioutil"
    23  	"os"
    24  	"path"
    25  	"testing"
    26  	"time"
    27  
    28  	"github.com/cilium/cilium/pkg/identity"
    29  	"github.com/cilium/cilium/pkg/identity/cache"
    30  	"github.com/cilium/cilium/pkg/kvstore"
    31  	"github.com/cilium/cilium/pkg/kvstore/store"
    32  	"github.com/cilium/cilium/pkg/lock"
    33  	"github.com/cilium/cilium/pkg/testutils"
    34  
    35  	. "gopkg.in/check.v1"
    36  )
    37  
    38  func Test(t *testing.T) {
    39  	TestingT(t)
    40  }
    41  
    42  type ClusterMeshTestSuite struct{}
    43  
    44  var _ = Suite(&ClusterMeshTestSuite{})
    45  
    46  var (
    47  	nodes      = map[string]*testNode{}
    48  	nodesMutex lock.RWMutex
    49  )
    50  
    51  type testNode struct {
    52  	// Name is the name of the node. This is typically the hostname of the node.
    53  	Name string
    54  
    55  	// Cluster is the name of the cluster the node is associated with
    56  	Cluster string
    57  }
    58  
    59  func (n *testNode) GetKeyName() string {
    60  	return path.Join(n.Name, n.Cluster)
    61  }
    62  
    63  func (n *testNode) DeepKeyCopy() store.LocalKey {
    64  	return &testNode{
    65  		Name:    n.Name,
    66  		Cluster: n.Cluster,
    67  	}
    68  }
    69  
    70  func (n *testNode) Marshal() ([]byte, error) {
    71  	return json.Marshal(n)
    72  }
    73  
    74  func (n *testNode) Unmarshal(data []byte) error {
    75  	return json.Unmarshal(data, n)
    76  }
    77  
    78  var testNodeCreator = func() store.Key {
    79  	n := testNode{}
    80  	return &n
    81  }
    82  
    83  type testObserver struct{}
    84  
    85  func (o *testObserver) OnUpdate(k store.Key) {
    86  	n := k.(*testNode)
    87  	nodesMutex.Lock()
    88  	nodes[n.GetKeyName()] = n
    89  	nodesMutex.Unlock()
    90  }
    91  
    92  func (o *testObserver) OnDelete(k store.NamedKey) {
    93  	n := k.(*testNode)
    94  	nodesMutex.Lock()
    95  	delete(nodes, n.GetKeyName())
    96  	nodesMutex.Unlock()
    97  }
    98  
    99  type identityAllocatorOwnerMock struct{}
   100  
   101  func (i *identityAllocatorOwnerMock) UpdateIdentities(added, deleted cache.IdentityCache) {}
   102  
   103  func (i *identityAllocatorOwnerMock) GetNodeSuffix() string {
   104  	return "foo"
   105  }
   106  
   107  func (s *ClusterMeshTestSuite) TestClusterMesh(c *C) {
   108  	kvstore.SetupDummy("etcd")
   109  	defer kvstore.Client().Close()
   110  
   111  	identity.InitWellKnownIdentities()
   112  	// The nils are only used by k8s CRD identities. We default to kvstore.
   113  	<-cache.InitIdentityAllocator(&identityAllocatorOwnerMock{}, nil, nil)
   114  	defer cache.Close()
   115  
   116  	dir, err := ioutil.TempDir("", "multicluster")
   117  	c.Assert(err, IsNil)
   118  	defer os.RemoveAll(dir)
   119  
   120  	etcdConfig := []byte(fmt.Sprintf("endpoints:\n- %s\n", kvstore.EtcdDummyAddress()))
   121  
   122  	config1 := path.Join(dir, "cluster1")
   123  	err = ioutil.WriteFile(config1, etcdConfig, 0644)
   124  	c.Assert(err, IsNil)
   125  
   126  	config2 := path.Join(dir, "cluster2")
   127  	err = ioutil.WriteFile(config2, etcdConfig, 0644)
   128  	c.Assert(err, IsNil)
   129  
   130  	cm, err := NewClusterMesh(Configuration{
   131  		Name:            "test2",
   132  		ConfigDirectory: dir,
   133  		NodeKeyCreator:  testNodeCreator,
   134  		nodeObserver:    &testObserver{},
   135  	})
   136  	c.Assert(err, IsNil)
   137  	c.Assert(cm, Not(IsNil))
   138  
   139  	nodeNames := []string{"foo", "bar", "baz"}
   140  
   141  	// wait for both clusters to appear in the list of cm clusters
   142  	c.Assert(testutils.WaitUntil(func() bool {
   143  		return cm.NumReadyClusters() == 2
   144  	}, 10*time.Second), IsNil)
   145  
   146  	cm.mutex.RLock()
   147  	for _, rc := range cm.clusters {
   148  		rc.mutex.RLock()
   149  		for _, name := range nodeNames {
   150  			err = rc.remoteNodes.UpdateLocalKeySync(&testNode{Name: name, Cluster: rc.name})
   151  			c.Assert(err, IsNil)
   152  		}
   153  		rc.mutex.RUnlock()
   154  	}
   155  	cm.mutex.RUnlock()
   156  
   157  	// wait for all cm nodes in both clusters to appear in the node list
   158  	c.Assert(testutils.WaitUntil(func() bool {
   159  		nodesMutex.RLock()
   160  		defer nodesMutex.RUnlock()
   161  		return len(nodes) == 2*len(nodeNames)
   162  	}, 10*time.Second), IsNil)
   163  
   164  	os.RemoveAll(config2)
   165  
   166  	// wait for the removed cluster to disappear
   167  	c.Assert(testutils.WaitUntil(func() bool {
   168  		return cm.NumReadyClusters() == 1
   169  	}, 5*time.Second), IsNil)
   170  
   171  	// wait for the nodes of the removed cluster to disappear
   172  	c.Assert(testutils.WaitUntil(func() bool {
   173  		nodesMutex.RLock()
   174  		defer nodesMutex.RUnlock()
   175  		return len(nodes) == len(nodeNames)
   176  	}, 10*time.Second), IsNil)
   177  
   178  	os.RemoveAll(config1)
   179  
   180  	// wait for the removed cluster to disappear
   181  	c.Assert(testutils.WaitUntil(func() bool {
   182  		return cm.NumReadyClusters() == 0
   183  	}, 5*time.Second), IsNil)
   184  
   185  	// wait for the nodes of the removed cluster to disappear
   186  	c.Assert(testutils.WaitUntil(func() bool {
   187  		nodesMutex.RLock()
   188  		defer nodesMutex.RUnlock()
   189  		return len(nodes) == 0
   190  	}, 10*time.Second), IsNil)
   191  
   192  	cm.Close()
   193  }