func TestGracefulStoreHandleFinalizers(t *testing.T) { initialGeneration := int64(1) podWithFinalizer := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, Generation: initialGeneration}, Spec: api.PodSpec{NodeName: "machine"}, } testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) registry.EnableGarbageCollection = true defaultDeleteStrategy := testRESTStrategy{api.Scheme, names.SimpleNameGenerator, true, false, true} registry.DeleteStrategy = testGracefulStrategy{defaultDeleteStrategy} defer destroyFunc() // create pod _, err := registry.Create(testContext, podWithFinalizer) if err != nil { t.Errorf("Unexpected error: %v", err) } // delete the pod with grace period=0, the pod should still exist because it has a finalizer _, err = registry.Delete(testContext, podWithFinalizer.Name, api.NewDeleteOptions(0)) if err != nil { t.Fatalf("Unexpected error: %v", err) } _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } updatedPodWithFinalizer := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Finalizers: []string{"foo.com/x"}, ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, Spec: api.PodSpec{NodeName: "machine"}, } _, _, err = registry.Update(testContext, updatedPodWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(updatedPodWithFinalizer, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } // the object should still exist, because it still has a finalizer _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) if err != nil { t.Fatalf("Unexpected error: %v", err) } podWithNoFinalizer := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: podWithFinalizer.ObjectMeta.ResourceVersion}, Spec: api.PodSpec{NodeName: "anothermachine"}, } _, _, err = registry.Update(testContext, podWithFinalizer.ObjectMeta.Name, rest.DefaultUpdatedObjectInfo(podWithNoFinalizer, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } // the pod should be removed, because its finalizer is removed _, err = registry.Get(testContext, podWithFinalizer.Name, &metav1.GetOptions{}) if !errors.IsNotFound(err) { t.Fatalf("Unexpected error: %v", err) } }
func TestServiceRegistryIPUpdate(t *testing.T) { storage, _ := NewTestREST(t, nil) svc := &api.Service{ ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz"}, SessionAffinity: api.ServiceAffinityNone, Type: api.ServiceTypeClusterIP, Ports: []api.ServicePort{{ Port: 6502, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(6502), }}, }, } ctx := genericapirequest.NewDefaultContext() created_svc, _ := storage.Create(ctx, svc) created_service := created_svc.(*api.Service) if created_service.Spec.Ports[0].Port != 6502 { t.Errorf("Expected port 6502, but got %v", created_service.Spec.Ports[0].Port) } if !makeIPNet(t).Contains(net.ParseIP(created_service.Spec.ClusterIP)) { t.Errorf("Unexpected ClusterIP: %s", created_service.Spec.ClusterIP) } update := deepCloneService(created_service) update.Spec.Ports[0].Port = 6503 updated_svc, _, _ := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update, api.Scheme)) updated_service := updated_svc.(*api.Service) if updated_service.Spec.Ports[0].Port != 6503 { t.Errorf("Expected port 6503, but got %v", updated_service.Spec.Ports[0].Port) } testIPs := []string{"1.2.3.93", "1.2.3.94", "1.2.3.95", "1.2.3.96"} testIP := "" for _, ip := range testIPs { if !storage.serviceIPs.(*ipallocator.Range).Has(net.ParseIP(ip)) { testIP = ip break } } update = deepCloneService(created_service) update.Spec.Ports[0].Port = 6503 update.Spec.ClusterIP = testIP // Error: Cluster IP is immutable _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update, api.Scheme)) if err == nil || !errors.IsInvalid(err) { t.Errorf("Unexpected error type: %v", err) } }
func TestStoreUpdate(t *testing.T) { podA := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: api.PodSpec{NodeName: "machine"}, } podB := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: api.PodSpec{NodeName: "machine2"}, } podAWithResourceVersion := &api.Pod{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test", ResourceVersion: "7"}, Spec: api.PodSpec{NodeName: "machine"}, } testContext := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") destroyFunc, registry := NewTestGenericStoreRegistry(t) defer destroyFunc() // Test1 try to update a non-existing node _, _, err := registry.Update(testContext, podA.Name, rest.DefaultUpdatedObjectInfo(podA, api.Scheme)) if !errors.IsNotFound(err) { t.Errorf("Unexpected error: %v", err) } // Test2 createIfNotFound and verify registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = true if !updateAndVerify(t, testContext, registry, podA) { t.Errorf("Unexpected error updating podA") } registry.UpdateStrategy.(*testRESTStrategy).allowCreateOnUpdate = false // Test3 outofDate _, _, err = registry.Update(testContext, podAWithResourceVersion.Name, rest.DefaultUpdatedObjectInfo(podAWithResourceVersion, api.Scheme)) if !errors.IsConflict(err) { t.Errorf("Unexpected error updating podAWithResourceVersion: %v", err) } // Test4 normal update and verify if !updateAndVerify(t, testContext, registry, podB) { t.Errorf("Unexpected error updating podB") } // Test5 unconditional update // NOTE: The logic for unconditional updates doesn't make sense to me, and imho should be removed. // doUnconditionalUpdate := resourceVersion == 0 && e.UpdateStrategy.AllowUnconditionalUpdate() // ^^ That condition can *never be true due to the creation of root objects. // // registry.UpdateStrategy.(*testRESTStrategy).allowUnconditionalUpdate = true // updateAndVerify(t, testContext, registry, podAWithResourceVersion) }
func TestGenerationNumber(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) defer storage.ReplicaSet.Store.DestroyFunc() modifiedSno := *validNewReplicaSet() modifiedSno.Generation = 100 modifiedSno.Status.ObservedGeneration = 10 ctx := genericapirequest.NewDefaultContext() rs, err := createReplicaSet(storage.ReplicaSet, modifiedSno, t) etcdRS, err := storage.ReplicaSet.Get(ctx, rs.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } storedRS, _ := etcdRS.(*extensions.ReplicaSet) // Generation initialization if storedRS.Generation != 1 && storedRS.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation number %v, status generation %v", storedRS.Generation, storedRS.Status.ObservedGeneration) } // Updates to spec should increment the generation number storedRS.Spec.Replicas += 1 storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS, api.Scheme)) if err != nil { t.Errorf("unexpected error: %v", err) } etcdRS, err = storage.ReplicaSet.Get(ctx, rs.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } storedRS, _ = etcdRS.(*extensions.ReplicaSet) if storedRS.Generation != 2 || storedRS.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation, spec: %v, status: %v", storedRS.Generation, storedRS.Status.ObservedGeneration) } // Updates to status should not increment either spec or status generation numbers storedRS.Status.Replicas += 1 storage.ReplicaSet.Update(ctx, storedRS.Name, rest.DefaultUpdatedObjectInfo(storedRS, api.Scheme)) if err != nil { t.Errorf("unexpected error: %v", err) } etcdRS, err = storage.ReplicaSet.Get(ctx, rs.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } storedRS, _ = etcdRS.(*extensions.ReplicaSet) if storedRS.Generation != 2 || storedRS.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation number, spec: %v, status: %v", storedRS.Generation, storedRS.Status.ObservedGeneration) } }
func TestGenerationNumber(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) defer storage.Controller.Store.DestroyFunc() modifiedSno := *validNewController() modifiedSno.Generation = 100 modifiedSno.Status.ObservedGeneration = 10 ctx := genericapirequest.NewDefaultContext() rc, err := createController(storage.Controller, modifiedSno, t) ctrl, err := storage.Controller.Get(ctx, rc.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } controller, _ := ctrl.(*api.ReplicationController) // Generation initialization if controller.Generation != 1 && controller.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation number %v, status generation %v", controller.Generation, controller.Status.ObservedGeneration) } // Updates to spec should increment the generation number controller.Spec.Replicas += 1 storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme)) if err != nil { t.Errorf("unexpected error: %v", err) } ctrl, err = storage.Controller.Get(ctx, rc.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } controller, _ = ctrl.(*api.ReplicationController) if controller.Generation != 2 || controller.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation, spec: %v, status: %v", controller.Generation, controller.Status.ObservedGeneration) } // Updates to status should not increment either spec or status generation numbers controller.Status.Replicas += 1 storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme)) if err != nil { t.Errorf("unexpected error: %v", err) } ctrl, err = storage.Controller.Get(ctx, rc.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } controller, _ = ctrl.(*api.ReplicationController) if controller.Generation != 2 || controller.Status.ObservedGeneration != 0 { t.Fatalf("Unexpected generation number, spec: %v, status: %v", controller.Generation, controller.Status.ObservedGeneration) } }
func TestUpdate(t *testing.T) { storage, _, si, destroyFunc := newStorage(t) defer destroyFunc() ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), "test") key := "/controllers/test/foo" if err := si.Create(ctx, key, &validController, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } replicas := int32(12) update := extensions.Scale{ ObjectMeta: metav1.ObjectMeta{Name: "foo", Namespace: "test"}, Spec: extensions.ScaleSpec{ Replicas: replicas, }, } if _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil { t.Fatalf("unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } updated := obj.(*extensions.Scale) if updated.Spec.Replicas != replicas { t.Errorf("wrong replicas count expected: %d got: %d", replicas, updated.Spec.Replicas) } }
func (t *Tester) testUpdateIgnoreClusterName(obj runtime.Object, createFn CreateFunc, getFn GetFunc) { ctx := t.TestContext() foo := copyOrDie(obj) name := t.namer(9) t.setObjectMeta(foo, name) if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } storedFoo, err := getFn(ctx, foo) if err != nil { t.Errorf("unexpected error: %v", err) } older := copyOrDie(storedFoo) olderMeta := t.getObjectMetaOrFail(older) olderMeta.ClusterName = "clustername-to-ignore" _, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.Name, rest.DefaultUpdatedObjectInfo(older, api.Scheme)) if err != nil { t.Errorf("Unexpected error: %v", err) } updatedFoo, err := getFn(ctx, older) if err != nil { t.Errorf("unexpected error: %v", err) } if clusterName := t.getObjectMetaOrFail(updatedFoo).ClusterName; len(clusterName) != 0 { t.Errorf("Unexpected clusterName update: expected empty, got %v", clusterName) } }
func (t *Tester) testUpdateRejectsMismatchedNamespace(obj runtime.Object, createFn CreateFunc, getFn GetFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(1)) if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } storedFoo, err := getFn(ctx, foo) if err != nil { t.Errorf("unexpected error: %v", err) } objectMeta := t.getObjectMetaOrFail(storedFoo) objectMeta.Name = t.namer(1) objectMeta.Namespace = "not-default" obj, updated, err := t.storage.(rest.Updater).Update(t.TestContext(), "foo1", rest.DefaultUpdatedObjectInfo(storedFoo, api.Scheme)) if obj != nil || updated { t.Errorf("expected nil object and not updated") } if err == nil { t.Errorf("expected an error, but didn't get one") } else if !strings.Contains(err.Error(), "does not match the namespace sent on the request") { t.Errorf("expected 'does not match the namespace sent on the request' error, got '%v'", err.Error()) } }
func (t *Tester) testUpdateIgnoreGenerationUpdates(obj runtime.Object, createFn CreateFunc, getFn GetFunc) { ctx := t.TestContext() foo := copyOrDie(obj) name := t.namer(8) t.setObjectMeta(foo, name) if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } storedFoo, err := getFn(ctx, foo) if err != nil { t.Errorf("unexpected error: %v", err) } older := copyOrDie(storedFoo) olderMeta := t.getObjectMetaOrFail(older) olderMeta.Generation = 2 _, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.Name, rest.DefaultUpdatedObjectInfo(older, api.Scheme)) if err != nil { t.Errorf("Unexpected error: %v", err) } updatedFoo, err := getFn(ctx, older) if err != nil { t.Errorf("unexpected error: %v", err) } if exp, got := int64(1), t.getObjectMetaOrFail(updatedFoo).Generation; exp != got { t.Errorf("Unexpected generation update: expected %d, got %d", exp, got) } }
func (t *Tester) testUpdateFailsOnVersionTooOld(obj runtime.Object, createFn CreateFunc, getFn GetFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(3)) if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } storedFoo, err := getFn(ctx, foo) if err != nil { t.Errorf("unexpected error: %v", err) } older := copyOrDie(storedFoo) olderMeta := t.getObjectMetaOrFail(older) olderMeta.ResourceVersion = "1" _, _, err = t.storage.(rest.Updater).Update(t.TestContext(), olderMeta.Name, rest.DefaultUpdatedObjectInfo(older, api.Scheme)) if err == nil { t.Errorf("Expected an error, but we didn't get one") } else if !errors.IsConflict(err) { t.Errorf("Expected Conflict error, got '%v'", err) } }
func (t *Tester) testUpdateEquals(obj runtime.Object, createFn CreateFunc, getFn GetFunc, updateFn UpdateFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(2)) if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } toUpdate, err := getFn(ctx, foo) if err != nil { t.Errorf("unexpected error: %v", err) } toUpdate = updateFn(toUpdate) toUpdateMeta := t.getObjectMetaOrFail(toUpdate) updated, created, err := t.storage.(rest.Updater).Update(ctx, toUpdateMeta.Name, rest.DefaultUpdatedObjectInfo(toUpdate, api.Scheme)) if err != nil { t.Errorf("unexpected error: %v", err) } if created { t.Errorf("unexpected creation") } got, err := getFn(ctx, foo) if err != nil { t.Errorf("unexpected error: %v", err) } // Set resource version which might be unset in created object. updatedMeta := t.getObjectMetaOrFail(updated) gotMeta := t.getObjectMetaOrFail(got) updatedMeta.ResourceVersion = gotMeta.ResourceVersion if e, a := updated, got; !api.Semantic.DeepEqual(e, a) { t.Errorf("unexpected obj: %#v, expected %#v", e, a) } }
func TestUpdateStatus(t *testing.T) { storage, statusStorage, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewContext() key, _ := storage.KeyFunc(ctx, "foo") pvStart := validNewPersistentVolume("foo") err := storage.Storage.Create(ctx, key, pvStart, nil, 0) if err != nil { t.Errorf("unexpected error: %v", err) } pvIn := &api.PersistentVolume{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", }, Status: api.PersistentVolumeStatus{ Phase: api.VolumeBound, }, } _, _, err = statusStorage.Update(ctx, pvIn.Name, rest.DefaultUpdatedObjectInfo(pvIn, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } pvOut := obj.(*api.PersistentVolume) // only compare the relevant change b/c metadata will differ if !api.Semantic.DeepEqual(pvIn.Status, pvOut.Status) { t.Errorf("unexpected object: %s", diff.ObjectDiff(pvIn.Status, pvOut.Status)) } }
func (s *storage) UpdateService(ctx genericapirequest.Context, svc *api.Service) (*api.Service, error) { obj, _, err := s.Update(ctx, svc.Name, rest.DefaultUpdatedObjectInfo(svc, api.Scheme)) if err != nil { return nil, err } return obj.(*api.Service), nil }
func (s *storage) UpdateController(ctx genericapirequest.Context, controller *api.ReplicationController) (*api.ReplicationController, error) { obj, _, err := s.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller, api.Scheme)) if err != nil { return nil, err } return obj.(*api.ReplicationController), nil }
func (s *storage) UpdateDeployment(ctx genericapirequest.Context, deployment *extensions.Deployment) (*extensions.Deployment, error) { obj, _, err := s.Update(ctx, deployment.Name, rest.DefaultUpdatedObjectInfo(deployment, api.Scheme)) if err != nil { return nil, err } return obj.(*extensions.Deployment), nil }
func TestServiceRegistryIPLoadBalancer(t *testing.T) { storage, _ := NewTestREST(t, nil) svc := &api.Service{ ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz"}, SessionAffinity: api.ServiceAffinityNone, Type: api.ServiceTypeLoadBalancer, Ports: []api.ServicePort{{ Port: 6502, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(6502), }}, }, } ctx := genericapirequest.NewDefaultContext() created_svc, _ := storage.Create(ctx, svc) created_service := created_svc.(*api.Service) if created_service.Spec.Ports[0].Port != 6502 { t.Errorf("Expected port 6502, but got %v", created_service.Spec.Ports[0].Port) } if !makeIPNet(t).Contains(net.ParseIP(created_service.Spec.ClusterIP)) { t.Errorf("Unexpected ClusterIP: %s", created_service.Spec.ClusterIP) } update := deepCloneService(created_service) _, _, err := storage.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(update, api.Scheme)) if err != nil { t.Errorf("Unexpected error %v", err) } }
func TestServiceRegistryUpdateMultiPortExternalService(t *testing.T) { ctx := genericapirequest.NewDefaultContext() storage, _ := NewTestREST(t, nil) // Create external load balancer. svc1 := &api.Service{ ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1"}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz"}, SessionAffinity: api.ServiceAffinityNone, Type: api.ServiceTypeLoadBalancer, Ports: []api.ServicePort{{ Name: "p", Port: 6502, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(6502), }, { Name: "q", Port: 8086, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(8086), }}, }, } if _, err := storage.Create(ctx, svc1); err != nil { t.Fatalf("Unexpected error: %v", err) } // Modify ports svc2 := deepCloneService(svc1) svc2.Spec.Ports[1].Port = 8088 if _, _, err := storage.Update(ctx, svc2.Name, rest.DefaultUpdatedObjectInfo(svc2, api.Scheme)); err != nil { t.Fatalf("Unexpected error: %v", err) } }
func (s *storage) UpdateReplicaSet(ctx genericapirequest.Context, replicaSet *extensions.ReplicaSet) (*extensions.ReplicaSet, error) { obj, _, err := s.Update(ctx, replicaSet.Name, rest.DefaultUpdatedObjectInfo(replicaSet, api.Scheme)) if err != nil { return nil, err } return obj.(*extensions.ReplicaSet), nil }
func TestEtcdUpdateNotScheduled(t *testing.T) { storage, _, _, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewDefaultContext() if _, err := storage.Create(ctx, validNewPod()); err != nil { t.Fatalf("unexpected error: %v", err) } podIn := validChangedPod() _, _, err := storage.Update(ctx, podIn.Name, rest.DefaultUpdatedObjectInfo(podIn, api.Scheme)) if err != nil { t.Errorf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, validNewPod().ObjectMeta.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("unexpected error: %v", err) } podOut := obj.(*api.Pod) // validChangedPod only changes the Labels, so were checking the update was valid if !api.Semantic.DeepEqual(podIn.Labels, podOut.Labels) { t.Errorf("objects differ: %v", diff.ObjectDiff(podOut, podIn)) } }
func TestStatusUpdate(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) defer storage.Deployment.Store.DestroyFunc() ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace) key := "/deployments/" + namespace + "/" + name if err := storage.Deployment.Storage.Create(ctx, key, &validDeployment, nil, 0); err != nil { t.Fatalf("unexpected error: %v", err) } update := extensions.Deployment{ ObjectMeta: validDeployment.ObjectMeta, Spec: extensions.DeploymentSpec{ Replicas: defaultReplicas, }, Status: extensions.DeploymentStatus{ Replicas: defaultReplicas, }, } if _, _, err := storage.Status.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil { t.Fatalf("unexpected error: %v", err) } obj, err := storage.Deployment.Get(ctx, name, &metav1.GetOptions{}) if err != nil { t.Fatalf("unexpected error: %v", err) } deployment := obj.(*extensions.Deployment) if deployment.Spec.Replicas != 7 { t.Errorf("we expected .spec.replicas to not be updated but it was updated to %v", deployment.Spec.Replicas) } if deployment.Status.Replicas != defaultReplicas { t.Errorf("we expected .status.replicas to be updated to %d but it was %v", defaultReplicas, deployment.Status.Replicas) } }
func (s *storage) UpdateConfigMap(ctx genericapirequest.Context, cfg *api.ConfigMap) (*api.ConfigMap, error) { obj, _, err := s.Update(ctx, cfg.Name, rest.DefaultUpdatedObjectInfo(cfg, api.Scheme)) if err != nil { return nil, err } return obj.(*api.ConfigMap), nil }
func TestScaleUpdate(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) defer storage.ReplicaSet.Store.DestroyFunc() name := "foo" var rs extensions.ReplicaSet ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), api.NamespaceDefault) key := "/replicasets/" + api.NamespaceDefault + "/" + name if err := storage.ReplicaSet.Storage.Create(ctx, key, &validReplicaSet, &rs, 0); err != nil { t.Fatalf("error setting new replica set (key: %s) %v: %v", key, validReplicaSet, err) } replicas := 12 update := extensions.Scale{ ObjectMeta: metav1.ObjectMeta{ Name: name, Namespace: api.NamespaceDefault, }, Spec: extensions.ScaleSpec{ Replicas: int32(replicas), }, } if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil { t.Fatalf("error updating scale %v: %v", update, err) } obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{}) if err != nil { t.Fatalf("error fetching scale for %s: %v", name, err) } scale := obj.(*extensions.Scale) if scale.Spec.Replicas != int32(replicas) { t.Errorf("wrong replicas count expected: %d got: %d", replicas, scale.Spec.Replicas) } update.ResourceVersion = rs.ResourceVersion update.Spec.Replicas = 15 if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil && !errors.IsConflict(err) { t.Fatalf("unexpected error, expecting an update conflict but got %v", err) } }
func (t *Tester) testUpdateRetrievesOldObject(obj runtime.Object, createFn CreateFunc, getFn GetFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(6)) objectMeta := t.getObjectMetaOrFail(foo) objectMeta.Annotations = map[string]string{"A": "1"} if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) return } storedFoo, err := getFn(ctx, foo) if err != nil { t.Errorf("unexpected error: %v", err) return } storedFooWithUpdates := copyOrDie(storedFoo) objectMeta = t.getObjectMetaOrFail(storedFooWithUpdates) objectMeta.Annotations = map[string]string{"A": "2"} // Make sure a custom transform is called, and sees the expected updatedObject and oldObject // This tests the mechanism used to pass the old and new object to admission calledUpdatedObject := 0 noopTransform := func(_ genericapirequest.Context, updatedObject runtime.Object, oldObject runtime.Object) (runtime.Object, error) { if !reflect.DeepEqual(storedFoo, oldObject) { t.Errorf("Expected\n\t%#v\ngot\n\t%#v", storedFoo, oldObject) } if !reflect.DeepEqual(storedFooWithUpdates, updatedObject) { t.Errorf("Expected\n\t%#v\ngot\n\t%#v", storedFooWithUpdates, updatedObject) } calledUpdatedObject++ return updatedObject, nil } updatedObj, created, err := t.storage.(rest.Updater).Update(ctx, objectMeta.Name, rest.DefaultUpdatedObjectInfo(storedFooWithUpdates, api.Scheme, noopTransform)) if err != nil { t.Errorf("unexpected error: %v", err) return } if created { t.Errorf("expected no creation for object") return } if updatedObj == nil { t.Errorf("expected non-nil object from update") return } if calledUpdatedObject != 1 { t.Errorf("expected UpdatedObject() to be called 1 time, was called %d", calledUpdatedObject) return } }
func TestServiceStorageValidatesUpdate(t *testing.T) { ctx := genericapirequest.NewDefaultContext() storage, registry := NewTestREST(t, nil) registry.CreateService(ctx, &api.Service{ ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz"}, Ports: []api.ServicePort{{ Port: 6502, Protocol: api.ProtocolTCP, }}, }, }) failureCases := map[string]api.Service{ "empty ID": { ObjectMeta: metav1.ObjectMeta{Name: ""}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz"}, SessionAffinity: api.ServiceAffinityNone, Type: api.ServiceTypeClusterIP, Ports: []api.ServicePort{{ Port: 6502, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(6502), }}, }, }, "invalid selector": { ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: api.ServiceSpec{ Selector: map[string]string{"ThisSelectorFailsValidation": "ok"}, SessionAffinity: api.ServiceAffinityNone, Type: api.ServiceTypeClusterIP, Ports: []api.ServicePort{{ Port: 6502, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(6502), }}, }, }, } for _, failureCase := range failureCases { c, created, err := storage.Update(ctx, failureCase.Name, rest.DefaultUpdatedObjectInfo(&failureCase, api.Scheme)) if c != nil || created { t.Errorf("Expected nil object or created false") } if !errors.IsInvalid(err) { t.Errorf("Expected to get an invalid resource error, got %v", err) } } }
func TestServiceRegistryUpdate(t *testing.T) { ctx := genericapirequest.NewDefaultContext() storage, registry := NewTestREST(t, nil) svc, err := registry.CreateService(ctx, &api.Service{ ObjectMeta: metav1.ObjectMeta{Name: "foo", ResourceVersion: "1", Namespace: api.NamespaceDefault}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz1"}, Ports: []api.ServicePort{{ Port: 6502, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(6502), }}, }, }) if err != nil { t.Fatalf("Expected no error: %v", err) } updated_svc, created, err := storage.Update(ctx, "foo", rest.DefaultUpdatedObjectInfo(&api.Service{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", ResourceVersion: svc.ResourceVersion}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz2"}, SessionAffinity: api.ServiceAffinityNone, Type: api.ServiceTypeClusterIP, Ports: []api.ServicePort{{ Port: 6502, Protocol: api.ProtocolTCP, TargetPort: intstr.FromInt(6502), }}, }, }, api.Scheme)) if err != nil { t.Fatalf("Expected no error: %v", err) } if updated_svc == nil { t.Errorf("Expected non-nil object") } if created { t.Errorf("expected not created") } updated_service := updated_svc.(*api.Service) if updated_service.Name != "foo" { t.Errorf("Expected foo, but got %v", updated_service.Name) } if e, a := "foo", registry.UpdatedID; e != a { t.Errorf("Expected %v, but got %v", e, a) } }
func TestScaleUpdate(t *testing.T) { storage, server := newStorage(t) defer server.Terminate(t) defer storage.Controller.Store.DestroyFunc() ctx := genericapirequest.WithNamespace(genericapirequest.NewContext(), namespace) rc, err := createController(storage.Controller, *validController, t) if err != nil { t.Fatalf("error setting new replication controller %v: %v", *validController, err) } replicas := int32(12) update := autoscaling.Scale{ ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}, Spec: autoscaling.ScaleSpec{ Replicas: replicas, }, } if _, _, err := storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil { t.Fatalf("error updating scale %v: %v", update, err) } obj, err := storage.Scale.Get(ctx, name, &metav1.GetOptions{}) if err != nil { t.Fatalf("error fetching scale for %s: %v", name, err) } scale := obj.(*autoscaling.Scale) if scale.Spec.Replicas != replicas { t.Errorf("wrong replicas count expected: %d got: %d", replicas, rc.Spec.Replicas) } update.ResourceVersion = rc.ResourceVersion update.Spec.Replicas = 15 if _, _, err = storage.Scale.Update(ctx, update.Name, rest.DefaultUpdatedObjectInfo(&update, api.Scheme)); err != nil && !errors.IsConflict(err) { t.Fatalf("unexpected error, expecting an update conflict but got %v", err) } }
func TestUpdateStatus(t *testing.T) { storage, status, server := newStorage(t) defer server.Terminate(t) defer storage.Store.DestroyFunc() ctx := genericapirequest.NewDefaultContext() key, _ := storage.KeyFunc(ctx, "foo") resourcequotaStart := validNewResourceQuota() err := storage.Storage.Create(ctx, key, resourcequotaStart, nil, 0) if err != nil { t.Fatalf("Unexpected error: %v", err) } resourcequotaIn := &api.ResourceQuota{ ObjectMeta: metav1.ObjectMeta{ Name: "foo", Namespace: api.NamespaceDefault, }, Status: api.ResourceQuotaStatus{ Used: api.ResourceList{ api.ResourceCPU: resource.MustParse("1"), api.ResourceMemory: resource.MustParse("1Gi"), api.ResourcePods: resource.MustParse("1"), api.ResourceServices: resource.MustParse("1"), api.ResourceReplicationControllers: resource.MustParse("1"), api.ResourceQuotas: resource.MustParse("1"), }, Hard: api.ResourceList{ api.ResourceCPU: resource.MustParse("100"), api.ResourceMemory: resource.MustParse("4Gi"), api.ResourcePods: resource.MustParse("10"), api.ResourceServices: resource.MustParse("10"), api.ResourceReplicationControllers: resource.MustParse("10"), api.ResourceQuotas: resource.MustParse("1"), }, }, } _, _, err = status.Update(ctx, resourcequotaIn.Name, rest.DefaultUpdatedObjectInfo(resourcequotaIn, api.Scheme)) if err != nil { t.Fatalf("Unexpected error: %v", err) } obj, err := storage.Get(ctx, "foo", &metav1.GetOptions{}) rqOut := obj.(*api.ResourceQuota) // only compare the meaningful update b/c we can't compare due to metadata if !api.Semantic.DeepEqual(resourcequotaIn.Status, rqOut.Status) { t.Errorf("unexpected object: %s", diff.ObjectDiff(resourcequotaIn, rqOut)) } }
func TestUpdateServiceWithConflictingNamespace(t *testing.T) { storage, _ := NewTestREST(t, nil) service := &api.Service{ ObjectMeta: metav1.ObjectMeta{Name: "test", Namespace: "not-default"}, } ctx := genericapirequest.NewDefaultContext() obj, created, err := storage.Update(ctx, service.Name, rest.DefaultUpdatedObjectInfo(service, api.Scheme)) if obj != nil || created { t.Error("Expected a nil object, but we got a value or created was true") } if err == nil { t.Errorf("Expected an error, but we didn't get one") } else if strings.Index(err.Error(), "Service.Namespace does not match the provided context") == -1 { t.Errorf("Expected 'Service.Namespace does not match the provided context' error, got '%s'", err.Error()) } }
func updateAndVerify(t *testing.T, ctx genericapirequest.Context, registry *Store, pod *api.Pod) bool { obj, _, err := registry.Update(ctx, pod.Name, rest.DefaultUpdatedObjectInfo(pod, api.Scheme)) if err != nil { t.Errorf("Unexpected error: %v", err) return false } checkObj, err := registry.Get(ctx, pod.Name, &metav1.GetOptions{}) if err != nil { t.Errorf("Unexpected error: %v", err) return false } if e, a := obj, checkObj; !reflect.DeepEqual(e, a) { t.Errorf("Expected %#v, got %#v", e, a) return false } return true }
func (t *Tester) testUpdateOnNotFound(obj runtime.Object) { t.setObjectMeta(obj, t.namer(0)) _, created, err := t.storage.(rest.Updater).Update(t.TestContext(), t.namer(0), rest.DefaultUpdatedObjectInfo(obj, api.Scheme)) if t.createOnUpdate { if err != nil { t.Errorf("creation allowed on updated, but got an error: %v", err) } if !created { t.Errorf("creation allowed on update, but object not created") } } else { if err == nil { t.Errorf("Expected an error, but we didn't get one") } else if !errors.IsNotFound(err) { t.Errorf("Expected NotFound error, got '%v'", err) } } }