1
16
17 package client
18
19 import (
20 "context"
21 "fmt"
22 "log"
23 "reflect"
24 rt "runtime"
25 "strings"
26 "sync"
27 "testing"
28 "time"
29
30 "github.com/google/go-cmp/cmp"
31 appsv1 "k8s.io/api/apps/v1"
32 v1 "k8s.io/api/core/v1"
33 eventsv1 "k8s.io/api/events/v1"
34 "k8s.io/apimachinery/pkg/api/equality"
35 apierrors "k8s.io/apimachinery/pkg/api/errors"
36 "k8s.io/apimachinery/pkg/api/resource"
37 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
38 "k8s.io/apimachinery/pkg/fields"
39 "k8s.io/apimachinery/pkg/labels"
40 "k8s.io/apimachinery/pkg/runtime"
41 "k8s.io/apimachinery/pkg/runtime/schema"
42 "k8s.io/apimachinery/pkg/types"
43 "k8s.io/apimachinery/pkg/util/wait"
44 "k8s.io/apimachinery/pkg/watch"
45 appsv1ac "k8s.io/client-go/applyconfigurations/apps/v1"
46 corev1ac "k8s.io/client-go/applyconfigurations/core/v1"
47 metav1ac "k8s.io/client-go/applyconfigurations/meta/v1"
48 clientset "k8s.io/client-go/kubernetes"
49 "k8s.io/utils/pointer"
50
51 "k8s.io/component-base/version"
52 kubeapiservertesting "k8s.io/kubernetes/cmd/kube-apiserver/app/testing"
53 "k8s.io/kubernetes/pkg/api/legacyscheme"
54 "k8s.io/kubernetes/test/integration/framework"
55 imageutils "k8s.io/kubernetes/test/utils/image"
56 )
57
58 func TestClient(t *testing.T) {
59 result := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
60 defer result.TearDownFn()
61
62 client := clientset.NewForConfigOrDie(result.ClientConfig)
63
64 info, err := client.Discovery().ServerVersion()
65 if err != nil {
66 t.Fatalf("unexpected error: %v", err)
67 }
68 if e, a := version.Get(), *info; !reflect.DeepEqual(e, a) {
69 t.Errorf("expected %#v, got %#v", e, a)
70 }
71
72 pods, err := client.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
73 if err != nil {
74 t.Fatalf("unexpected error: %v", err)
75 }
76 if len(pods.Items) != 0 {
77 t.Errorf("expected no pods, got %#v", pods)
78 }
79
80
81 pod := &v1.Pod{
82 ObjectMeta: metav1.ObjectMeta{
83 GenerateName: "test",
84 Namespace: "default",
85 },
86 Spec: v1.PodSpec{
87 Containers: []v1.Container{
88 {
89 Name: "test",
90 },
91 },
92 },
93 }
94
95 got, err := client.CoreV1().Pods("default").Create(context.TODO(), pod, metav1.CreateOptions{})
96 if err == nil {
97 t.Fatalf("unexpected non-error: %v", got)
98 }
99
100
101 pod.Spec.Containers[0].Image = "an-image"
102 got, err = client.CoreV1().Pods("default").Create(context.TODO(), pod, metav1.CreateOptions{})
103 if err != nil {
104 t.Fatalf("unexpected error: %v", err)
105 }
106 if got.Name == "" {
107 t.Errorf("unexpected empty pod Name %v", got)
108 }
109
110
111 pods, err = client.CoreV1().Pods("default").List(context.TODO(), metav1.ListOptions{})
112 if err != nil {
113 t.Fatalf("unexpected error: %v", err)
114 }
115 if len(pods.Items) != 1 {
116 t.Errorf("expected one pod, got %#v", pods)
117 }
118 actual := pods.Items[0]
119 if actual.Name != got.Name {
120 t.Errorf("expected pod %#v, got %#v", got, actual)
121 }
122 if actual.Spec.NodeName != "" {
123 t.Errorf("expected pod to be unscheduled, got %#v", actual)
124 }
125 }
126
127 func TestAtomicPut(t *testing.T) {
128 result := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
129 defer result.TearDownFn()
130
131 c := clientset.NewForConfigOrDie(result.ClientConfig)
132
133 rcBody := v1.ReplicationController{
134 TypeMeta: metav1.TypeMeta{
135 APIVersion: c.CoreV1().RESTClient().APIVersion().String(),
136 },
137 ObjectMeta: metav1.ObjectMeta{
138 Name: "atomicrc",
139 Namespace: "default",
140 Labels: map[string]string{
141 "name": "atomicrc",
142 },
143 },
144 Spec: v1.ReplicationControllerSpec{
145 Replicas: pointer.Int32(0),
146 Selector: map[string]string{
147 "foo": "bar",
148 },
149 Template: &v1.PodTemplateSpec{
150 ObjectMeta: metav1.ObjectMeta{
151 Labels: map[string]string{
152 "foo": "bar",
153 },
154 },
155 Spec: v1.PodSpec{
156 Containers: []v1.Container{
157 {Name: "name", Image: "image"},
158 },
159 },
160 },
161 },
162 }
163 rcs := c.CoreV1().ReplicationControllers("default")
164 rc, err := rcs.Create(context.TODO(), &rcBody, metav1.CreateOptions{})
165 if err != nil {
166 t.Fatalf("Failed creating atomicRC: %v", err)
167 }
168 testLabels := labels.Set{
169 "foo": "bar",
170 }
171 for i := 0; i < 5; i++ {
172
173 testLabels[string([]byte{byte('a' + i)})] = string([]byte{byte('z' - i)})
174 }
175 var wg sync.WaitGroup
176 wg.Add(len(testLabels))
177 for label, value := range testLabels {
178 go func(l, v string) {
179 defer wg.Done()
180 for {
181 tmpRC, err := rcs.Get(context.TODO(), rc.Name, metav1.GetOptions{})
182 if err != nil {
183 t.Errorf("Error getting atomicRC: %v", err)
184 continue
185 }
186 if tmpRC.Spec.Selector == nil {
187 tmpRC.Spec.Selector = map[string]string{l: v}
188 tmpRC.Spec.Template.Labels = map[string]string{l: v}
189 } else {
190 tmpRC.Spec.Selector[l] = v
191 tmpRC.Spec.Template.Labels[l] = v
192 }
193 _, err = rcs.Update(context.TODO(), tmpRC, metav1.UpdateOptions{})
194 if err != nil {
195 if apierrors.IsConflict(err) {
196
197 continue
198 }
199 t.Errorf("Unexpected error putting atomicRC: %v", err)
200 continue
201 }
202 return
203 }
204 }(label, value)
205 }
206 wg.Wait()
207 rc, err = rcs.Get(context.TODO(), rc.Name, metav1.GetOptions{})
208 if err != nil {
209 t.Fatalf("Failed getting atomicRC after writers are complete: %v", err)
210 }
211 if !reflect.DeepEqual(testLabels, labels.Set(rc.Spec.Selector)) {
212 t.Errorf("Selector PUTs were not atomic: wanted %v, got %v", testLabels, rc.Spec.Selector)
213 }
214 }
215
216 func TestPatch(t *testing.T) {
217 result := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
218 defer result.TearDownFn()
219
220 c := clientset.NewForConfigOrDie(result.ClientConfig)
221
222 name := "patchpod"
223 resource := "pods"
224 podBody := v1.Pod{
225 TypeMeta: metav1.TypeMeta{
226 APIVersion: c.CoreV1().RESTClient().APIVersion().String(),
227 },
228 ObjectMeta: metav1.ObjectMeta{
229 Name: name,
230 Namespace: "default",
231 Labels: map[string]string{},
232 },
233 Spec: v1.PodSpec{
234 Containers: []v1.Container{
235 {Name: "name", Image: "image"},
236 },
237 },
238 }
239 pods := c.CoreV1().Pods("default")
240 _, err := pods.Create(context.TODO(), &podBody, metav1.CreateOptions{})
241 if err != nil {
242 t.Fatalf("Failed creating patchpods: %v", err)
243 }
244
245 patchBodies := map[schema.GroupVersion]map[types.PatchType]struct {
246 AddLabelBody []byte
247 RemoveLabelBody []byte
248 RemoveAllLabelsBody []byte
249 }{
250 v1.SchemeGroupVersion: {
251 types.JSONPatchType: {
252 []byte(`[{"op":"add","path":"/metadata/labels","value":{"foo":"bar","baz":"qux"}}]`),
253 []byte(`[{"op":"remove","path":"/metadata/labels/foo"}]`),
254 []byte(`[{"op":"remove","path":"/metadata/labels"}]`),
255 },
256 types.MergePatchType: {
257 []byte(`{"metadata":{"labels":{"foo":"bar","baz":"qux"}}}`),
258 []byte(`{"metadata":{"labels":{"foo":null}}}`),
259 []byte(`{"metadata":{"labels":null}}`),
260 },
261 types.StrategicMergePatchType: {
262 []byte(`{"metadata":{"labels":{"foo":"bar","baz":"qux"}}}`),
263 []byte(`{"metadata":{"labels":{"foo":null}}}`),
264 []byte(`{"metadata":{"labels":{"$patch":"replace"}}}`),
265 },
266 },
267 }
268
269 pb := patchBodies[c.CoreV1().RESTClient().APIVersion()]
270
271 execPatch := func(pt types.PatchType, body []byte) error {
272 result := c.CoreV1().RESTClient().Patch(pt).
273 Resource(resource).
274 Namespace("default").
275 Name(name).
276 Body(body).
277 Do(context.TODO())
278 if result.Error() != nil {
279 return result.Error()
280 }
281
282
283 jsonObj, err := result.Raw()
284 if err != nil {
285 t.Log(err)
286 } else {
287 t.Logf("%v", string(jsonObj))
288 }
289
290 return nil
291 }
292
293 for k, v := range pb {
294
295 err := execPatch(k, v.AddLabelBody)
296 if err != nil {
297 t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err)
298 }
299 pod, err := pods.Get(context.TODO(), name, metav1.GetOptions{})
300 if err != nil {
301 t.Fatalf("Failed getting patchpod: %v", err)
302 }
303 if len(pod.Labels) != 2 || pod.Labels["foo"] != "bar" || pod.Labels["baz"] != "qux" {
304 t.Errorf("Failed updating patchpod with patch type %s: labels are: %v", k, pod.Labels)
305 }
306
307
308 err = execPatch(k, v.RemoveLabelBody)
309 if err != nil {
310 t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err)
311 }
312 pod, err = pods.Get(context.TODO(), name, metav1.GetOptions{})
313 if err != nil {
314 t.Fatalf("Failed getting patchpod: %v", err)
315 }
316 if len(pod.Labels) != 1 || pod.Labels["baz"] != "qux" {
317 t.Errorf("Failed updating patchpod with patch type %s: labels are: %v", k, pod.Labels)
318 }
319
320
321 err = execPatch(k, v.RemoveAllLabelsBody)
322 if err != nil {
323 t.Fatalf("Failed updating patchpod with patch type %s: %v", k, err)
324 }
325 pod, err = pods.Get(context.TODO(), name, metav1.GetOptions{})
326 if err != nil {
327 t.Fatalf("Failed getting patchpod: %v", err)
328 }
329 if pod.Labels != nil {
330 t.Errorf("Failed remove all labels from patchpod with patch type %s: %v", k, pod.Labels)
331 }
332 }
333 }
334
335 func TestPatchWithCreateOnUpdate(t *testing.T) {
336 result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
337 defer result.TearDownFn()
338
339 c := clientset.NewForConfigOrDie(result.ClientConfig)
340
341 endpointTemplate := &v1.Endpoints{
342 ObjectMeta: metav1.ObjectMeta{
343 Name: "patchendpoint",
344 Namespace: "default",
345 },
346 Subsets: []v1.EndpointSubset{
347 {
348 Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}},
349 Ports: []v1.EndpointPort{{Port: 80, Protocol: v1.ProtocolTCP}},
350 },
351 },
352 }
353
354 patchEndpoint := func(json []byte) (runtime.Object, error) {
355 return c.CoreV1().RESTClient().Patch(types.MergePatchType).Resource("endpoints").Namespace("default").Name("patchendpoint").Body(json).Do(context.TODO()).Get()
356 }
357
358
359 {
360 endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
361 if err != nil {
362 t.Fatalf("Failed creating endpoint JSON: %v", err)
363 }
364 if obj, err := patchEndpoint(endpointJSON); !apierrors.IsNotFound(err) {
365 t.Errorf("Expected notfound creating from patch, got error=%v and object: %#v", err, obj)
366 }
367 }
368
369
370 createdEndpoint, err := c.CoreV1().Endpoints("default").Update(context.TODO(), endpointTemplate, metav1.UpdateOptions{})
371 if err != nil {
372 t.Fatalf("Failed creating endpoint: %v", err)
373 }
374
375
376 {
377 endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), createdEndpoint)
378 if err != nil {
379 t.Fatalf("Failed creating endpoint JSON: %v", err)
380 }
381 if _, err := patchEndpoint(endpointJSON); err != nil {
382 t.Errorf("Failed patching endpoint: %v", err)
383 }
384 }
385
386
387 {
388 endpointTemplate.Name = ""
389 endpointTemplate.UID = ""
390 endpointTemplate.ResourceVersion = "1"
391 endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
392 if err != nil {
393 t.Fatalf("Failed creating endpoint JSON: %v", err)
394 }
395 if _, err := patchEndpoint(endpointJSON); !apierrors.IsConflict(err) {
396 t.Errorf("Expected error, got %#v", err)
397 }
398 }
399
400
401 {
402 endpointTemplate.Name = ""
403 endpointTemplate.UID = "abc"
404 endpointTemplate.ResourceVersion = ""
405 endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
406 if err != nil {
407 t.Fatalf("Failed creating endpoint JSON: %v", err)
408 }
409 if _, err := patchEndpoint(endpointJSON); !apierrors.IsInvalid(err) {
410 t.Errorf("Expected error, got %#v", err)
411 }
412 }
413
414
415 {
416 endpointTemplate.Name = "changedname"
417 endpointTemplate.UID = ""
418 endpointTemplate.ResourceVersion = ""
419 endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
420 if err != nil {
421 t.Fatalf("Failed creating endpoint JSON: %v", err)
422 }
423 if _, err := patchEndpoint(endpointJSON); !apierrors.IsBadRequest(err) {
424 t.Errorf("Expected error, got %#v", err)
425 }
426 }
427
428
429 {
430 endpointTemplate.Name = ""
431 endpointTemplate.UID = ""
432 endpointTemplate.ResourceVersion = ""
433 endpointJSON, err := runtime.Encode(legacyscheme.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate)
434 if err != nil {
435 t.Fatalf("Failed creating endpoint JSON: %v", err)
436 }
437 if _, err := patchEndpoint(endpointJSON); err != nil {
438 t.Errorf("Failed patching endpoint: %v", err)
439 }
440 }
441 }
442
443 func TestAPIVersions(t *testing.T) {
444 result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
445 defer result.TearDownFn()
446
447 c := clientset.NewForConfigOrDie(result.ClientConfig)
448
449 clientVersion := c.CoreV1().RESTClient().APIVersion().String()
450 g, err := c.Discovery().ServerGroups()
451 if err != nil {
452 t.Fatalf("Failed to get api versions: %v", err)
453 }
454 versions := metav1.ExtractGroupVersions(g)
455
456
457 for _, version := range versions {
458 if version == clientVersion {
459 return
460 }
461 }
462 t.Errorf("Server does not support APIVersion used by client. Server supported APIVersions: '%v', client APIVersion: '%v'", versions, clientVersion)
463 }
464
465 func TestEventValidation(t *testing.T) {
466 result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
467 defer result.TearDownFn()
468
469 client := clientset.NewForConfigOrDie(result.ClientConfig)
470
471 createNamespace := func(namespace string) string {
472 if namespace == "" {
473 namespace = metav1.NamespaceDefault
474 }
475 return namespace
476 }
477
478 mkCoreEvent := func(ver string, ns string) *v1.Event {
479 name := fmt.Sprintf("%v-%v-event", ver, ns)
480 namespace := createNamespace(ns)
481 return &v1.Event{
482 ObjectMeta: metav1.ObjectMeta{
483 Namespace: namespace,
484 Name: name,
485 },
486 InvolvedObject: v1.ObjectReference{
487 Namespace: ns,
488 Name: name,
489 },
490 Count: 2,
491 Type: "Normal",
492 ReportingController: "test-controller",
493 ReportingInstance: "test-1",
494 Reason: fmt.Sprintf("event %v test", name),
495 Action: "Testing",
496 }
497 }
498 mkV1Event := func(ver string, ns string) *eventsv1.Event {
499 name := fmt.Sprintf("%v-%v-event", ver, ns)
500 namespace := createNamespace(ns)
501 return &eventsv1.Event{
502 ObjectMeta: metav1.ObjectMeta{
503 Namespace: namespace,
504 Name: name,
505 },
506 Regarding: v1.ObjectReference{
507 Namespace: ns,
508 Name: name,
509 },
510 Series: &eventsv1.EventSeries{
511 Count: 2,
512 LastObservedTime: metav1.MicroTime{Time: time.Now()},
513 },
514 Type: "Normal",
515 EventTime: metav1.MicroTime{Time: time.Now()},
516 ReportingController: "test-controller",
517 ReportingInstance: "test-2",
518 Reason: fmt.Sprintf("event %v test", name),
519 Action: "Testing",
520 }
521 }
522
523 testcases := []struct {
524 name string
525 namespace string
526 hasError bool
527 }{
528 {
529 name: "Involved object is namespaced",
530 namespace: "kube-system",
531 hasError: false,
532 },
533 {
534 name: "Involved object is cluster-scoped",
535 namespace: "",
536 hasError: false,
537 },
538 }
539
540 for _, test := range testcases {
541
542 oldEventObj := mkCoreEvent("corev1", test.namespace)
543 corev1Event, err := client.CoreV1().Events(oldEventObj.Namespace).Create(context.TODO(), oldEventObj, metav1.CreateOptions{})
544 if err != nil && !test.hasError {
545 t.Errorf("%v, call Create failed, expect has error: %v, but got: %v", test.name, test.hasError, err)
546 }
547 newEventObj := mkV1Event("eventsv1", test.namespace)
548 eventsv1Event, err := client.EventsV1().Events(newEventObj.Namespace).Create(context.TODO(), newEventObj, metav1.CreateOptions{})
549 if err != nil && !test.hasError {
550 t.Errorf("%v, call Create failed, expect has error: %v, but got: %v", test.name, test.hasError, err)
551 }
552 if corev1Event.Namespace != eventsv1Event.Namespace {
553 t.Errorf("%v, events created by different api client have different namespaces that isn't expected", test.name)
554 }
555
556 corev1Event.Count++
557 corev1Event, err = client.CoreV1().Events(corev1Event.Namespace).Update(context.TODO(), corev1Event, metav1.UpdateOptions{})
558 if err != nil && !test.hasError {
559 t.Errorf("%v, call Update failed, expect has error: %v, but got: %v", test.name, test.hasError, err)
560 }
561 eventsv1Event.Series.Count++
562 eventsv1Event.Series.LastObservedTime = metav1.MicroTime{Time: time.Now()}
563 eventsv1Event, err = client.EventsV1().Events(eventsv1Event.Namespace).Update(context.TODO(), eventsv1Event, metav1.UpdateOptions{})
564 if err != nil && !test.hasError {
565 t.Errorf("%v, call Update failed, expect has error: %v, but got: %v", test.name, test.hasError, err)
566 }
567 if corev1Event.Namespace != eventsv1Event.Namespace {
568 t.Errorf("%v, events updated by different api client have different namespaces that isn't expected", test.name)
569 }
570 }
571 }
572
573 func TestEventCompatibility(t *testing.T) {
574 result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
575 defer result.TearDownFn()
576
577 client := clientset.NewForConfigOrDie(result.ClientConfig)
578
579 coreevents := []*v1.Event{
580 {
581 ObjectMeta: metav1.ObjectMeta{
582 Name: "pass-core-default-cluster-scoped",
583 Namespace: "default",
584 },
585 Type: "Normal",
586 Reason: "event test",
587 Action: "Testing",
588 ReportingController: "test-controller",
589 ReportingInstance: "test-controller-1",
590 InvolvedObject: v1.ObjectReference{Kind: "Node", Name: "foo", Namespace: ""},
591 },
592 {
593 ObjectMeta: metav1.ObjectMeta{
594 Name: "fail-core-kube-system-cluster-scoped",
595 Namespace: "kube-system",
596 },
597 Type: "Normal",
598 Reason: "event test",
599 Action: "Testing",
600 ReportingController: "test-controller",
601 ReportingInstance: "test-controller-1",
602 InvolvedObject: v1.ObjectReference{Kind: "Node", Name: "foo", Namespace: ""},
603 },
604 {
605 ObjectMeta: metav1.ObjectMeta{
606 Name: "fail-core-other-ns-cluster-scoped",
607 Namespace: "test-ns",
608 },
609 Type: "Normal",
610 Reason: "event test",
611 Action: "Testing",
612 ReportingController: "test-controller",
613 ReportingInstance: "test-controller-1",
614 InvolvedObject: v1.ObjectReference{Kind: "Node", Name: "foo", Namespace: ""},
615 },
616 }
617 for _, e := range coreevents {
618 t.Run(e.Name, func(t *testing.T) {
619 _, err := client.CoreV1().Events(e.Namespace).Create(context.TODO(), e, metav1.CreateOptions{})
620 if err == nil && !strings.HasPrefix(e.Name, "pass-") {
621 t.Fatalf("unexpected pass")
622 }
623 if err != nil && !strings.HasPrefix(e.Name, "fail-") {
624 t.Fatalf("unexpected error: %v", err)
625 }
626 })
627 }
628
629 v1events := []*eventsv1.Event{
630 {
631 ObjectMeta: metav1.ObjectMeta{
632 Name: "pass-events-default-cluster-scoped",
633 Namespace: "default",
634 },
635 EventTime: metav1.MicroTime{Time: time.Now()},
636 Type: "Normal",
637 Reason: "event test",
638 Action: "Testing",
639 ReportingController: "test-controller",
640 ReportingInstance: "test-controller-1",
641 Regarding: v1.ObjectReference{Kind: "Node", Name: "foo", Namespace: ""},
642 },
643 {
644 ObjectMeta: metav1.ObjectMeta{
645 Name: "pass-events-kube-system-cluster-scoped",
646 Namespace: "kube-system",
647 },
648 EventTime: metav1.MicroTime{Time: time.Now()},
649 Type: "Normal",
650 Reason: "event test",
651 Action: "Testing",
652 ReportingController: "test-controller",
653 ReportingInstance: "test-controller-1",
654 Regarding: v1.ObjectReference{Kind: "Node", Name: "foo", Namespace: ""},
655 },
656 {
657 ObjectMeta: metav1.ObjectMeta{
658 Name: "fail-events-other-ns-cluster-scoped",
659 Namespace: "test-ns",
660 },
661 EventTime: metav1.MicroTime{Time: time.Now()},
662 Type: "Normal",
663 Reason: "event test",
664 Action: "Testing",
665 ReportingController: "test-controller",
666 ReportingInstance: "test-controller-1",
667 Regarding: v1.ObjectReference{Kind: "Node", Name: "foo", Namespace: ""},
668 },
669 }
670 for _, e := range v1events {
671 t.Run(e.Name, func(t *testing.T) {
672 _, err := client.EventsV1().Events(e.Namespace).Create(context.TODO(), e, metav1.CreateOptions{})
673 if err == nil && !strings.HasPrefix(e.Name, "pass-") {
674 t.Fatalf("unexpected pass")
675 }
676 if err != nil && !strings.HasPrefix(e.Name, "fail-") {
677 t.Fatalf("unexpected error: %v", err)
678 }
679 })
680 }
681 }
682
683 func TestSingleWatch(t *testing.T) {
684 result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
685 defer result.TearDownFn()
686
687 client := clientset.NewForConfigOrDie(result.ClientConfig)
688
689 mkEvent := func(i int) *v1.Event {
690 name := fmt.Sprintf("event-%v", i)
691 return &v1.Event{
692 ObjectMeta: metav1.ObjectMeta{
693 Namespace: "default",
694 Name: name,
695 },
696 InvolvedObject: v1.ObjectReference{
697 Namespace: "default",
698 Name: name,
699 },
700 Reason: fmt.Sprintf("event %v", i),
701 }
702 }
703
704 rv1 := ""
705 for i := 0; i < 10; i++ {
706 event := mkEvent(i)
707 got, err := client.CoreV1().Events("default").Create(context.TODO(), event, metav1.CreateOptions{})
708 if err != nil {
709 t.Fatalf("Failed creating event %#q: %v", event, err)
710 }
711 if rv1 == "" {
712 rv1 = got.ResourceVersion
713 if rv1 == "" {
714 t.Fatal("did not get a resource version.")
715 }
716 }
717 t.Logf("Created event %#v", got.ObjectMeta)
718 }
719
720 w, err := client.CoreV1().RESTClient().Get().
721 Namespace("default").
722 Resource("events").
723 VersionedParams(&metav1.ListOptions{
724 ResourceVersion: rv1,
725 Watch: true,
726 FieldSelector: fields.OneTermEqualSelector("metadata.name", "event-9").String(),
727 }, metav1.ParameterCodec).
728 Watch(context.TODO())
729
730 if err != nil {
731 t.Fatalf("Failed watch: %v", err)
732 }
733 defer w.Stop()
734
735 select {
736 case <-time.After(wait.ForeverTestTimeout):
737 t.Fatalf("watch took longer than %s", wait.ForeverTestTimeout.String())
738 case got, ok := <-w.ResultChan():
739 if !ok {
740 t.Fatal("Watch channel closed unexpectedly.")
741 }
742
743
744
745
746 if e, a := watch.Added, got.Type; e != a {
747 t.Errorf("Wanted %v, got %v", e, a)
748 }
749 switch o := got.Object.(type) {
750 case *v1.Event:
751 if e, a := "event-9", o.Name; e != a {
752 t.Errorf("Wanted %v, got %v", e, a)
753 }
754 default:
755 t.Fatalf("Unexpected watch event containing object %#q", got)
756 }
757 }
758 }
759
760 func TestMultiWatch(t *testing.T) {
761
762
763 t.Skip()
764
765 const watcherCount = 50
766 rt.GOMAXPROCS(watcherCount)
767
768 result := kubeapiservertesting.StartTestServerOrDie(t, nil, nil, framework.SharedEtcd())
769 defer result.TearDownFn()
770
771 client := clientset.NewForConfigOrDie(result.ClientConfig)
772
773 dummyEvent := func(i int) *v1.Event {
774 name := fmt.Sprintf("unrelated-%v", i)
775 return &v1.Event{
776 ObjectMeta: metav1.ObjectMeta{
777 Name: fmt.Sprintf("%v.%x", name, time.Now().UnixNano()),
778 Namespace: "default",
779 },
780 InvolvedObject: v1.ObjectReference{
781 Name: name,
782 Namespace: "default",
783 },
784 Reason: fmt.Sprintf("unrelated change %v", i),
785 }
786 }
787
788 type timePair struct {
789 t time.Time
790 name string
791 }
792
793 receivedTimes := make(chan timePair, watcherCount*2)
794 watchesStarted := sync.WaitGroup{}
795
796
797 for i := 0; i < watcherCount; i++ {
798 watchesStarted.Add(1)
799 name := fmt.Sprintf("multi-watch-%v", i)
800 got, err := client.CoreV1().Pods("default").Create(context.TODO(), &v1.Pod{
801 ObjectMeta: metav1.ObjectMeta{
802 Name: name,
803 Labels: labels.Set{"watchlabel": name},
804 },
805 Spec: v1.PodSpec{
806 Containers: []v1.Container{{
807 Name: "pause",
808 Image: imageutils.GetPauseImageName(),
809 }},
810 },
811 }, metav1.CreateOptions{})
812
813 if err != nil {
814 t.Fatalf("Couldn't make %v: %v", name, err)
815 }
816 go func(name, rv string) {
817 options := metav1.ListOptions{
818 LabelSelector: labels.Set{"watchlabel": name}.AsSelector().String(),
819 ResourceVersion: rv,
820 }
821 w, err := client.CoreV1().Pods("default").Watch(context.TODO(), options)
822 if err != nil {
823 panic(fmt.Sprintf("watch error for %v: %v", name, err))
824 }
825 defer w.Stop()
826 watchesStarted.Done()
827 e, ok := <-w.ResultChan()
828 if !ok {
829 panic(fmt.Sprintf("%v ended early?", name))
830 }
831 if e.Type != watch.Modified {
832 panic(fmt.Sprintf("Got unexpected watch notification:\n%v: %+v %+v", name, e, e.Object))
833 }
834 receivedTimes <- timePair{time.Now(), name}
835 }(name, got.ObjectMeta.ResourceVersion)
836 }
837 log.Printf("%v: %v pods made and watchers started", time.Now(), watcherCount)
838
839
840
841 watchesStarted.Wait()
842
843 const (
844 useEventsAsUnrelatedType = false
845 usePodsAsUnrelatedType = true
846 )
847
848
849 if useEventsAsUnrelatedType {
850 const unrelatedCount = 3000
851 var wg sync.WaitGroup
852 defer wg.Wait()
853 changeToMake := make(chan int, unrelatedCount*2)
854 changeMade := make(chan int, unrelatedCount*2)
855 go func() {
856 for i := 0; i < unrelatedCount; i++ {
857 changeToMake <- i
858 }
859 close(changeToMake)
860 }()
861 for i := 0; i < 50; i++ {
862 wg.Add(1)
863 go func() {
864 defer wg.Done()
865 for {
866 i, ok := <-changeToMake
867 if !ok {
868 return
869 }
870 if _, err := client.CoreV1().Events("default").Create(context.TODO(), dummyEvent(i), metav1.CreateOptions{}); err != nil {
871 panic(fmt.Sprintf("couldn't make an event: %v", err))
872 }
873 changeMade <- i
874 }
875 }()
876 }
877
878 for i := 0; i < 2000; i++ {
879 <-changeMade
880 if (i+1)%50 == 0 {
881 log.Printf("%v: %v unrelated changes made", time.Now(), i+1)
882 }
883 }
884 }
885 if usePodsAsUnrelatedType {
886 const unrelatedCount = 3000
887 var wg sync.WaitGroup
888 defer wg.Wait()
889 changeToMake := make(chan int, unrelatedCount*2)
890 changeMade := make(chan int, unrelatedCount*2)
891 go func() {
892 for i := 0; i < unrelatedCount; i++ {
893 changeToMake <- i
894 }
895 close(changeToMake)
896 }()
897 for i := 0; i < 50; i++ {
898 wg.Add(1)
899 go func() {
900 defer wg.Done()
901 for {
902 i, ok := <-changeToMake
903 if !ok {
904 return
905 }
906 name := fmt.Sprintf("unrelated-%v", i)
907 _, err := client.CoreV1().Pods("default").Create(context.TODO(), &v1.Pod{
908 ObjectMeta: metav1.ObjectMeta{
909 Name: name,
910 },
911 Spec: v1.PodSpec{
912 Containers: []v1.Container{{
913 Name: "nothing",
914 Image: imageutils.GetPauseImageName(),
915 }},
916 },
917 }, metav1.CreateOptions{})
918
919 if err != nil {
920 panic(fmt.Sprintf("couldn't make unrelated pod: %v", err))
921 }
922 changeMade <- i
923 }
924 }()
925 }
926
927 for i := 0; i < 2000; i++ {
928 <-changeMade
929 if (i+1)%50 == 0 {
930 log.Printf("%v: %v unrelated changes made", time.Now(), i+1)
931 }
932 }
933 }
934
935
936
937 sentTimes := make(chan timePair, watcherCount*2)
938 for i := 0; i < watcherCount; i++ {
939 go func(i int) {
940 name := fmt.Sprintf("multi-watch-%v", i)
941 pod, err := client.CoreV1().Pods("default").Get(context.TODO(), name, metav1.GetOptions{})
942 if err != nil {
943 panic(fmt.Sprintf("Couldn't get %v: %v", name, err))
944 }
945 pod.Spec.Containers[0].Image = imageutils.GetPauseImageName()
946 sentTimes <- timePair{time.Now(), name}
947 if _, err := client.CoreV1().Pods("default").Update(context.TODO(), pod, metav1.UpdateOptions{}); err != nil {
948 panic(fmt.Sprintf("Couldn't make %v: %v", name, err))
949 }
950 }(i)
951 }
952
953 sent := map[string]time.Time{}
954 for i := 0; i < watcherCount; i++ {
955 tp := <-sentTimes
956 sent[tp.name] = tp.t
957 }
958 log.Printf("all changes made")
959 dur := map[string]time.Duration{}
960 for i := 0; i < watcherCount; i++ {
961 tp := <-receivedTimes
962 delta := tp.t.Sub(sent[tp.name])
963 dur[tp.name] = delta
964 log.Printf("%v: %v", tp.name, delta)
965 }
966 log.Printf("all watches ended")
967 t.Errorf("durations: %v", dur)
968 }
969
970 func TestApplyWithApplyConfiguration(t *testing.T) {
971 deployment := appsv1ac.Deployment("nginx-deployment-3", "default").
972 WithSpec(appsv1ac.DeploymentSpec().
973 WithSelector(metav1ac.LabelSelector().
974 WithMatchLabels(map[string]string{"app": "nginx"}),
975 ).
976 WithTemplate(corev1ac.PodTemplateSpec().
977 WithLabels(map[string]string{"app": "nginx"}).
978 WithSpec(corev1ac.PodSpec().
979 WithContainers(corev1ac.Container().
980 WithName("nginx").
981 WithImage("nginx:1.14.2").
982 WithStdin(true).
983 WithPorts(corev1ac.ContainerPort().
984 WithContainerPort(8080).
985 WithProtocol(v1.ProtocolTCP),
986 ).
987 WithResources(corev1ac.ResourceRequirements().
988 WithLimits(v1.ResourceList{
989 v1.ResourceCPU: resource.MustParse("4"),
990 v1.ResourceMemory: resource.MustParse("32Gi"),
991 }),
992 ),
993 ),
994 ),
995 ),
996 )
997 testServer := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
998 defer testServer.TearDownFn()
999
1000 c := clientset.NewForConfigOrDie(testServer.ClientConfig)
1001
1002
1003 obj, err := c.AppsV1().Deployments("default").Apply(context.TODO(), deployment, metav1.ApplyOptions{FieldManager: "test-mgr", Force: true})
1004 if err != nil {
1005 t.Fatalf("unexpected error when applying manifest for Deployment: %v", err)
1006 }
1007 if obj.Spec.Template.Spec.Containers[0].Image != "nginx:1.14.2" {
1008 t.Errorf("expected image %s but got %s", "nginx:1.14.2", obj.Spec.Template.Spec.Containers[0].Image)
1009 }
1010 cpu := obj.Spec.Template.Spec.Containers[0].Resources.Limits[v1.ResourceCPU]
1011 if cpu.Value() != int64(4) {
1012 t.Errorf("expected resourceCPU limit %d but got %d", 4, cpu.Value())
1013 }
1014
1015
1016 statusApply := appsv1ac.Deployment("nginx-deployment-3", "default").
1017 WithStatus(appsv1ac.DeploymentStatus().
1018 WithConditions(
1019 appsv1ac.DeploymentCondition().
1020 WithType(appsv1.DeploymentReplicaFailure).
1021 WithStatus(v1.ConditionUnknown).
1022 WithLastTransitionTime(metav1.Now()).
1023 WithLastUpdateTime(metav1.Now()).
1024 WithMessage("apply status test").
1025 WithReason("TestApplyWithApplyConfiguration"),
1026 ),
1027 )
1028 obj, err = c.AppsV1().Deployments("default").ApplyStatus(context.TODO(), statusApply, metav1.ApplyOptions{FieldManager: "test-mgr", Force: true})
1029 if err != nil {
1030 t.Fatalf("unexpected error when applying manifest for Deployment: %v", err)
1031 }
1032 var found bool
1033 for _, c := range obj.Status.Conditions {
1034 if c.Type == appsv1.DeploymentReplicaFailure && c.Status == v1.ConditionUnknown &&
1035 c.Message == "apply status test" && c.Reason == "TestApplyWithApplyConfiguration" {
1036 found = true
1037 break
1038 }
1039 }
1040 if !found {
1041 t.Error("expected status to contain DeploymentReplicaFailure condition set by apply")
1042 }
1043 }
1044
1045 func TestExtractModifyApply(t *testing.T) {
1046 testCases := []struct {
1047 name string
1048
1049
1050 modifyFunc func(apply *appsv1ac.DeploymentApplyConfiguration)
1051 modifyStatusFunc func(apply *appsv1ac.DeploymentApplyConfiguration)
1052
1053
1054 verifyAppliedFunc func(applied *appsv1ac.DeploymentApplyConfiguration)
1055 verifyStatusAppliedFunc func(applied *appsv1ac.DeploymentApplyConfiguration)
1056 }{
1057 {
1058
1059 name: "modify-scalar",
1060 modifyFunc: func(apply *appsv1ac.DeploymentApplyConfiguration) {
1061 apply.Spec.WithReplicas(2)
1062 },
1063 verifyAppliedFunc: func(applied *appsv1ac.DeploymentApplyConfiguration) {
1064 if *applied.Spec.Replicas != 2 {
1065 t.Errorf("Expected 2 replicas but got: %d", *applied.Spec.Replicas)
1066 }
1067 },
1068 },
1069 {
1070
1071 name: "modify-struct",
1072 modifyFunc: func(apply *appsv1ac.DeploymentApplyConfiguration) {
1073 apply.Spec.Template.WithSpec(corev1ac.PodSpec().
1074 WithContainers(
1075 corev1ac.Container().
1076 WithName("modify-struct").
1077 WithImage("nginx:1.14.3"),
1078 ),
1079 )
1080 },
1081 verifyAppliedFunc: func(applied *appsv1ac.DeploymentApplyConfiguration) {
1082 containers := applied.Spec.Template.Spec.Containers
1083 if len(containers) != 1 {
1084 t.Errorf("Expected 1 container but got %d", len(containers))
1085 }
1086 if *containers[0].Name != "modify-struct" {
1087 t.Errorf("Expected container name modify-struct but got: %s", *containers[0].Name)
1088 }
1089 },
1090 },
1091 {
1092
1093 name: "modify-map",
1094 modifyFunc: func(apply *appsv1ac.DeploymentApplyConfiguration) {
1095 apply.WithLabels(map[string]string{"label2": "value2"})
1096 },
1097 verifyAppliedFunc: func(applied *appsv1ac.DeploymentApplyConfiguration) {
1098 labels := applied.Labels
1099 if len(labels) != 2 {
1100 t.Errorf("Expected 2 label but got %d", len(labels))
1101 }
1102 if labels["label2"] != "value2" {
1103 t.Errorf("Expected container name value2 but got: %s", labels["label2"])
1104 }
1105 },
1106 },
1107 {
1108
1109 name: "modify-slice",
1110 modifyFunc: func(apply *appsv1ac.DeploymentApplyConfiguration) {
1111 apply.Spec.Template.Spec.WithContainers(corev1ac.Container().
1112 WithName("modify-slice").
1113 WithImage("nginx:1.14.2"),
1114 )
1115 },
1116 verifyAppliedFunc: func(applied *appsv1ac.DeploymentApplyConfiguration) {
1117 containers := applied.Spec.Template.Spec.Containers
1118 if len(containers) != 2 {
1119 t.Errorf("Expected 2 containers but got %d", len(containers))
1120 }
1121 if *containers[0].Name != "initial-container" {
1122 t.Errorf("Expected container name initial-container but got: %s", *containers[0].Name)
1123 }
1124 if *containers[1].Name != "modify-slice" {
1125 t.Errorf("Expected container name modify-slice but got: %s", *containers[1].Name)
1126 }
1127 },
1128 },
1129 {
1130
1131 name: "modify-status-conditions",
1132 modifyStatusFunc: func(apply *appsv1ac.DeploymentApplyConfiguration) {
1133 apply.WithStatus(appsv1ac.DeploymentStatus().
1134 WithConditions(appsv1ac.DeploymentCondition().
1135 WithType(appsv1.DeploymentProgressing).
1136 WithStatus(v1.ConditionUnknown).
1137 WithLastTransitionTime(metav1.Now()).
1138 WithLastUpdateTime(metav1.Now()).
1139 WithMessage("progressing").
1140 WithReason("TestExtractModifyApply_Status"),
1141 ),
1142 )
1143 },
1144 verifyStatusAppliedFunc: func(applied *appsv1ac.DeploymentApplyConfiguration) {
1145 conditions := applied.Status.Conditions
1146 if len(conditions) != 1 {
1147 t.Errorf("Expected 1 conditions but got %d", len(conditions))
1148 }
1149 if *conditions[0].Type != appsv1.DeploymentProgressing {
1150 t.Errorf("Expected condition name DeploymentProgressing but got: %s", *conditions[0].Type)
1151 }
1152 },
1153 },
1154 }
1155
1156 testServer := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
1157 defer testServer.TearDownFn()
1158 c := clientset.NewForConfigOrDie(testServer.ClientConfig)
1159 deploymentClient := c.AppsV1().Deployments("default")
1160 fieldMgr := "test-mgr"
1161
1162 for _, tc := range testCases {
1163 t.Run(tc.name, func(t *testing.T) {
1164
1165 deployApply := appsv1ac.Deployment(tc.name, "default").
1166 WithLabels(map[string]string{"label1": "value1"}).
1167 WithSpec(appsv1ac.DeploymentSpec().
1168 WithSelector(metav1ac.LabelSelector().
1169 WithMatchLabels(map[string]string{"app": tc.name}),
1170 ).
1171 WithTemplate(corev1ac.PodTemplateSpec().
1172 WithLabels(map[string]string{"app": tc.name}).
1173 WithSpec(corev1ac.PodSpec().
1174 WithContainers(
1175 corev1ac.Container().
1176 WithName("initial-container").
1177 WithImage("nginx:1.14.2"),
1178 ),
1179 ),
1180 ),
1181 )
1182 actual, err := deploymentClient.Apply(context.TODO(), deployApply, metav1.ApplyOptions{FieldManager: fieldMgr})
1183 if err != nil {
1184 t.Fatalf("Failed to apply: %v", err)
1185 }
1186 if tc.modifyFunc != nil {
1187 extractedDeployment, err := appsv1ac.ExtractDeployment(actual, fieldMgr)
1188 if err != nil {
1189 t.Fatalf("Failed to extract: %v", err)
1190 }
1191 tc.modifyFunc(extractedDeployment)
1192 result, err := deploymentClient.Apply(context.TODO(), extractedDeployment, metav1.ApplyOptions{FieldManager: fieldMgr})
1193 if err != nil {
1194 t.Fatalf("Failed to apply extracted apply configuration: %v", err)
1195 }
1196 extractedResult, err := appsv1ac.ExtractDeployment(result, fieldMgr)
1197 if err != nil {
1198 t.Fatalf("Failed to extract: %v", err)
1199 }
1200 if tc.verifyAppliedFunc != nil {
1201 tc.verifyAppliedFunc(extractedResult)
1202 }
1203 }
1204
1205 if tc.modifyStatusFunc != nil {
1206 extractedDeployment, err := appsv1ac.ExtractDeploymentStatus(actual, fieldMgr)
1207 if err != nil {
1208 t.Fatalf("Failed to extract: %v", err)
1209 }
1210 tc.modifyStatusFunc(extractedDeployment)
1211 result, err := deploymentClient.ApplyStatus(context.TODO(), extractedDeployment, metav1.ApplyOptions{FieldManager: fieldMgr})
1212 if err != nil {
1213 t.Fatalf("Failed to apply extracted apply configuration to status: %v", err)
1214 }
1215 extractedResult, err := appsv1ac.ExtractDeploymentStatus(result, fieldMgr)
1216 if err != nil {
1217 t.Fatalf("Failed to extract: %v", err)
1218 }
1219 if tc.verifyStatusAppliedFunc != nil {
1220 tc.verifyStatusAppliedFunc(extractedResult)
1221 }
1222 }
1223 })
1224 }
1225 }
1226
1227 func TestExtractModifyApply_ForceOwnership(t *testing.T) {
1228 testServer := kubeapiservertesting.StartTestServerOrDie(t, nil, []string{"--disable-admission-plugins", "ServiceAccount"}, framework.SharedEtcd())
1229 defer testServer.TearDownFn()
1230 c := clientset.NewForConfigOrDie(testServer.ClientConfig)
1231 deploymentClient := c.AppsV1().Deployments("default")
1232
1233
1234 createApply := appsv1ac.Deployment("nginx-apply", "default").
1235 WithSpec(appsv1ac.DeploymentSpec().
1236 WithSelector(metav1ac.LabelSelector().
1237 WithMatchLabels(map[string]string{"app": "nginx"}),
1238 ).
1239 WithTemplate(corev1ac.PodTemplateSpec().
1240 WithLabels(map[string]string{"app": "nginx"}).
1241 WithSpec(corev1ac.PodSpec().
1242 WithContainers(
1243 corev1ac.Container().
1244 WithName("nginx").
1245 WithImage("nginx:1.14.2").
1246 WithWorkingDir("/tmp/v1"),
1247 ),
1248 ),
1249 ),
1250 )
1251
1252 _, err := deploymentClient.Apply(context.TODO(), createApply, metav1.ApplyOptions{FieldManager: "create-mgr", Force: true})
1253 if err != nil {
1254 t.Fatalf("Error creating createApply: %v", err)
1255 }
1256
1257
1258 sidecarApply := appsv1ac.Deployment("nginx-apply", "default").
1259 WithSpec(appsv1ac.DeploymentSpec().
1260 WithTemplate(corev1ac.PodTemplateSpec().
1261 WithSpec(corev1ac.PodSpec().
1262 WithContainers(
1263 corev1ac.Container().
1264 WithName("sidecar").
1265 WithImage("nginx:1.14.2"),
1266 ),
1267 ),
1268 ),
1269 )
1270
1271 applied, err := deploymentClient.Apply(context.TODO(), sidecarApply, metav1.ApplyOptions{FieldManager: "sidecar-mgr", Force: true})
1272 if err != nil {
1273 t.Fatalf("Error applying createApply: %v", err)
1274 }
1275 sidecarExtracted, err := appsv1ac.ExtractDeployment(applied, "sidecar-mgr")
1276 if err != nil {
1277 t.Fatalf("Error extracting createApply apply configuration: %v", err)
1278 }
1279 if !equality.Semantic.DeepEqual(sidecarApply, sidecarExtracted) {
1280 t.Errorf("Expected sidecarExtracted apply configuration to match original, but got:\n%s\n", cmp.Diff(sidecarApply, sidecarExtracted))
1281 }
1282
1283
1284
1285 sidecarExtracted.Spec.Template.Spec.Containers[0].WithImage("nginx:1.14.3")
1286 sidecarExtracted.Spec.Template.Spec.WithContainers(corev1ac.Container().
1287 WithName("nginx").
1288 WithWorkingDir("/tmp/v2"),
1289 )
1290 reapplied, err := deploymentClient.Apply(context.TODO(), sidecarExtracted, metav1.ApplyOptions{FieldManager: "sidecar-mgr", Force: true})
1291 if err != nil {
1292 t.Fatalf("Unexpected error when applying manifest for Deployment: %v", err)
1293 }
1294
1295
1296 reappliedExtracted, err := appsv1ac.ExtractDeployment(reapplied, "sidecar-mgr")
1297 if err != nil {
1298 t.Fatalf("Error extracting sidecarExtracted apply configuration: %v", err)
1299 }
1300
1301 expectedReappliedExtracted := appsv1ac.Deployment("nginx-apply", "default").
1302 WithSpec(appsv1ac.DeploymentSpec().
1303 WithTemplate(corev1ac.PodTemplateSpec().
1304 WithSpec(corev1ac.PodSpec().
1305 WithContainers(
1306 corev1ac.Container().
1307 WithName("sidecar").
1308 WithImage("nginx:1.14.3"),
1309 corev1ac.Container().
1310 WithName("nginx").
1311 WithWorkingDir("/tmp/v2"),
1312 ),
1313 ),
1314 ),
1315 )
1316 if !equality.Semantic.DeepEqual(expectedReappliedExtracted, reappliedExtracted) {
1317 t.Errorf("Reapplied apply configuration did not match expected, got:\n%s\n", cmp.Diff(expectedReappliedExtracted, reappliedExtracted))
1318 }
1319
1320 createMgrExtracted, err := appsv1ac.ExtractDeployment(reapplied, "create-mgr")
1321 if err != nil {
1322 t.Fatalf("Error extracting createApply apply configuration: %v", err)
1323 }
1324
1325 expectedCreateExtracted := appsv1ac.Deployment("nginx-apply", "default").
1326 WithSpec(appsv1ac.DeploymentSpec().
1327 WithSelector(metav1ac.LabelSelector().
1328 WithMatchLabels(map[string]string{"app": "nginx"}),
1329 ).
1330 WithTemplate(corev1ac.PodTemplateSpec().
1331 WithLabels(map[string]string{"app": "nginx"}).
1332 WithSpec(corev1ac.PodSpec().
1333 WithContainers(
1334 corev1ac.Container().
1335 WithName("nginx").
1336 WithImage("nginx:1.14.2"),
1337 ),
1338 ),
1339 ),
1340 )
1341 if !equality.Semantic.DeepEqual(expectedCreateExtracted, createMgrExtracted) {
1342 t.Errorf("createMgrExtracted apply configuration did not match expected, got:\n%s\n", cmp.Diff(expectedCreateExtracted, createMgrExtracted))
1343 }
1344 }
1345
View as plain text