func (t *Tester) testCreateValidatesNames(valid runtime.Object) { for _, invalidName := range validation.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 validation.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) } } }
func TestEtcdCreateBinding(t *testing.T) { ctx := api.NewDefaultContext() testCases := map[string]struct { binding api.Binding errOK func(error) bool }{ "noName": { binding: api.Binding{ ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"}, Target: api.ObjectReference{}, }, errOK: func(err error) bool { return errors.IsInvalid(err) }, }, "badKind": { binding: api.Binding{ ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"}, Target: api.ObjectReference{Name: "machine1", Kind: "unknown"}, }, errOK: func(err error) bool { return errors.IsInvalid(err) }, }, "emptyKind": { binding: api.Binding{ ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"}, Target: api.ObjectReference{Name: "machine2"}, }, errOK: func(err error) bool { return err == nil }, }, "kindNode": { binding: api.Binding{ ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "foo"}, Target: api.ObjectReference{Name: "machine3", Kind: "Node"}, }, errOK: func(err error) bool { return err == nil }, }, } for k, test := range testCases { storage, bindingStorage, _, server := newStorage(t) key, _ := storage.KeyFunc(ctx, "foo") key = etcdtest.AddPrefix(key) if _, err := storage.Create(ctx, validNewPod()); err != nil { t.Fatalf("%s: unexpected error: %v", k, err) } if _, err := bindingStorage.Create(ctx, &test.binding); !test.errOK(err) { t.Errorf("%s: unexpected error: %v", k, err) } else if err == nil { // If bind succeeded, verify Host field in pod's Spec. pod, err := storage.Get(ctx, validNewPod().ObjectMeta.Name) if err != nil { t.Errorf("%s: unexpected error: %v", k, err) } else if pod.(*api.Pod).Spec.NodeName != test.binding.Target.Name { t.Errorf("%s: expected: %v, got: %v", k, pod.(*api.Pod).Spec.NodeName, test.binding.Target.Name) } } server.Terminate(t) } }
// 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 checkCustomErr(customPrefix string, err error, handleErr func(string)) { if err == nil { return } if errors.IsInvalid(err) { details := err.(*errors.StatusError).Status().Details for i := range details.Causes { c := &details.Causes[i] s := strings.Split(c.Message, "}': ") if len(s) == 2 { c.Message = s[1] c.Field = "" } } prefix := fmt.Sprintf("%s", customPrefix) errs := statusCausesToAggrError(details.Causes) handleErr(MultilineError(prefix, errs)) } // handle multiline errors if clientcmd.IsConfigurationInvalid(err) { handleErr(MultilineError("Error in configuration: ", err)) } if agg, ok := err.(utilerrors.Aggregate); ok && len(agg.Errors()) > 0 { handleErr(MultipleErrors("", agg.Errors())) } msg, ok := StandardErrorMessage(err) if !ok { msg = fmt.Sprintf("error: %s\n", err.Error()) } handleErr(msg) }
func TestEtcdControllerValidatesUpdate(t *testing.T) { ctx := api.NewDefaultContext() storage, _ := newStorage(t) updateController, err := createController(storage, validController, t) if err != nil { t.Errorf("Failed to create controller, cannot proceed with test.") } updaters := []func(rc api.ReplicationController) (runtime.Object, bool, error){ func(rc api.ReplicationController) (runtime.Object, bool, error) { rc.UID = "newUID" return storage.Update(ctx, &rc) }, func(rc api.ReplicationController) (runtime.Object, bool, error) { rc.Name = "" return storage.Update(ctx, &rc) }, func(rc api.ReplicationController) (runtime.Object, bool, error) { rc.Spec.Selector = map[string]string{} return storage.Update(ctx, &rc) }, } for _, u := range updaters { c, updated, err := u(updateController) if c != nil || updated { t.Errorf("Expected nil object and not created") } if !errors.IsInvalid(err) && !errors.IsBadRequest(err) { t.Errorf("Expected invalid or bad request error, got %v of type %T", err, err) } } }
// NewCommandStartEtcdServer starts only the etcd server func NewCommandStartEtcdServer(name, basename string, out io.Writer) (*cobra.Command, *EtcdOptions) { options := &EtcdOptions{Output: out} cmd := &cobra.Command{ Use: name, Short: "Launch etcd server", Long: fmt.Sprintf(etcdLong, basename, name), Run: func(c *cobra.Command, args []string) { kcmdutil.CheckErr(options.Validate()) startProfiler() if err := options.StartEtcdServer(); err != nil { if kerrors.IsInvalid(err) { if details := err.(*kerrors.StatusError).ErrStatus.Details; details != nil { fmt.Fprintf(c.OutOrStderr(), "Invalid %s %s\n", details.Kind, details.Name) for _, cause := range details.Causes { fmt.Fprintf(c.OutOrStderr(), " %s: %s\n", cause.Field, cause.Message) } os.Exit(255) } } glog.Fatal(err) } }, } flags := cmd.Flags() // This command only supports reading from config flags.StringVar(&options.ConfigFile, "config", "", "Location of the master configuration file to run from.") cmd.MarkFlagFilename("config", "yaml", "yml") cmd.MarkFlagRequired("config") return cmd, options }
func TestUpdateWithEmptyResourceVersion(t *testing.T) { // Starting conditions associatedUser1, associatedIdentity1User1 := makeAssociated() unassociatedUser2 := makeUser() // Finishing conditions _, unassociatedIdentity1 := disassociate(associatedUser1, associatedIdentity1User1) expectedActions := []test.Action{ // Existing mapping lookup {"GetIdentity", associatedIdentity1User1.Name}, {"GetUser", associatedUser1.Name}, } mapping := &api.UserIdentityMapping{ Identity: kapi.ObjectReference{Name: unassociatedIdentity1.Name}, User: kapi.ObjectReference{Name: unassociatedUser2.Name}, } actions, _, _, rest := setupRegistries(associatedIdentity1User1, associatedUser1, unassociatedUser2) _, _, err := rest.Update(kapi.NewContext(), mapping.Name, kapirest.DefaultUpdatedObjectInfo(mapping, kapi.Scheme)) if err == nil { t.Errorf("Expected error") } if !kerrs.IsInvalid(err) { t.Errorf("Unexpected error: %v", err) } verifyActions(expectedActions, *actions, t) }
func checkErr(err error, handleErr func(string)) { if err == nil { return } if errors.IsInvalid(err) { details := err.(*errors.StatusError).Status().Details prefix := fmt.Sprintf("The %s %q is invalid:", details.Kind, details.Name) errs := statusCausesToAggrError(details.Causes) handleErr(MultilineError(prefix, errs)) } // handle multiline errors if clientcmd.IsConfigurationInvalid(err) { handleErr(MultilineError("Error in configuration: ", err)) } if agg, ok := err.(utilerrors.Aggregate); ok && len(agg.Errors()) > 0 { handleErr(MultipleErrors("", agg.Errors())) } msg, ok := StandardErrorMessage(err) if !ok { msg = fmt.Sprintf("error: %s\n", err.Error()) } handleErr(msg) }
func TestEtcdParseWatchResourceVersion(t *testing.T) { testCases := []struct { Version string Kind string ExpectVersion uint64 Err bool }{ {Version: "", ExpectVersion: 0}, {Version: "a", Err: true}, {Version: " ", Err: true}, {Version: "1", ExpectVersion: 2}, {Version: "10", ExpectVersion: 11}, } for _, testCase := range testCases { version, err := ParseWatchResourceVersion(testCase.Version, testCase.Kind) switch { case testCase.Err: if err == nil { t.Errorf("%s: unexpected non-error", testCase.Version) continue } if !errors.IsInvalid(err) { t.Errorf("%s: unexpected error: %v", testCase.Version, err) continue } case !testCase.Err && err != nil: t.Errorf("%s: unexpected error: %v", testCase.Version, err) continue } if version != testCase.ExpectVersion { t.Errorf("%s: expected version %d but was %d", testCase.Version, testCase.ExpectVersion, version) } } }
func TestUpdateMissingUser(t *testing.T) { // Starting conditions associatedUser1, associatedIdentity1User1 := makeAssociated() unassociatedUser2 := makeUser() // Finishing conditions _, unassociatedIdentity1 := disassociate(associatedUser1, associatedIdentity1User1) expectedActions := []test.Action{ // Existing mapping lookup {"GetIdentity", associatedIdentity1User1.Name}, {"GetUser", associatedUser1.Name}, // New user lookup {"GetUser", unassociatedUser2.Name}, } mapping := &api.UserIdentityMapping{ ObjectMeta: kapi.ObjectMeta{ResourceVersion: unassociatedIdentity1.ResourceVersion}, Identity: kapi.ObjectReference{Name: unassociatedIdentity1.Name}, User: kapi.ObjectReference{Name: unassociatedUser2.Name}, } actions, _, _, rest := setupRegistries(associatedIdentity1User1, associatedUser1) _, _, err := rest.Update(kapi.NewContext(), mapping) if err == nil { t.Errorf("Expected error: %v", err) } if !kerrs.IsInvalid(err) { t.Errorf("Unexpected error: %v", err) } verifyActions(expectedActions, *actions, t) }
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) } } }
// IsErrorLimitExceeded returns true if the given error is a limit error. func IsErrorLimitExceeded(err error) bool { if isForbidden := apierrs.IsForbidden(err); isForbidden || apierrs.IsInvalid(err) { lowered := strings.ToLower(err.Error()) // the limit error message can be accompanied only by Invalid reason if strings.Contains(lowered, errLimitsMessageString) { return true } } return false }
// isInvalidTriggerError returns true if the given error is // a validation error that contains 'invalid trigger type' in its // error message. This error is returned from older servers that // consider the presence of unknown trigger types to be an error. func isInvalidTriggerError(err error) bool { if !kapierrors.IsInvalid(err) { return false } statusErr, ok := err.(*kapierrors.StatusError) if !ok { return false } return strings.Contains(statusErr.Status().Message, "invalid trigger type") }
func (t *Tester) TestDeleteInvokesValidation(invalid ...runtime.Object) { for i, obj := range invalid { objectMeta := t.getObjectMetaOrFail(obj) ctx := t.TestContext() _, err := t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, nil) if !errors.IsInvalid(err) { t.Errorf("%d: Expected to get an invalid resource error, got %v", i, err) } } }
func TestCreateInvalidProject(t *testing.T) { mockClient := &testclient.Fake{} storage := NewREST(mockClient.Namespaces(), &mockLister{}) _, err := storage.Create(nil, &api.Project{ ObjectMeta: kapi.ObjectMeta{ Annotations: map[string]string{"openshift.io/display-name": "h\t\ni"}, }, }) if !errors.IsInvalid(err) { t.Errorf("Expected 'invalid' error, got %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) } } }
// NewCommandStartMasterAPI starts only the APIserver func NewCommandStartMasterAPI(name, basename string, out io.Writer) (*cobra.Command, *MasterOptions) { options := &MasterOptions{Output: out} options.DefaultsFromName(basename) cmd := &cobra.Command{ Use: name, Short: "Launch master API", Long: fmt.Sprintf(apiLong, basename, name), Run: func(c *cobra.Command, args []string) { if err := options.Complete(); err != nil { fmt.Fprintln(c.Out(), kcmdutil.UsageError(c, err.Error())) return } if len(options.ConfigFile) == 0 { fmt.Fprintln(c.Out(), kcmdutil.UsageError(c, "--config is required for this command")) return } if err := options.Validate(args); err != nil { fmt.Fprintln(c.Out(), kcmdutil.UsageError(c, err.Error())) return } startProfiler() if err := options.StartMaster(); err != nil { if kerrors.IsInvalid(err) { if details := err.(*kerrors.StatusError).ErrStatus.Details; details != nil { fmt.Fprintf(c.Out(), "Invalid %s %s\n", details.Kind, details.Name) for _, cause := range details.Causes { fmt.Fprintf(c.Out(), " %s: %s\n", cause.Field, cause.Message) } os.Exit(255) } } glog.Fatal(err) } }, } options.MasterArgs = NewDefaultMasterArgs() options.MasterArgs.StartAPI = true flags := cmd.Flags() // This command only supports reading from config and the listen argument flags.StringVar(&options.ConfigFile, "config", "", "Location of the master configuration file to run from. Required") cmd.MarkFlagFilename("config", "yaml", "yml") // TODO: add health and metrics endpoints on this listen argument BindListenArg(options.MasterArgs.ListenArg, flags, "") return cmd, options }
func TestCreateMissingID(t *testing.T) { _, helper := newHelper(t) storage := NewREST(helper) obj, err := storage.Create(kapi.NewDefaultContext(), &api.Image{}) if obj != nil { t.Errorf("Expected nil obj, got %v", obj) } if !errors.IsInvalid(err) { t.Errorf("Expected 'invalid' error, got %v", err) } }
func TestServiceRegistryIPUpdate(t *testing.T) { storage, _ := NewTestREST(t, nil) svc := &api.Service{ ObjectMeta: api.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 := api.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 (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 %s was not valid", info.Mapping.Kind, info.Name), } if err, ok := err.(kclient.APIStatus); ok { if details := err.Status().Details; details != nil { for _, cause := range details.Causes { reason.other = append(reason.other, cause.Message) } } } r.header.reasons = append(r.header.reasons, reason) return fmt.Sprintf("Error: the %s %s is invalid", info.Mapping.Kind, info.Name) case errors.IsNotFound(err): r.notfound++ return fmt.Sprintf("Error: the %s %s has been deleted on the server", info.Mapping.Kind, info.Name) case errors.IsConflict(err): if r.delta != nil { v1 := info.ResourceVersion if perr := applyPatch(r.delta, info, r.version); perr != nil { // the error was related to the patching process if nerr, ok := perr.(patchError); ok { r.conflict++ if jsonmerge.IsPreconditionFailed(nerr.error) { return fmt.Sprintf("Error: the API version of the provided object cannot be changed") } // the patch is in conflict, report to user and exit if jsonmerge.IsConflicting(nerr.error) { // TODO: read message return fmt.Sprintf("Error: a conflicting change was made to the %s %s on the server", info.Mapping.Kind, info.Name) } glog.V(4).Infof("Attempted to patch the resource, but failed: %v", perr) return fmt.Sprintf("Error: %v", err) } // try processing this server error and unset delta so we don't recurse r.delta = nil return r.AddError(err, info) } return fmt.Sprintf("Applied your changes to %s from version %s onto %s", info.Name, v1, info.ResourceVersion) } // no delta was available r.conflict++ return fmt.Sprintf("Error: %v", err) default: r.retryable++ return fmt.Sprintf("Error: the %s %s could not be updated: %v", info.Mapping.Kind, info.Name, err) } }
// NewCommandStartNode provides a CLI handler for 'start node' command func NewCommandStartNode(fullName string, out io.Writer) (*cobra.Command, *NodeOptions) { options := &NodeOptions{Output: out} cmd := &cobra.Command{ Use: "node", Short: "Launch a node", Long: fmt.Sprintf(nodeLong, fullName), Run: func(c *cobra.Command, args []string) { if err := options.Complete(); err != nil { fmt.Println(err.Error()) c.Help() return } if err := options.Validate(args); err != nil { fmt.Println(err.Error()) c.Help() return } startProfiler() if err := options.StartNode(); err != nil { if kerrors.IsInvalid(err) { if details := err.(*kerrors.StatusError).ErrStatus.Details; details != nil { fmt.Fprintf(out, "Invalid %s %s\n", details.Kind, details.Name) for _, cause := range details.Causes { fmt.Fprintf(out, " %s: %s\n", cause.Field, cause.Message) } os.Exit(255) } } glog.Fatal(err) } }, } flags := cmd.Flags() flags.StringVar(&options.ConfigFile, "config", "", "Location of the node configuration file to run from. When running from a configuration file, all other command-line arguments are ignored.") options.NodeArgs = NewDefaultNodeArgs() BindNodeArgs(options.NodeArgs, flags, "") BindListenArg(options.NodeArgs.ListenArg, flags, "") BindImageFormatArgs(options.NodeArgs.ImageFormatArgs, flags, "") BindKubeConnectionArgs(options.NodeArgs.KubeConnectionArgs, flags, "") // autocompletion hints cmd.MarkFlagFilename("config", "yaml", "yml") return cmd, options }
func (t *Tester) TestDeleteInvokesValidation(invalid ...runtime.Object) { for i, obj := range invalid { objectMeta, err := api.ObjectMetaFor(obj) if err != nil { t.Fatalf("object does not have ObjectMeta: %v\n%#v", err, obj) } ctx := t.TestContext() _, err = t.storage.(rest.GracefulDeleter).Delete(ctx, objectMeta.Name, nil) if !errors.IsInvalid(err) { t.Errorf("%d: Expected to get an invalid resource error, got %v", i, err) } } }
func TestServiceStorageValidatesUpdate(t *testing.T) { ctx := api.NewDefaultContext() storage, registry := NewTestREST(t, nil) registry.CreateService(ctx, &api.Service{ ObjectMeta: api.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: api.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: api.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: api.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: api.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: api.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 := api.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) } } }
func isInvalidSourceInputsError(err error) bool { if err != nil { if statusErr, ok := err.(*kerrors.StatusError); ok { if kerrors.IsInvalid(statusErr) { for _, cause := range statusErr.ErrStatus.Details.Causes { if cause.Field == "spec.source" { return true } } } } } return false }
func TestEtcdCreateControllerValidates(t *testing.T) { ctx := api.NewDefaultContext() storage, _ := newStorage(t) emptyName := validController emptyName.Name = "" failureCases := []api.Daemon{emptyName} for _, failureCase := range failureCases { c, err := storage.Create(ctx, &failureCase) if c != nil { t.Errorf("Expected nil channel") } if !errors.IsInvalid(err) { t.Errorf("Expected to get an invalid resource error, got %v", err) } } }
func checkErr(err error, handleErr func(string)) { if err == nil { return } if kerrors.IsInvalid(err) { details := err.(*kerrors.StatusError).Status().Details prefix := fmt.Sprintf("The %s %q is invalid.\n", details.Kind, details.Name) errs := statusCausesToAggrError(details.Causes) handleErr(MultilineError(prefix, errs)) return } if noMatch, ok := err.(*meta.NoResourceMatchError); ok { switch { case len(noMatch.PartialResource.Group) > 0 && len(noMatch.PartialResource.Version) > 0: handleErr(fmt.Sprintf("the server doesn't have a resource type %q in group %q and version %q", noMatch.PartialResource.Resource, noMatch.PartialResource.Group, noMatch.PartialResource.Version)) case len(noMatch.PartialResource.Group) > 0: handleErr(fmt.Sprintf("the server doesn't have a resource type %q in group %q", noMatch.PartialResource.Resource, noMatch.PartialResource.Group)) case len(noMatch.PartialResource.Version) > 0: handleErr(fmt.Sprintf("the server doesn't have a resource type %q in version %q", noMatch.PartialResource.Resource, noMatch.PartialResource.Version)) default: handleErr(fmt.Sprintf("the server doesn't have a resource type %q", noMatch.PartialResource.Resource)) } return } // handle multiline errors if clientcmd.IsConfigurationInvalid(err) { handleErr(MultilineError("Error in configuration: ", err)) return } if agg, ok := err.(utilerrors.Aggregate); ok && len(agg.Errors()) > 0 { handleErr(MultipleErrors("", agg.Errors())) return } msg, ok := StandardErrorMessage(err) if !ok { msg = err.Error() if !strings.HasPrefix(msg, "error: ") { msg = fmt.Sprintf("error: %s", msg) } } handleErr(msg) }
// TODO: remove, this is covered by RESTTest.TestCreate func TestPodStorageValidatesCreate(t *testing.T) { fakeEtcdClient, etcdStorage := newEtcdStorage(t) fakeEtcdClient.Err = fmt.Errorf("test error") storage := NewStorage(etcdStorage, nil).Pod pod := validNewPod() pod.Labels = map[string]string{ "invalid/label/to/cause/validation/failure": "bar", } c, err := storage.Create(api.NewDefaultContext(), pod) if c != nil { t.Errorf("Expected nil object") } if !errors.IsInvalid(err) { t.Errorf("Expected to get an invalid resource error, got %v", err) } }
func TestPodLogValidates(t *testing.T) { etcdStorage, _ := registrytest.NewEtcdStorage(t, "") storage := NewStorage(etcdStorage, false, nil) negativeOne := int64(-1) testCases := []*api.PodLogOptions{ {SinceSeconds: &negativeOne}, {TailLines: &negativeOne}, } for _, tc := range testCases { _, err := storage.Log.Get(api.NewDefaultContext(), "test", tc) if !errors.IsInvalid(err) { t.Fatalf("unexpected error: %v", err) } } }
func TestServiceRegistryIPUpdate(t *testing.T) { rest, _ := NewTestREST(t, nil) svc := &api.Service{ ObjectMeta: api.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: util.NewIntOrStringFromInt(6502), }}, }, } ctx := api.NewDefaultContext() created_svc, _ := rest.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, _, _ := rest.Update(ctx, update) 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) } update = deepCloneService(created_service) update.Spec.Ports[0].Port = 6503 update.Spec.ClusterIP = "1.2.3.76" // error _, _, err := rest.Update(ctx, update) if err == nil || !errors.IsInvalid(err) { t.Errorf("Unexpected error type: %v", err) } }