func (t *Tester) testCreateValidatesNames(valid runtime.Object) { for _, invalidName := range path.NameMayNotBe { objCopy := copyOrDie(valid) objCopyMeta := t.getObjectMetaOrFail(objCopy) objCopyMeta.Name = invalidName ctx := t.TestContext() _, err := t.storage.(rest.Creater).Create(ctx, objCopy) if !errors.IsInvalid(err) { t.Errorf("%s: Expected to get an invalid resource error, got '%v'", invalidName, err) } } for _, invalidSuffix := range path.NameMayNotContain { objCopy := copyOrDie(valid) objCopyMeta := t.getObjectMetaOrFail(objCopy) objCopyMeta.Name += invalidSuffix ctx := t.TestContext() _, err := t.storage.(rest.Creater).Create(ctx, objCopy) if !errors.IsInvalid(err) { t.Errorf("%s: Expected to get an invalid resource error, got '%v'", invalidSuffix, err) } } }
// handlePodUpdateError prints a more useful error to the end user when mutating a pod. func handlePodUpdateError(out io.Writer, err error, resource string) { if statusError, ok := err.(*errors.StatusError); ok && errors.IsInvalid(err) { errorDetails := statusError.Status().Details if errorDetails.Kind == "Pod" { all, match := true, false for _, cause := range errorDetails.Causes { if cause.Field == "spec" && strings.Contains(cause.Message, "may not update fields other than") { fmt.Fprintf(out, "error: may not update %s in pod %q directly\n", resource, errorDetails.Name) match = true } else { all = false } } if all && match { return } } else { if ok := kcmdutil.PrintErrorWithCauses(err, out); ok { return } } } fmt.Fprintf(out, "error: %v\n", err) }
func (t *Tester) testCreateInvokesValidation(invalid ...runtime.Object) { for i, obj := range invalid { ctx := t.TestContext() _, err := t.storage.(rest.Creater).Create(ctx, obj) if !errors.IsInvalid(err) { t.Errorf("%d: Expected to get an invalid resource error, got %v", i, 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) } }
// checkErr formats a given error as a string and calls the passed handleErr // func with that string and an kubectl exit code. func checkErr(prefix string, err error, handleErr func(string, int)) { // unwrap aggregates of 1 if agg, ok := err.(utilerrors.Aggregate); ok && len(agg.Errors()) == 1 { err = agg.Errors()[0] } switch { case err == nil: return case err == ErrExit: handleErr("", DefaultErrorExitCode) return case kerrors.IsInvalid(err): details := err.(*kerrors.StatusError).Status().Details s := fmt.Sprintf("%sThe %s %q is invalid", prefix, details.Kind, details.Name) if len(details.Causes) > 0 { errs := statusCausesToAggrError(details.Causes) handleErr(MultilineError(s+": ", errs), DefaultErrorExitCode) } else { handleErr(s, DefaultErrorExitCode) } case clientcmd.IsConfigurationInvalid(err): handleErr(MultilineError(fmt.Sprintf("%sError in configuration: ", prefix), err), DefaultErrorExitCode) default: switch err := err.(type) { case *meta.NoResourceMatchError: switch { case len(err.PartialResource.Group) > 0 && len(err.PartialResource.Version) > 0: handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in group %q and version %q", prefix, err.PartialResource.Resource, err.PartialResource.Group, err.PartialResource.Version), DefaultErrorExitCode) case len(err.PartialResource.Group) > 0: handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in group %q", prefix, err.PartialResource.Resource, err.PartialResource.Group), DefaultErrorExitCode) case len(err.PartialResource.Version) > 0: handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q in version %q", prefix, err.PartialResource.Resource, err.PartialResource.Version), DefaultErrorExitCode) default: handleErr(fmt.Sprintf("%sthe server doesn't have a resource type %q", prefix, err.PartialResource.Resource), DefaultErrorExitCode) } case utilerrors.Aggregate: handleErr(MultipleErrors(prefix, err.Errors()), DefaultErrorExitCode) case utilexec.ExitError: // do not print anything, only terminate with given error handleErr("", err.ExitStatus()) default: // for any other error type msg, ok := StandardErrorMessage(err) if !ok { msg = err.Error() if !strings.HasPrefix(msg, "error: ") { msg = fmt.Sprintf("error: %s", msg) } } handleErr(msg, DefaultErrorExitCode) } } }
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 TestServiceStorageValidatesCreate(t *testing.T) { storage, _ := NewTestREST(t, nil) 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), }}, }, }, "empty port": { ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz"}, SessionAffinity: api.ServiceAffinityNone, Type: api.ServiceTypeClusterIP, Ports: []api.ServicePort{{ Protocol: api.ProtocolTCP, }}, }, }, "missing targetPort": { ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: api.ServiceSpec{ Selector: map[string]string{"bar": "baz"}, SessionAffinity: api.ServiceAffinityNone, Type: api.ServiceTypeClusterIP, Ports: []api.ServicePort{{ Port: 6502, Protocol: api.ProtocolTCP, }}, }, }, } ctx := genericapirequest.NewDefaultContext() for _, failureCase := range failureCases { c, err := storage.Create(ctx, &failureCase) if c != nil { t.Errorf("Expected nil object") } if !errors.IsInvalid(err) { t.Errorf("Expected to get an invalid resource error, got %v", err) } } }
// ReleaseReplicaSet sends a patch to free the ReplicaSet from the control of the Deployment controller. // It returns the error if the patching fails. 404 and 422 errors are ignored. func (m *ReplicaSetControllerRefManager) ReleaseReplicaSet(replicaSet *extensions.ReplicaSet) error { glog.V(2).Infof("patching ReplicaSet %s_%s to remove its controllerRef to %s/%s:%s", replicaSet.Namespace, replicaSet.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.controllerObject.Name) deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.controllerObject.UID, replicaSet.UID) err := m.rsControl.PatchReplicaSet(replicaSet.Namespace, replicaSet.Name, []byte(deleteOwnerRefPatch)) if err != nil { if errors.IsNotFound(err) { // If the ReplicaSet no longer exists, ignore it. return nil } if errors.IsInvalid(err) { // Invalid error will be returned in two cases: 1. the ReplicaSet // has no owner reference, 2. the uid of the ReplicaSet doesn't // match, which means the ReplicaSet is deleted and then recreated. // In both cases, the error can be ignored. return nil } } return err }
func (t *Tester) testUpdateInvokesValidation(obj runtime.Object, createFn CreateFunc, invalidUpdateFn ...UpdateFunc) { ctx := t.TestContext() foo := copyOrDie(obj) t.setObjectMeta(foo, t.namer(4)) if err := createFn(ctx, foo); err != nil { t.Errorf("unexpected error: %v", err) } for _, update := range invalidUpdateFn { toUpdate := update(copyOrDie(foo)) toUpdateMeta := t.getObjectMetaOrFail(toUpdate) got, created, err := t.storage.(rest.Updater).Update(t.TestContext(), toUpdateMeta.Name, rest.DefaultUpdatedObjectInfo(toUpdate, api.Scheme)) if got != nil || created { t.Errorf("expected nil object and no creation for object: %v", toUpdate) } if !errors.IsInvalid(err) && !errors.IsBadRequest(err) { t.Errorf("expected invalid or bad request error, got %v", err) } } }
func TestPodLogValidates(t *testing.T) { config, server := registrytest.NewEtcdStorage(t, "") defer server.Terminate(t) s, destroyFunc := generic.NewRawStorage(config) defer destroyFunc() store := &genericregistry.Store{ Storage: s, } logRest := &LogREST{Store: store, KubeletConn: nil} negativeOne := int64(-1) testCases := []*api.PodLogOptions{ {SinceSeconds: &negativeOne}, {TailLines: &negativeOne}, } for _, tc := range testCases { _, err := logRest.Get(genericapirequest.NewDefaultContext(), "test", tc) if !errors.IsInvalid(err) { t.Fatalf("unexpected error: %v", err) } } }
func (r *editResults) addError(err error, info *resource.Info) string { switch { case errors.IsInvalid(err): r.edit = append(r.edit, info) reason := editReason{ head: fmt.Sprintf("%s %q was not valid", info.Mapping.Resource, info.Name), } if err, ok := err.(errors.APIStatus); ok { if details := err.Status().Details; details != nil { for _, cause := range details.Causes { reason.other = append(reason.other, fmt.Sprintf("%s: %s", cause.Field, cause.Message)) } } } r.header.reasons = append(r.header.reasons, reason) return fmt.Sprintf("error: %s %q is invalid", info.Mapping.Resource, info.Name) case errors.IsNotFound(err): r.notfound++ return fmt.Sprintf("error: %s %q could not be found on the server", info.Mapping.Resource, info.Name) default: r.retryable++ return fmt.Sprintf("error: %s %q could not be patched: %v", info.Mapping.Resource, info.Name, err) } }
// ReleasePod sends a patch to free the pod from the control of the controller. // It returns the error if the patching fails. 404 and 422 errors are ignored. func (m *PodControllerRefManager) ReleasePod(pod *v1.Pod) error { glog.V(2).Infof("patching pod %s_%s to remove its controllerRef to %s/%s:%s", pod.Namespace, pod.Name, m.controllerKind.GroupVersion(), m.controllerKind.Kind, m.controllerObject.Name) deleteOwnerRefPatch := fmt.Sprintf(`{"metadata":{"ownerReferences":[{"$patch":"delete","uid":"%s"}],"uid":"%s"}}`, m.controllerObject.UID, pod.UID) err := m.podControl.PatchPod(pod.Namespace, pod.Name, []byte(deleteOwnerRefPatch)) if err != nil { if errors.IsNotFound(err) { // If the pod no longer exists, ignore it. return nil } if errors.IsInvalid(err) { // Invalid error will be returned in two cases: 1. the pod // has no owner reference, 2. the uid of the pod doesn't // match, which means the pod is deleted and then recreated. // In both cases, the error can be ignored. // TODO: If the pod has owner references, but none of them // has the owner.UID, server will silently ignore the patch. // Investigate why. return nil } } return err }
func TestPatchWithCreateOnUpdate(t *testing.T) { _, s := framework.RunAMaster(nil) defer s.Close() c := clientset.NewForConfigOrDie(&restclient.Config{Host: s.URL, ContentConfig: restclient.ContentConfig{GroupVersion: &api.Registry.GroupOrDie(v1.GroupName).GroupVersion}}) ns := framework.CreateTestingNamespace("patch-with-create", s, t) defer framework.DeleteTestingNamespace(ns, s, t) endpointTemplate := &v1.Endpoints{ ObjectMeta: metav1.ObjectMeta{ Name: "patchendpoint", Namespace: ns.Name, }, Subsets: []v1.EndpointSubset{ { Addresses: []v1.EndpointAddress{{IP: "1.2.3.4"}}, Ports: []v1.EndpointPort{{Port: 80, Protocol: v1.ProtocolTCP}}, }, }, } patchEndpoint := func(json []byte) (runtime.Object, error) { return c.Core().RESTClient().Patch(types.MergePatchType).Resource("endpoints").Namespace(ns.Name).Name("patchendpoint").Body(json).Do().Get() } // Make sure patch doesn't get to CreateOnUpdate { endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if obj, err := patchEndpoint(endpointJSON); !apierrors.IsNotFound(err) { t.Errorf("Expected notfound creating from patch, got error=%v and object: %#v", err, obj) } } // Create the endpoint (endpoints set AllowCreateOnUpdate=true) to get a UID and resource version createdEndpoint, err := c.Core().Endpoints(ns.Name).Update(endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint: %v", err) } // Make sure identity patch is accepted { endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), createdEndpoint) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); err != nil { t.Errorf("Failed patching endpoint: %v", err) } } // Make sure patch complains about a mismatched resourceVersion { endpointTemplate.Name = "" endpointTemplate.UID = "" endpointTemplate.ResourceVersion = "1" endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); !apierrors.IsConflict(err) { t.Errorf("Expected error, got %#v", err) } } // Make sure patch complains about mutating the UID { endpointTemplate.Name = "" endpointTemplate.UID = "abc" endpointTemplate.ResourceVersion = "" endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); !apierrors.IsInvalid(err) { t.Errorf("Expected error, got %#v", err) } } // Make sure patch complains about a mismatched name { endpointTemplate.Name = "changedname" endpointTemplate.UID = "" endpointTemplate.ResourceVersion = "" endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); !apierrors.IsBadRequest(err) { t.Errorf("Expected error, got %#v", err) } } // Make sure patch containing originally submitted JSON is accepted { endpointTemplate.Name = "" endpointTemplate.UID = "" endpointTemplate.ResourceVersion = "" endpointJSON, err := runtime.Encode(api.Codecs.LegacyCodec(v1.SchemeGroupVersion), endpointTemplate) if err != nil { t.Fatalf("Failed creating endpoint JSON: %v", err) } if _, err := patchEndpoint(endpointJSON); err != nil { t.Errorf("Failed patching endpoint: %v", err) } } }
_, err := cs.Core().Pods(ns).Create(initPausePod(f, pausePodConfig{ Name: podName, Affinity: &v1.Affinity{ NodeAffinity: &v1.NodeAffinity{ RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{ NodeSelectorTerms: []v1.NodeSelectorTerm{ { MatchExpressions: []v1.NodeSelectorRequirement{}, }, }, }, }, }, })) if err == nil || !errors.IsInvalid(err) { framework.Failf("Expect error of invalid, got : %v", err) } // Wait a bit to allow scheduler to do its thing if the pod is not rejected. waitForScheduler() }) It("validates that NodeSelector is respected if matching [Conformance]", func() { nodeName := getNodeThatCanRunPod(f) By("Trying to apply a random label on the found node.") k := fmt.Sprintf("kubernetes.io/e2e-%s", string(uuid.NewUUID())) v := "42" framework.AddOrUpdateLabelOnNode(cs, nodeName, k, v) framework.ExpectNodeHasLabel(cs, nodeName, k, v)