github.com/imran-kn/cilium-fork@v1.6.9/pkg/k8s/informer/benchmarks/informer_benchmarks_test.go (about) 1 // Copyright 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 benchmarks 18 19 import ( 20 "encoding/json" 21 "os" 22 "strconv" 23 "sync" 24 "testing" 25 26 "github.com/cilium/cilium/pkg/annotation" 27 "github.com/cilium/cilium/pkg/k8s" 28 "github.com/cilium/cilium/pkg/k8s/informer" 29 30 "github.com/cilium/cilium/pkg/defaults" 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/apimachinery/pkg/util/wait" 36 "k8s.io/apimachinery/pkg/watch" 37 "k8s.io/client-go/tools/cache" 38 ) 39 40 func Test(t *testing.T) { 41 TestingT(t) 42 } 43 44 type K8sIntegrationSuite struct{} 45 46 var _ = Suite(&K8sIntegrationSuite{}) 47 48 func (k *K8sIntegrationSuite) SetUpSuite(c *C) { 49 if os.Getenv("INTEGRATION") != "" { 50 if k8sConfigPath := os.Getenv("KUBECONFIG"); k8sConfigPath == "" { 51 k8s.Configure("", "/var/lib/cilium/cilium.kubeconfig", defaults.K8sClientQPSLimit, defaults.K8sClientBurst) 52 } else { 53 k8s.Configure("", k8sConfigPath, defaults.K8sClientQPSLimit, defaults.K8sClientBurst) 54 } 55 } 56 } 57 58 var nodeSampleJSON = `{ 59 "apiVersion": "v1", 60 "kind": "Node", 61 "metadata": { 62 "annotations": { 63 "container.googleapis.com/instance_id": "111111111111111111", 64 "io.cilium.network.ipv4-cilium-host": "10.0.0.1", 65 "io.cilium.network.ipv4-health-ip": "10.0.0.1", 66 "io.cilium.network.ipv4-pod-cidr": "10.0.0.1/27", 67 "node.alpha.kubernetes.io/ttl": "30", 68 "volumes.kubernetes.io/controller-managed-attach-detach": "true" 69 }, 70 "creationTimestamp": "2019-03-07T13:35:02Z", 71 "labels": { 72 "beta.kubernetes.io/arch": "amd64", 73 "beta.kubernetes.io/fluentd-ds-ready": "true", 74 "beta.kubernetes.io/instance-type": "foo", 75 "beta.kubernetes.io/os": "linux", 76 "cloud.google.com/gke-nodepool": "default-pool", 77 "cloud.google.com/gke-os-distribution": "cos", 78 "disktype": "ssd", 79 "failure-domain.beta.kubernetes.io/region": "earth", 80 "failure-domain.beta.kubernetes.io/zone": "earth", 81 "kubernetes.io/hostname": "super-node" 82 }, 83 "name": "super-node", 84 "resourceVersion": "0", 85 "selfLink": "/api/v1/nodes/super-node", 86 "uid": "cf66ea66-40dd-11e9-bcdf-4201ac100009" 87 }, 88 "spec": { 89 "podCIDR": "10.0.0.1/16", 90 "providerID": "gce://universe/earth/super-node" 91 }, 92 "status": { 93 "addresses": [ 94 { 95 "address": "10.0.0.1", 96 "type": "InternalIP" 97 }, 98 { 99 "address": "", 100 "type": "ExternalIP" 101 }, 102 { 103 "address": "super-node.c.earth.internal", 104 "type": "InternalDNS" 105 }, 106 { 107 "address": "super-node.c.earth.internal", 108 "type": "Hostname" 109 } 110 ], 111 "allocatable": { 112 "attachable-volumes-gce-pd": "0", 113 "cpu": "0m", 114 "ephemeral-storage": "0", 115 "hugepages-2Mi": "0", 116 "memory": "0", 117 "pods": "0" 118 }, 119 "capacity": { 120 "attachable-volumes-gce-pd": "16", 121 "cpu": "4", 122 "ephemeral-storage": "26615568Ki", 123 "hugepages-2Mi": "0", 124 "memory": "8173944Ki", 125 "pods": "16" 126 }, 127 "conditions": [ 128 { 129 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 130 "lastTransitionTime": "2019-03-07T13:40:03Z", 131 "message": "kubelet is functioning properly", 132 "reason": "FrequentKubeletRestart", 133 "status": "False", 134 "type": "FrequentKubeletRestart" 135 }, 136 { 137 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 138 "lastTransitionTime": "2019-03-07T13:40:04Z", 139 "message": "docker is functioning properly", 140 "reason": "FrequentDockerRestart", 141 "status": "False", 142 "type": "FrequentDockerRestart" 143 }, 144 { 145 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 146 "lastTransitionTime": "2019-03-07T13:40:05Z", 147 "message": "containerd is functioning properly", 148 "reason": "FrequentContainerdRestart", 149 "status": "False", 150 "type": "FrequentContainerdRestart" 151 }, 152 { 153 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 154 "lastTransitionTime": "2019-03-07T13:40:03Z", 155 "message": "docker overlay2 is functioning properly", 156 "reason": "CorruptDockerOverlay2", 157 "status": "False", 158 "type": "CorruptDockerOverlay2" 159 }, 160 { 161 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 162 "lastTransitionTime": "2019-03-07T13:35:01Z", 163 "message": "kernel has no deadlock", 164 "reason": "KernelHasNoDeadlock", 165 "status": "False", 166 "type": "KernelDeadlock" 167 }, 168 { 169 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 170 "lastTransitionTime": "2019-03-07T13:35:01Z", 171 "message": "Filesystem is not read-only", 172 "reason": "FilesystemIsNotReadOnly", 173 "status": "False", 174 "type": "ReadonlyFilesystem" 175 }, 176 { 177 "lastHeartbeatTime": "2019-03-15T10:49:17Z", 178 "lastTransitionTime": "2019-03-07T13:40:03Z", 179 "message": "node is functioning properly", 180 "reason": "UnregisterNetDevice", 181 "status": "False", 182 "type": "FrequentUnregisterNetDevice" 183 }, 184 { 185 "lastHeartbeatTime": "2019-03-15T10:44:54Z", 186 "lastTransitionTime": "2019-03-15T10:44:54Z", 187 "message": "NodeController create implicit route", 188 "reason": "RouteCreated", 189 "status": "False", 190 "type": "NetworkUnavailable" 191 }, 192 { 193 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 194 "lastTransitionTime": "2019-03-07T13:35:02Z", 195 "message": "kubelet has sufficient disk space available", 196 "reason": "KubeletHasSufficientDisk", 197 "status": "False", 198 "type": "OutOfDisk" 199 }, 200 { 201 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 202 "lastTransitionTime": "2019-03-07T13:35:02Z", 203 "message": "kubelet has sufficient memory available", 204 "reason": "KubeletHasSufficientMemory", 205 "status": "False", 206 "type": "MemoryPressure" 207 }, 208 { 209 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 210 "lastTransitionTime": "2019-03-07T13:35:02Z", 211 "message": "kubelet has no disk pressure", 212 "reason": "KubeletHasNoDiskPressure", 213 "status": "False", 214 "type": "DiskPressure" 215 }, 216 { 217 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 218 "lastTransitionTime": "2019-03-07T13:35:02Z", 219 "message": "kubelet has sufficient PID available", 220 "reason": "KubeletHasSufficientPID", 221 "status": "False", 222 "type": "PIDPressure" 223 }, 224 { 225 "lastHeartbeatTime": "2019-03-15T10:49:57Z", 226 "lastTransitionTime": "2019-03-07T13:36:12Z", 227 "message": "kubelet is posting ready status. AppArmor enabled", 228 "reason": "KubeletReady", 229 "status": "True", 230 "type": "Ready" 231 } 232 ], 233 "daemonEndpoints": { 234 "kubeletEndpoint": { 235 "Port": 10250 236 } 237 }, 238 "images": [ 239 { 240 "names": [ 241 "quay.io/cilium/cilium-dev@sha256:53e005e8ae3649412cfb5b5538916bc6c9f66c408ee6a76273e964a285cb28aa", 242 "quay.io/cilium/cilium-dev:scale-test-2019-03-13" 243 ], 244 "sizeBytes": 618888533 245 }, 246 { 247 "names": [ 248 "quay.io/cilium/cilium@sha256:9f41fc120b2c8cf5006220bcea7ee17c573cb13f0d32b0578ea83690f6412b6e", 249 "quay.io/cilium/cilium:latest" 250 ], 251 "sizeBytes": 618884013 252 }, 253 { 254 "names": [ 255 "quay.io/cilium/cilium-dev@sha256:41b2bc225d90a52cbf04f030fd4e4bb8235e00262e08643963dd887090d17b96", 256 "quay.io/cilium/cilium-dev:scale-test-2019-03-12" 257 ], 258 "sizeBytes": 618855547 259 }, 260 { 261 "names": [ 262 "cilium/cilium@sha256:bb8a0507c1850f856d7c3e1ab27fa8246d666dcf5bab9040ced3d6513e730b02", 263 "cilium/cilium:latest" 264 ], 265 "sizeBytes": 618841491 266 }, 267 { 268 "names": [ 269 "cilium/cilium@sha256:2d0ea8c2eee882c7005d5645f349f58bca57fcd8e2e682a517c400ccd045f9c2" 270 ], 271 "sizeBytes": 618821939 272 }, 273 { 274 "names": [ 275 "cilium/cilium-dev@sha256:c55141a813d30123c34372b87d75c3b8ff4eaf955ff0531f93ec2a8fbd2d6dff", 276 "cilium/cilium-dev:tgraf-scale-fixes2" 277 ], 278 "sizeBytes": 618670939 279 }, 280 { 281 "names": [ 282 "k8s.gcr.io/node-problem-detector@sha256:f95cab985c26b2f46e9bd43283e0bfa88860c14e0fb0649266babe8b65e9eb2b", 283 "k8s.gcr.io/node-problem-detector:v0.4.1" 284 ], 285 "sizeBytes": 286572743 286 }, 287 { 288 "names": [ 289 "grafana/grafana@sha256:b5098a06dc59d28b11120eab01d8d0147b526a175aa606f9978934b6b2224138", 290 "grafana/grafana:6.0.0" 291 ], 292 "sizeBytes": 256099268 293 }, 294 { 295 "names": [ 296 "quay.io/coreos/etcd-operator@sha256:3633b6d103e9efc2798e4214c8ee6d9b78f262eca65f085d76f5b4aee77e1e95", 297 "quay.io/coreos/etcd-operator:v0.9.3" 298 ], 299 "sizeBytes": 150833530 300 }, 301 { 302 "names": [ 303 "k8s.gcr.io/fluentd-elasticsearch@sha256:a54e7a450c0bdd19f49f56e487427a08c50f99ea8f8846179acf7d4182ce1fc0", 304 "k8s.gcr.io/fluentd-elasticsearch:v2.2.0" 305 ], 306 "sizeBytes": 138313727 307 }, 308 { 309 "names": [ 310 "k8s.gcr.io/fluentd-gcp-scaler@sha256:457a13df66534b94bab627c4c2dc2df0ee5153a5d0f0afd27502bd46bd8da81d", 311 "k8s.gcr.io/fluentd-gcp-scaler:0.5" 312 ], 313 "sizeBytes": 103488147 314 }, 315 { 316 "names": [ 317 "k8s.gcr.io/kubernetes-dashboard-amd64@sha256:dc4026c1b595435ef5527ca598e1e9c4343076926d7d62b365c44831395adbd0", 318 "k8s.gcr.io/kubernetes-dashboard-amd64:v1.8.3" 319 ], 320 "sizeBytes": 102319441 321 }, 322 { 323 "names": [ 324 "gcr.io/google_containers/kube-proxy:v1.12.5-gke.10", 325 "k8s.gcr.io/kube-proxy:v1.12.5-gke.10" 326 ], 327 "sizeBytes": 101370340 328 }, 329 { 330 "names": [ 331 "k8s.gcr.io/event-exporter@sha256:7f9cd7cb04d6959b0aa960727d04fa86759008048c785397b7b0d9dff0007516", 332 "k8s.gcr.io/event-exporter:v0.2.3" 333 ], 334 "sizeBytes": 94171943 335 }, 336 { 337 "names": [ 338 "gcr.io/google-containers/prometheus-to-sd@sha256:6c0c742475363d537ff059136e5d5e4ab1f512ee0fd9b7ca42ea48bc309d1662", 339 "k8s.gcr.io/prometheus-to-sd@sha256:6c0c742475363d537ff059136e5d5e4ab1f512ee0fd9b7ca42ea48bc309d1662", 340 "gcr.io/google-containers/prometheus-to-sd:v0.3.1", 341 "k8s.gcr.io/prometheus-to-sd:v0.3.1" 342 ], 343 "sizeBytes": 88077694 344 }, 345 { 346 "names": [ 347 "k8s.gcr.io/heapster-amd64@sha256:9fae0af136ce0cf4f88393b3670f7139ffc464692060c374d2ae748e13144521", 348 "k8s.gcr.io/heapster-amd64:v1.6.0-beta.1" 349 ], 350 "sizeBytes": 76016169 351 }, 352 { 353 "names": [ 354 "k8s.gcr.io/ingress-gce-glbc-amd64@sha256:14f14351a03038b238232e60850a9cfa0dffbed0590321ef84216a432accc1ca", 355 "k8s.gcr.io/ingress-gce-glbc-amd64:v1.2.3" 356 ], 357 "sizeBytes": 71797285 358 }, 359 { 360 "names": [ 361 "quay.io/cilium/cilium-dev@sha256:d8bb81b46f9e10e40ca106bc6a9ac0f3365e5310bbb5bfba1f52d1d8c8b64740", 362 "quay.io/cilium/cilium-dev:vetcd-v3.3.11-hf1-aanm" 363 ], 364 "sizeBytes": 64108258 365 }, 366 { 367 "names": [ 368 "k8s.gcr.io/kube-addon-manager@sha256:d53486c3a0b49ebee019932878dc44232735d5622a51dbbdcec7124199020d09", 369 "k8s.gcr.io/kube-addon-manager:v8.7" 370 ], 371 "sizeBytes": 63322109 372 }, 373 { 374 "names": [ 375 "k8s.gcr.io/cpvpa-amd64@sha256:cfe7b0a11c9c8e18c87b1eb34fef9a7cbb8480a8da11fc2657f78dbf4739f869", 376 "k8s.gcr.io/cpvpa-amd64:v0.6.0" 377 ], 378 "sizeBytes": 51785854 379 }, 380 { 381 "names": [ 382 "k8s.gcr.io/k8s-dns-kube-dns-amd64@sha256:618a82fa66cf0c75e4753369a6999032372be7308866fc9afb381789b1e5ad52", 383 "k8s.gcr.io/k8s-dns-kube-dns@sha256:c54a527a4ba8f1bc15e4796b09bf5d69313c7f42af9911dc437e056c0264a2fe", 384 "k8s.gcr.io/k8s-dns-kube-dns-amd64:1.14.13", 385 "k8s.gcr.io/k8s-dns-kube-dns:1.14.13" 386 ], 387 "sizeBytes": 51157394 388 }, 389 { 390 "names": [ 391 "k8s.gcr.io/cluster-proportional-autoscaler-amd64@sha256:36359630278b119e7dd78f5437be1c667080108fa59ecba1b81cda3610dcf4d7", 392 "k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.2.0" 393 ], 394 "sizeBytes": 50258329 395 }, 396 { 397 "names": [ 398 "k8s.gcr.io/cluster-proportional-autoscaler-amd64@sha256:003f98d9f411ddfa6ff6d539196355e03ddd69fa4ed38c7ffb8fec6f729afe2d", 399 "k8s.gcr.io/cluster-proportional-autoscaler-amd64:1.1.2-r2" 400 ], 401 "sizeBytes": 49648481 402 }, 403 { 404 "names": [ 405 "k8s.gcr.io/ip-masq-agent-amd64@sha256:1ffda57d87901bc01324c82ceb2145fe6a0448d3f0dd9cb65aa76a867cd62103", 406 "k8s.gcr.io/ip-masq-agent-amd64:v2.1.1" 407 ], 408 "sizeBytes": 49612505 409 }, 410 { 411 "names": [ 412 "quay.io/cilium/operator-dev@sha256:ab697ec83f8e3da7e64630c67252a5cf2ac4017ce2414c6c1d5476e165a844c6", 413 "quay.io/cilium/operator-dev:scale-test-2019-03-12" 414 ], 415 "sizeBytes": 48754920 416 } 417 ], 418 "nodeInfo": { 419 "architecture": "amd64", 420 "bootID": "999999999999999999999999999", 421 "containerRuntimeVersion": "docker://17.3.2", 422 "kernelVersion": "4.14.91+", 423 "kubeProxyVersion": "v1.12.5", 424 "kubeletVersion": "v1.12.5", 425 "machineID": "999999999999999999999999999", 426 "operatingSystem": "linux", 427 "osImage": "Container-Optimized OS from Google", 428 "systemUUID": "999999999999999999999999999" 429 } 430 } 431 } 432 ` 433 434 func (k *K8sIntegrationSuite) benchmarkInformer(nCycles int, newInformer bool, c *C) { 435 n := v1.Node{} 436 err := json.Unmarshal([]byte(nodeSampleJSON), &n) 437 n.ResourceVersion = "1" 438 c.Assert(err, IsNil) 439 w := watch.NewFakeWithChanSize(nCycles, false) 440 wg := sync.WaitGroup{} 441 442 lw := &cache.ListWatch{ 443 ListFunc: func(_ metav1.ListOptions) (runtime.Object, error) { 444 return &v1.NodeList{ 445 Items: []v1.Node{n}, 446 }, nil 447 }, 448 WatchFunc: func(_ metav1.ListOptions) (watch.Interface, error) { 449 return w, nil 450 }, 451 } 452 453 if newInformer { 454 _, controller := informer.NewInformer( 455 lw, 456 &v1.Node{}, 457 0, 458 cache.ResourceEventHandlerFuncs{ 459 AddFunc: func(obj interface{}) {}, 460 UpdateFunc: func(oldObj, newObj interface{}) { 461 if oldK8sNP := k8s.CopyObjToV1Node(oldObj); oldK8sNP != nil { 462 if newK8sNP := k8s.CopyObjToV1Node(newObj); newK8sNP != nil { 463 if k8s.EqualV1Node(oldK8sNP, newK8sNP) { 464 return 465 } 466 } 467 } 468 }, 469 DeleteFunc: func(obj interface{}) { 470 k8sNP := k8s.CopyObjToV1Node(obj) 471 if k8sNP == nil { 472 deletedObj, ok := obj.(cache.DeletedFinalStateUnknown) 473 if !ok { 474 return 475 } 476 // Delete was not observed by the watcher but is 477 // removed from kube-apiserver. This is the last 478 // known state and the object no longer exists. 479 k8sNP = k8s.CopyObjToV1Node(deletedObj.Obj) 480 if k8sNP == nil { 481 return 482 } 483 } 484 wg.Done() 485 }, 486 }, 487 k8s.ConvertToNode, 488 ) 489 go controller.Run(wait.NeverStop) 490 } else { 491 _, controller := cache.NewInformer( 492 lw, 493 &v1.Node{}, 494 0, 495 cache.ResourceEventHandlerFuncs{ 496 AddFunc: func(obj interface{}) {}, 497 UpdateFunc: func(oldObj, newObj interface{}) { 498 if oldK8sNP := OldCopyObjToV1Node(oldObj); oldK8sNP != nil { 499 if newK8sNP := OldCopyObjToV1Node(newObj); newK8sNP != nil { 500 if OldEqualV1Node(oldK8sNP, newK8sNP) { 501 return 502 } 503 } 504 } 505 }, 506 DeleteFunc: func(obj interface{}) { 507 k8sNP := OldCopyObjToV1Node(obj) 508 if k8sNP == nil { 509 deletedObj, ok := obj.(cache.DeletedFinalStateUnknown) 510 if !ok { 511 return 512 } 513 // Delete was not observed by the watcher but is 514 // removed from kube-apiserver. This is the last 515 // known state and the object no longer exists. 516 k8sNP = OldCopyObjToV1Node(deletedObj.Obj) 517 if k8sNP == nil { 518 return 519 } 520 } 521 wg.Done() 522 }, 523 }, 524 ) 525 go controller.Run(wait.NeverStop) 526 } 527 528 wg.Add(1) 529 c.ResetTimer() 530 for i := 2; i <= nCycles; i++ { 531 n.ResourceVersion = strconv.Itoa(i) 532 w.Action(watch.Modified, &n) 533 } 534 w.Action(watch.Deleted, &n) 535 wg.Wait() 536 c.StopTimer() 537 } 538 539 func OldEqualV1Node(node1, node2 *v1.Node) bool { 540 // The only information we care about the node is it's annotations, in 541 // particularly the CiliumHostIP annotation. 542 return node1.GetObjectMeta().GetName() == node2.GetObjectMeta().GetName() && 543 node1.GetAnnotations()[annotation.CiliumHostIP] == node2.GetAnnotations()[annotation.CiliumHostIP] 544 } 545 546 func OldCopyObjToV1Node(obj interface{}) *v1.Node { 547 node, ok := obj.(*v1.Node) 548 if !ok { 549 return nil 550 } 551 return node.DeepCopy() 552 } 553 554 func (k *K8sIntegrationSuite) Benchmark_Informer(c *C) { 555 nCycles, err := strconv.Atoi(os.Getenv("CYCLES")) 556 if err != nil { 557 nCycles = c.N 558 } 559 560 k.benchmarkInformer(nCycles, true, c) 561 } 562 563 func (k *K8sIntegrationSuite) Benchmark_K8sInformer(c *C) { 564 nCycles, err := strconv.Atoi(os.Getenv("CYCLES")) 565 if err != nil { 566 nCycles = c.N 567 } 568 569 k.benchmarkInformer(nCycles, false, c) 570 }