github.phpd.cn/cilium/cilium@v1.6.12/pkg/k8s/client_test.go (about) 1 // Copyright 2016-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 k8s 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "net" 23 "time" 24 25 "github.com/cilium/cilium/pkg/annotation" 26 "github.com/cilium/cilium/pkg/checker" 27 "github.com/cilium/cilium/pkg/k8s/types" 28 "github.com/cilium/cilium/pkg/node" 29 "github.com/cilium/cilium/pkg/source" 30 31 . "gopkg.in/check.v1" 32 "k8s.io/api/core/v1" 33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 34 "k8s.io/apimachinery/pkg/runtime" 35 "k8s.io/client-go/kubernetes/fake" 36 "k8s.io/client-go/testing" 37 ) 38 39 func (s *K8sSuite) TestUseNodeCIDR(c *C) { 40 // Test IPv4 41 node1 := v1.Node{ 42 ObjectMeta: metav1.ObjectMeta{ 43 Name: "node1", 44 Annotations: map[string]string{ 45 annotation.V4CIDRName: "10.254.0.0/16", 46 annotation.CiliumHostIP: "10.254.0.1", 47 }, 48 }, 49 Spec: v1.NodeSpec{ 50 PodCIDR: "10.2.0.0/16", 51 }, 52 } 53 54 // set buffer to 2 to prevent blocking when calling UseNodeCIDR 55 // and we need to wait for the response of the channel. 56 patchChan := make(chan bool, 2) 57 fakeK8sClient := &fake.Clientset{} 58 k8sCli.Interface = fakeK8sClient 59 fakeK8sClient.AddReactor("patch", "nodes", 60 func(action testing.Action) (bool, runtime.Object, error) { 61 // If subresource is empty it means we are patching status and not 62 // patching annotations 63 if action.GetSubresource() != "" { 64 return true, nil, nil 65 } 66 67 n1copy := node1.DeepCopy() 68 n1copy.Annotations[annotation.V4CIDRName] = "10.2.0.0/16" 69 raw, err := json.Marshal(n1copy.Annotations) 70 if err != nil { 71 c.Assert(err, IsNil) 72 } 73 patchWanted := []byte(fmt.Sprintf(`{"metadata":{"annotations":%s}}`, raw)) 74 75 patchReceived := action.(testing.PatchAction).GetPatch() 76 c.Assert(string(patchReceived), checker.DeepEquals, string(patchWanted)) 77 patchChan <- true 78 return true, n1copy, nil 79 }) 80 81 node1Slim := ConvertToNode(node1.DeepCopy()).(*types.Node) 82 node1Cilium := ParseNode(node1Slim, source.Unspec) 83 84 useNodeCIDR(node1Cilium) 85 c.Assert(node.GetIPv4AllocRange().String(), Equals, "10.2.0.0/16") 86 // IPv6 Node range is not checked because it shouldn't be changed. 87 88 err := k8sCli.AnnotateNode("node1", 89 node.GetIPv4AllocRange(), 90 node.GetIPv6NodeRange(), 91 nil, 92 nil, 93 net.ParseIP("10.254.0.1"), 94 net.ParseIP("")) 95 96 c.Assert(err, IsNil) 97 98 select { 99 case <-patchChan: 100 case <-time.Tick(10 * time.Second): 101 c.Errorf("d.fakeK8sClient.CoreV1().Nodes().Update() was not called") 102 c.FailNow() 103 } 104 105 // Test IPv6 106 node2 := v1.Node{ 107 ObjectMeta: metav1.ObjectMeta{ 108 Name: "node2", 109 Annotations: map[string]string{ 110 annotation.V4CIDRName: "10.254.0.0/16", 111 annotation.CiliumHostIP: "10.254.0.1", 112 }, 113 }, 114 Spec: v1.NodeSpec{ 115 PodCIDR: "aaaa:aaaa:aaaa:aaaa:beef:beef::/96", 116 }, 117 } 118 119 failAttempts := 0 120 121 fakeK8sClient = &fake.Clientset{} 122 k8sCli.Interface = fakeK8sClient 123 fakeK8sClient.AddReactor("patch", "nodes", 124 func(action testing.Action) (bool, runtime.Object, error) { 125 // If subresource is empty it means we are patching status and not 126 // patching annotations 127 if action.GetSubresource() != "" { 128 return true, nil, nil 129 } 130 // first call will be a patch for annotations 131 if failAttempts == 0 { 132 failAttempts++ 133 return true, nil, fmt.Errorf("failing on purpose") 134 } 135 n2Copy := node2.DeepCopy() 136 n2Copy.Annotations[annotation.V4CIDRName] = "10.254.0.0/16" 137 n2Copy.Annotations[annotation.V6CIDRName] = "aaaa:aaaa:aaaa:aaaa:beef:beef::/96" 138 raw, err := json.Marshal(n2Copy.Annotations) 139 if err != nil { 140 c.Assert(err, IsNil) 141 } 142 patchWanted := []byte(fmt.Sprintf(`{"metadata":{"annotations":%s}}`, raw)) 143 144 patchReceived := action.(testing.PatchAction).GetPatch() 145 c.Assert(string(patchReceived), checker.DeepEquals, string(patchWanted)) 146 patchChan <- true 147 return true, n2Copy, nil 148 }) 149 150 node2Slim := ConvertToNode(node2.DeepCopy()).(*types.Node) 151 node2Cilium := ParseNode(node2Slim, source.Unspec) 152 useNodeCIDR(node2Cilium) 153 154 // We use the node's annotation for the IPv4 and the PodCIDR for the 155 // IPv6. 156 c.Assert(node.GetIPv4AllocRange().String(), Equals, "10.254.0.0/16") 157 c.Assert(node.GetIPv6NodeRange().String(), Equals, "aaaa:aaaa:aaaa:aaaa:beef:beef::/96") 158 159 err = k8sCli.AnnotateNode("node2", 160 node.GetIPv4AllocRange(), 161 node.GetIPv6NodeRange(), 162 nil, 163 nil, 164 net.ParseIP("10.254.0.1"), 165 net.ParseIP("")) 166 167 c.Assert(err, IsNil) 168 169 select { 170 case <-patchChan: 171 case <-time.Tick(10 * time.Second): 172 c.Errorf("d.fakeK8sClient.CoreV1().Nodes().Update() was not called") 173 c.FailNow() 174 } 175 }