github.com/GoogleContainerTools/skaffold@v1.39.18/pkg/skaffold/kubernetes/debugging/debug_test.go (about) 1 /* 2 Copyright 2021 The Skaffold Authors 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package debugging 18 19 import ( 20 "bytes" 21 "strings" 22 "testing" 23 24 v1 "k8s.io/api/core/v1" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 27 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug" 28 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/debug/types" 29 "github.com/GoogleContainerTools/skaffold/pkg/skaffold/kubernetes/manifest" 30 "github.com/GoogleContainerTools/skaffold/testutil" 31 ) 32 33 // testTransformer is a simple transformer that applies to everything 34 type testTransformer struct{} 35 36 func (t testTransformer) IsApplicable(config debug.ImageConfiguration) bool { 37 return true 38 } 39 40 func (t testTransformer) Apply(adapter types.ContainerAdapter, config debug.ImageConfiguration, portAlloc debug.PortAllocator, overrideProtocols []string) (types.ContainerDebugConfiguration, string, error) { 41 port := portAlloc(9999) 42 container := adapter.GetContainer() 43 container.Ports = append(container.Ports, types.ContainerPort{Name: "test", ContainerPort: port}) 44 45 testEnv := types.ContainerEnv{Order: []string{"KEY"}, Env: map[string]string{"KEY": "value"}} 46 container.Env = testEnv 47 48 return types.ContainerDebugConfiguration{Runtime: "test"}, "", nil 49 } 50 51 func TestPodEncodeDecode(t *testing.T) { 52 pod := &v1.Pod{ 53 TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.Version, Kind: "Pod"}, 54 ObjectMeta: metav1.ObjectMeta{Name: "podname"}, 55 Spec: v1.PodSpec{Containers: []v1.Container{{Name: "name1", Image: "image1"}}}} 56 b, err := encodeAsYaml(pod) 57 if err != nil { 58 t.Errorf("encodeAsYaml() failed: %v", err) 59 return 60 } 61 o, _, err := decodeFromYaml(b, nil, nil) 62 if err != nil { 63 t.Errorf("decodeFromYaml() failed: %v", err) 64 return 65 } 66 switch o := o.(type) { 67 case *v1.Pod: 68 testutil.CheckDeepEqual(t, "podname", o.ObjectMeta.Name) 69 testutil.CheckDeepEqual(t, 1, len(o.Spec.Containers)) 70 testutil.CheckDeepEqual(t, "name1", o.Spec.Containers[0].Name) 71 testutil.CheckDeepEqual(t, "image1", o.Spec.Containers[0].Image) 72 default: 73 t.Errorf("decodeFromYaml() failed: expected *v1.Pod but got %T", o) 74 } 75 } 76 77 // TestSkipAnnotatedPodSpec verifies that transformPodSpec skips podspecs that have a 78 // `debug.cloud.google.com/config` annotation. 79 func TestSkipAnnotatedPodSpec(t *testing.T) { 80 tfm := testTransformer{} 81 debug.RegisterContainerTransformer(tfm) 82 defer debug.UnregisterContainerTransformer(tfm) 83 84 pod := v1.Pod{ 85 TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.Version, Kind: "Pod"}, 86 ObjectMeta: metav1.ObjectMeta{Name: "podname", Annotations: map[string]string{"debug.cloud.google.com/config": "{}"}}, 87 Spec: v1.PodSpec{Containers: []v1.Container{{Name: "name1", Image: "image1"}}}} 88 89 retriever := func(image string) (debug.ImageConfiguration, error) { 90 return debug.ImageConfiguration{WorkingDir: "/a/dir"}, nil 91 } 92 93 copy := pod 94 result := transformManifest(&pod, retriever, "HELPERS") 95 testutil.CheckDeepEqual(t, false, result) 96 testutil.CheckDeepEqual(t, copy, pod) // should be unchanged 97 } 98 99 func TestApplyDebuggingTransforms(t *testing.T) { 100 tfm := testTransformer{} 101 debug.RegisterContainerTransformer(tfm) 102 defer debug.UnregisterContainerTransformer(tfm) 103 104 tests := []struct { 105 description string 106 shouldErr bool 107 in string 108 out string 109 }{ 110 { 111 "Pod", false, 112 `apiVersion: v1 113 kind: Pod 114 metadata: 115 name: pod 116 spec: 117 containers: 118 - image: gcr.io/k8s-debug/debug-example:latest 119 name: example 120 `, 121 `apiVersion: v1 122 kind: Pod 123 metadata: 124 annotations: 125 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 126 creationTimestamp: null 127 name: pod 128 spec: 129 containers: 130 - env: 131 - name: KEY 132 value: value 133 image: gcr.io/k8s-debug/debug-example:latest 134 name: example 135 ports: 136 - containerPort: 9999 137 name: test 138 resources: {} 139 status: {}`, 140 }, 141 { 142 "Deployment", false, 143 `apiVersion: apps/v1 144 kind: Deployment 145 metadata: 146 name: my-app 147 spec: 148 replicas: 10 149 selector: 150 matchLabels: 151 app: debug-app 152 template: 153 metadata: 154 labels: 155 app: debug-app 156 name: debug-pod 157 spec: 158 containers: 159 - image: gcr.io/k8s-debug/debug-example:latest 160 name: example 161 `, 162 `apiVersion: apps/v1 163 kind: Deployment 164 metadata: 165 creationTimestamp: null 166 name: my-app 167 spec: 168 replicas: 1 169 selector: 170 matchLabels: 171 app: debug-app 172 strategy: {} 173 template: 174 metadata: 175 annotations: 176 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 177 creationTimestamp: null 178 labels: 179 app: debug-app 180 name: debug-pod 181 spec: 182 containers: 183 - env: 184 - name: KEY 185 value: value 186 image: gcr.io/k8s-debug/debug-example:latest 187 name: example 188 ports: 189 - containerPort: 9999 190 name: test 191 resources: {} 192 status: {}`, 193 }, 194 { 195 "ReplicaSet", false, 196 `apiVersion: apps/v1 197 kind: ReplicaSet 198 metadata: 199 name: my-replicaset 200 spec: 201 replicas: 10 202 selector: 203 matchLabels: 204 app: debug-app 205 template: 206 metadata: 207 labels: 208 app: debug-app 209 name: debug-pod 210 spec: 211 containers: 212 - image: gcr.io/k8s-debug/debug-example:latest 213 name: example 214 `, 215 `apiVersion: apps/v1 216 kind: ReplicaSet 217 metadata: 218 creationTimestamp: null 219 name: my-replicaset 220 spec: 221 replicas: 1 222 selector: 223 matchLabels: 224 app: debug-app 225 template: 226 metadata: 227 annotations: 228 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 229 creationTimestamp: null 230 labels: 231 app: debug-app 232 name: debug-pod 233 spec: 234 containers: 235 - env: 236 - name: KEY 237 value: value 238 image: gcr.io/k8s-debug/debug-example:latest 239 name: example 240 ports: 241 - containerPort: 9999 242 name: test 243 resources: {} 244 status: 245 replicas: 0`, 246 }, 247 { 248 "StatefulSet", false, 249 `apiVersion: apps/v1 250 kind: StatefulSet 251 metadata: 252 name: my-statefulset 253 spec: 254 replicas: 10 255 selector: 256 matchLabels: 257 app: debug-app 258 serviceName: service 259 template: 260 metadata: 261 labels: 262 app: debug-app 263 name: debug-pod 264 spec: 265 containers: 266 - image: gcr.io/k8s-debug/debug-example:latest 267 name: example 268 `, 269 `apiVersion: apps/v1 270 kind: StatefulSet 271 metadata: 272 creationTimestamp: null 273 name: my-statefulset 274 spec: 275 replicas: 1 276 selector: 277 matchLabels: 278 app: debug-app 279 serviceName: service 280 template: 281 metadata: 282 annotations: 283 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 284 creationTimestamp: null 285 labels: 286 app: debug-app 287 name: debug-pod 288 spec: 289 containers: 290 - env: 291 - name: KEY 292 value: value 293 image: gcr.io/k8s-debug/debug-example:latest 294 name: example 295 ports: 296 - containerPort: 9999 297 name: test 298 resources: {} 299 updateStrategy: {} 300 status: 301 availableReplicas: 0 302 replicas: 0`, 303 }, 304 { 305 "DaemonSet", false, 306 `apiVersion: apps/v1 307 kind: DaemonSet 308 metadata: 309 name: my-daemonset 310 spec: 311 selector: 312 matchLabels: 313 app: debug-app 314 template: 315 metadata: 316 labels: 317 app: debug-app 318 name: debug-pod 319 spec: 320 containers: 321 - image: gcr.io/k8s-debug/debug-example:latest 322 name: example 323 `, 324 `apiVersion: apps/v1 325 kind: DaemonSet 326 metadata: 327 creationTimestamp: null 328 name: my-daemonset 329 spec: 330 selector: 331 matchLabels: 332 app: debug-app 333 template: 334 metadata: 335 annotations: 336 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 337 creationTimestamp: null 338 labels: 339 app: debug-app 340 name: debug-pod 341 spec: 342 containers: 343 - env: 344 - name: KEY 345 value: value 346 image: gcr.io/k8s-debug/debug-example:latest 347 name: example 348 ports: 349 - containerPort: 9999 350 name: test 351 resources: {} 352 updateStrategy: {} 353 status: 354 currentNumberScheduled: 0 355 desiredNumberScheduled: 0 356 numberMisscheduled: 0 357 numberReady: 0`, 358 }, 359 { 360 "Job", false, 361 `apiVersion: batch/v1 362 kind: Job 363 metadata: 364 name: my-job 365 spec: 366 selector: 367 matchLabels: 368 app: debug-app 369 template: 370 metadata: 371 labels: 372 app: debug-app 373 name: debug-pod 374 spec: 375 containers: 376 - image: gcr.io/k8s-debug/debug-example:latest 377 name: example 378 `, 379 `apiVersion: batch/v1 380 kind: Job 381 metadata: 382 creationTimestamp: null 383 name: my-job 384 spec: 385 selector: 386 matchLabels: 387 app: debug-app 388 template: 389 metadata: 390 annotations: 391 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 392 creationTimestamp: null 393 labels: 394 app: debug-app 395 name: debug-pod 396 spec: 397 containers: 398 - env: 399 - name: KEY 400 value: value 401 image: gcr.io/k8s-debug/debug-example:latest 402 name: example 403 ports: 404 - containerPort: 9999 405 name: test 406 resources: {} 407 status: {}`, 408 }, 409 { 410 "ReplicationController", false, 411 `apiVersion: v1 412 kind: ReplicationController 413 metadata: 414 name: my-rc 415 spec: 416 replicas: 10 417 selector: 418 app: debug-app 419 template: 420 metadata: 421 name: debug-pod 422 labels: 423 app: debug-app 424 spec: 425 containers: 426 - image: gcr.io/k8s-debug/debug-example:latest 427 name: example 428 `, 429 `apiVersion: v1 430 kind: ReplicationController 431 metadata: 432 creationTimestamp: null 433 name: my-rc 434 spec: 435 replicas: 1 436 selector: 437 app: debug-app 438 template: 439 metadata: 440 annotations: 441 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 442 creationTimestamp: null 443 labels: 444 app: debug-app 445 name: debug-pod 446 spec: 447 containers: 448 - env: 449 - name: KEY 450 value: value 451 image: gcr.io/k8s-debug/debug-example:latest 452 name: example 453 ports: 454 - containerPort: 9999 455 name: test 456 resources: {} 457 status: 458 replicas: 0`, 459 }, 460 { 461 description: "skip unhandled yamls like crds", 462 shouldErr: false, 463 in: `--- 464 apiVersion: openfaas.com/v1alpha2 465 kind: Function 466 metadata: 467 name: myfunction 468 namespace: openfaas-fn 469 spec: 470 name: myfunction 471 image: myfunction`, 472 out: `--- 473 apiVersion: openfaas.com/v1alpha2 474 kind: Function 475 metadata: 476 name: myfunction 477 namespace: openfaas-fn 478 spec: 479 name: myfunction 480 image: myfunction`, 481 }, 482 { 483 "multiple objects", false, 484 `apiVersion: v1 485 kind: Pod 486 metadata: 487 name: pod 488 spec: 489 containers: 490 - image: gcr.io/k8s-debug/debug-example:latest 491 name: example 492 --- 493 apiVersion: apps/v1 494 kind: Deployment 495 metadata: 496 name: my-app 497 spec: 498 replicas: 10 499 selector: 500 matchLabels: 501 app: debug-app 502 template: 503 metadata: 504 labels: 505 app: debug-app 506 name: debug-pod 507 spec: 508 containers: 509 - image: gcr.io/k8s-debug/debug-example:latest 510 name: example 511 `, 512 `apiVersion: v1 513 kind: Pod 514 metadata: 515 annotations: 516 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 517 creationTimestamp: null 518 name: pod 519 spec: 520 containers: 521 - env: 522 - name: KEY 523 value: value 524 image: gcr.io/k8s-debug/debug-example:latest 525 name: example 526 ports: 527 - containerPort: 9999 528 name: test 529 resources: {} 530 status: {} 531 --- 532 apiVersion: apps/v1 533 kind: Deployment 534 metadata: 535 creationTimestamp: null 536 name: my-app 537 spec: 538 replicas: 1 539 selector: 540 matchLabels: 541 app: debug-app 542 strategy: {} 543 template: 544 metadata: 545 annotations: 546 debug.cloud.google.com/config: '{"example":{"runtime":"test"}}' 547 creationTimestamp: null 548 labels: 549 app: debug-app 550 name: debug-pod 551 spec: 552 containers: 553 - env: 554 - name: KEY 555 value: value 556 image: gcr.io/k8s-debug/debug-example:latest 557 name: example 558 ports: 559 - containerPort: 9999 560 name: test 561 resources: {} 562 status: {}`, 563 }, 564 } 565 for _, test := range tests { 566 testutil.Run(t, test.description, func(t *testutil.T) { 567 retriever := func(image string) (debug.ImageConfiguration, error) { 568 return debug.ImageConfiguration{}, nil 569 } 570 571 l, err := manifest.Load(bytes.NewReader([]byte(test.in))) 572 t.CheckError(false, err) 573 result, err := applyDebuggingTransforms(l, retriever, "HELPERS") 574 575 t.CheckErrorAndDeepEqual(test.shouldErr, err, test.out, result.String(), testutil.YamlObj(t.T)) 576 }) 577 } 578 } 579 580 func TestWorkingDir(t *testing.T) { 581 tfm := testTransformer{} 582 debug.RegisterContainerTransformer(tfm) 583 defer debug.UnregisterContainerTransformer(tfm) 584 585 pod := &v1.Pod{ 586 TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.Version, Kind: "Pod"}, 587 ObjectMeta: metav1.ObjectMeta{Name: "podname"}, 588 Spec: v1.PodSpec{Containers: []v1.Container{{Name: "name1", Image: "image1"}}}} 589 590 retriever := func(image string) (debug.ImageConfiguration, error) { 591 return debug.ImageConfiguration{WorkingDir: "/a/dir"}, nil 592 } 593 594 result := transformManifest(pod, retriever, "HELPERS") 595 testutil.CheckDeepEqual(t, true, result) 596 debugConfig := pod.ObjectMeta.Annotations["debug.cloud.google.com/config"] 597 testutil.CheckDeepEqual(t, true, strings.Contains(debugConfig, `"workingDir":"/a/dir"`)) 598 } 599 600 func TestArtifactImage(t *testing.T) { 601 tfm := testTransformer{} 602 debug.RegisterContainerTransformer(tfm) 603 defer debug.UnregisterContainerTransformer(tfm) 604 605 pod := &v1.Pod{ 606 TypeMeta: metav1.TypeMeta{APIVersion: v1.SchemeGroupVersion.Version, Kind: "Pod"}, 607 ObjectMeta: metav1.ObjectMeta{Name: "podname"}, 608 Spec: v1.PodSpec{Containers: []v1.Container{{Name: "name1", Image: "image1"}}}} 609 610 retriever := func(image string) (debug.ImageConfiguration, error) { 611 return debug.ImageConfiguration{Artifact: "gcr.io/random/image"}, nil 612 } 613 614 result := transformManifest(pod, retriever, "HELPERS") 615 testutil.CheckDeepEqual(t, true, result) 616 debugConfig := pod.ObjectMeta.Annotations["debug.cloud.google.com/config"] 617 testutil.CheckDeepEqual(t, true, strings.Contains(debugConfig, `"artifact":"gcr.io/random/image"`)) 618 }