github.com/fafucoder/cilium@v1.6.11/daemon/status_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 main 18 19 import ( 20 "math/rand" 21 "time" 22 23 "github.com/cilium/cilium/api/v1/models" 24 . "github.com/cilium/cilium/api/v1/server/restapi/daemon" 25 "github.com/cilium/cilium/pkg/checker" 26 "github.com/cilium/cilium/pkg/datapath/fake" 27 "github.com/cilium/cilium/pkg/mtu" 28 "github.com/cilium/cilium/pkg/node/manager" 29 "github.com/cilium/cilium/pkg/nodediscovery" 30 "github.com/cilium/cilium/pkg/option" 31 32 "github.com/go-openapi/runtime/middleware" 33 . "gopkg.in/check.v1" 34 ) 35 36 type GetNodesSuite struct { 37 } 38 39 var _ = Suite(&GetNodesSuite{}) 40 41 var nm *manager.Manager 42 43 func (g *GetNodesSuite) SetUpTest(c *C) { 44 option.Config.IPv4ServiceRange = AutoCIDR 45 option.Config.IPv6ServiceRange = AutoCIDR 46 } 47 48 func (g *GetNodesSuite) SetUpSuite(c *C) { 49 var err error 50 nm, err = manager.NewManager("", fake.NewNodeHandler()) 51 c.Assert(err, IsNil) 52 } 53 54 func (g *GetNodesSuite) Test_getNodesHandle(c *C) { 55 // Set seed so we can have the same pseudorandom client IDs. 56 // The seed is set to 0 for each unit test. 57 rand.Seed(0) 58 const numberOfClients = 10 59 60 clientIDs := make([]int64, 0, numberOfClients) 61 for i := 0; i < numberOfClients; i++ { 62 clientIDs = append(clientIDs, rand.Int63()) 63 } 64 65 var zero int64 66 type args struct { 67 params GetClusterNodesParams 68 clients map[int64]*clusterNodesClient 69 daemon *Daemon 70 } 71 type want struct { 72 clients map[int64]*clusterNodesClient 73 responder *GetClusterNodesOK 74 } 75 tests := []struct { 76 name string 77 setupArgs func() args 78 setupWanted func() want 79 }{ 80 { 81 name: "create a client ID and store it locally", 82 setupArgs: func() args { 83 nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0)) 84 nodeDiscovery.LocalNode.Name = "foo" 85 return args{ 86 params: GetClusterNodesParams{ 87 ClientID: &zero, 88 }, 89 daemon: &Daemon{ 90 nodeDiscovery: nodeDiscovery, 91 }, 92 clients: map[int64]*clusterNodesClient{}, 93 } 94 }, 95 setupWanted: func() want { 96 m := &models.ClusterNodeStatus{ 97 ClientID: clientIDs[0], 98 Self: "foo", 99 } 100 return want{ 101 clients: map[int64]*clusterNodesClient{ 102 clientIDs[0]: { 103 ClusterNodeStatus: m, 104 }, 105 }, 106 responder: &GetClusterNodesOK{ 107 Payload: m, 108 }, 109 } 110 }, 111 }, 112 { 113 name: "retrieve nodes diff from a client that was already present", 114 setupArgs: func() args { 115 nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0)) 116 nodeDiscovery.LocalNode.Name = "foo" 117 return args{ 118 params: GetClusterNodesParams{ 119 ClientID: &clientIDs[0], 120 }, 121 daemon: &Daemon{ 122 nodeDiscovery: nodeDiscovery, 123 }, 124 clients: map[int64]*clusterNodesClient{ 125 clientIDs[0]: { 126 ClusterNodeStatus: &models.ClusterNodeStatus{ 127 ClientID: clientIDs[0], 128 Self: "foo", 129 NodesAdded: []*models.NodeElement{ 130 { 131 Name: "random-node-added", 132 }, 133 }, 134 }, 135 }, 136 }, 137 } 138 }, 139 setupWanted: func() want { 140 return want{ 141 // let's not forget once the server sends the diff to the 142 // client, the slice of nodes added and removed gets cleaned 143 // up 144 clients: map[int64]*clusterNodesClient{ 145 clientIDs[0]: { 146 ClusterNodeStatus: &models.ClusterNodeStatus{ 147 ClientID: clientIDs[0], 148 Self: "foo", 149 }, 150 }, 151 }, 152 responder: &GetClusterNodesOK{ 153 Payload: &models.ClusterNodeStatus{ 154 ClientID: clientIDs[0], 155 Self: "foo", 156 NodesAdded: []*models.NodeElement{ 157 { 158 Name: "random-node-added", 159 }, 160 }, 161 }, 162 }, 163 } 164 }, 165 }, 166 { 167 name: "retrieve nodes from an expired client, it should be ok because the clean up only happens when on insertion", 168 setupArgs: func() args { 169 nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0)) 170 nodeDiscovery.LocalNode.Name = "foo" 171 return args{ 172 params: GetClusterNodesParams{ 173 ClientID: &clientIDs[0], 174 }, 175 daemon: &Daemon{ 176 nodeDiscovery: nodeDiscovery, 177 }, 178 clients: map[int64]*clusterNodesClient{ 179 clientIDs[0]: { 180 lastSync: time.Now().Add(-clientGCTimeout), 181 ClusterNodeStatus: &models.ClusterNodeStatus{ 182 ClientID: clientIDs[0], 183 Self: "foo", 184 NodesAdded: []*models.NodeElement{ 185 { 186 Name: "random-node-added", 187 }, 188 }, 189 }, 190 }, 191 }, 192 } 193 }, 194 setupWanted: func() want { 195 return want{ 196 // let's not forget once the server sends the diff to the 197 // client, the slice of nodes added and removed gets cleaned 198 // up 199 clients: map[int64]*clusterNodesClient{ 200 clientIDs[0]: { 201 ClusterNodeStatus: &models.ClusterNodeStatus{ 202 ClientID: clientIDs[0], 203 Self: "foo", 204 }, 205 }, 206 }, 207 responder: &GetClusterNodesOK{ 208 Payload: &models.ClusterNodeStatus{ 209 ClientID: clientIDs[0], 210 Self: "foo", 211 NodesAdded: []*models.NodeElement{ 212 { 213 Name: "random-node-added", 214 }, 215 }, 216 }, 217 }, 218 } 219 }, 220 }, 221 { 222 name: "retrieve nodes for a new client, the expired client should be deleted", 223 setupArgs: func() args { 224 nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0)) 225 nodeDiscovery.LocalNode.Name = "foo" 226 return args{ 227 params: GetClusterNodesParams{ 228 ClientID: &zero, 229 }, 230 daemon: &Daemon{ 231 nodeDiscovery: nodeDiscovery, 232 }, 233 clients: map[int64]*clusterNodesClient{ 234 clientIDs[numberOfClients-1]: { 235 lastSync: time.Now().Add(-clientGCTimeout), 236 ClusterNodeStatus: &models.ClusterNodeStatus{ 237 ClientID: clientIDs[numberOfClients-1], 238 Self: "foo", 239 NodesAdded: []*models.NodeElement{ 240 { 241 Name: "random-node-added", 242 }, 243 }, 244 }, 245 }, 246 }, 247 } 248 }, 249 setupWanted: func() want { 250 return want{ 251 // let's not forget once the server sends the diff to the 252 // client, the slice of nodes added and removed gets cleaned 253 // up 254 clients: map[int64]*clusterNodesClient{ 255 clientIDs[0]: { 256 ClusterNodeStatus: &models.ClusterNodeStatus{ 257 ClientID: clientIDs[0], 258 Self: "foo", 259 }, 260 }, 261 }, 262 responder: &GetClusterNodesOK{ 263 Payload: &models.ClusterNodeStatus{ 264 ClientID: clientIDs[0], 265 Self: "foo", 266 }, 267 }, 268 } 269 }, 270 }, 271 { 272 name: "retrieve nodes for a new client, however the randomizer allocated an existing clientID, so we should return a empty clientID", 273 setupArgs: func() args { 274 nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0)) 275 nodeDiscovery.LocalNode.Name = "foo" 276 return args{ 277 params: GetClusterNodesParams{ 278 ClientID: &zero, 279 }, 280 daemon: &Daemon{ 281 nodeDiscovery: nodeDiscovery, 282 }, 283 clients: map[int64]*clusterNodesClient{ 284 clientIDs[0]: { 285 ClusterNodeStatus: &models.ClusterNodeStatus{ 286 ClientID: clientIDs[0], 287 Self: "foo", 288 NodesAdded: []*models.NodeElement{ 289 { 290 Name: "random-node-added", 291 }, 292 }, 293 }, 294 }, 295 }, 296 } 297 }, 298 setupWanted: func() want { 299 return want{ 300 clients: map[int64]*clusterNodesClient{ 301 clientIDs[0]: { 302 ClusterNodeStatus: &models.ClusterNodeStatus{ 303 ClientID: clientIDs[0], 304 Self: "foo", 305 NodesAdded: []*models.NodeElement{ 306 { 307 Name: "random-node-added", 308 }, 309 }, 310 }, 311 }, 312 }, 313 responder: &GetClusterNodesOK{ 314 Payload: &models.ClusterNodeStatus{ 315 Self: "foo", 316 }, 317 }, 318 } 319 }, 320 }, 321 { 322 name: "retrieve nodes for a client that does not want to have diffs, leave all other stored clients alone", 323 setupArgs: func() args { 324 nodeDiscovery := nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0)) 325 nodeDiscovery.LocalNode.Name = "foo" 326 return args{ 327 params: GetClusterNodesParams{}, 328 daemon: &Daemon{ 329 nodeDiscovery: nodeDiscovery, 330 }, 331 clients: map[int64]*clusterNodesClient{ 332 clientIDs[0]: { 333 ClusterNodeStatus: &models.ClusterNodeStatus{ 334 ClientID: clientIDs[0], 335 Self: "foo", 336 NodesAdded: []*models.NodeElement{ 337 { 338 Name: "random-node-added", 339 }, 340 }, 341 }, 342 }, 343 }, 344 } 345 }, 346 setupWanted: func() want { 347 return want{ 348 clients: map[int64]*clusterNodesClient{ 349 clientIDs[0]: { 350 ClusterNodeStatus: &models.ClusterNodeStatus{ 351 ClientID: clientIDs[0], 352 Self: "foo", 353 NodesAdded: []*models.NodeElement{ 354 { 355 Name: "random-node-added", 356 }, 357 }, 358 }, 359 }, 360 }, 361 responder: &GetClusterNodesOK{ 362 Payload: &models.ClusterNodeStatus{ 363 Self: "foo", 364 }, 365 }, 366 } 367 }, 368 }, 369 } 370 371 for _, tt := range tests { 372 c.Log(tt.name) 373 rand.Seed(0) 374 args := tt.setupArgs() 375 want := tt.setupWanted() 376 h := &getNodes{ 377 clients: args.clients, 378 d: args.daemon, 379 } 380 responder := h.Handle(args.params) 381 c.Assert(len(h.clients), checker.DeepEquals, len(want.clients)) 382 for k, v := range h.clients { 383 wantClient, ok := want.clients[k] 384 c.Assert(ok, Equals, true) 385 c.Assert(v.ClusterNodeStatus, checker.DeepEquals, wantClient.ClusterNodeStatus) 386 } 387 c.Assert(responder, checker.DeepEquals, middleware.Responder(want.responder)) 388 } 389 } 390 391 func (g *GetNodesSuite) Test_cleanupClients(c *C) { 392 now := time.Now() 393 type args struct { 394 clients map[int64]*clusterNodesClient 395 } 396 tests := []struct { 397 name string 398 setupArgs func() args 399 setupWanted func() args 400 }{ 401 { 402 name: "delete expired clients", 403 setupArgs: func() args { 404 return args{ 405 clients: map[int64]*clusterNodesClient{ 406 0: { 407 lastSync: now.Add(-clientGCTimeout), 408 }, 409 1: { 410 lastSync: now, 411 }, 412 }, 413 } 414 }, 415 setupWanted: func() args { 416 return args{ 417 clients: map[int64]*clusterNodesClient{ 418 1: { 419 lastSync: now, 420 }, 421 }, 422 } 423 }, 424 }, 425 } 426 427 for _, tt := range tests { 428 c.Log(tt.name) 429 args := tt.setupArgs() 430 want := tt.setupWanted() 431 h := &getNodes{ 432 clients: args.clients, 433 d: &Daemon{ 434 nodeDiscovery: nodediscovery.NewNodeDiscovery(nm, mtu.NewConfiguration(0, false, false, 0)), 435 }, 436 } 437 h.cleanupClients() 438 c.Assert(h.clients, checker.DeepEquals, want.clients) 439 } 440 }