func ValidateDeploymentRollback(obj *extensions.DeploymentRollback) field.ErrorList { allErrs := apivalidation.ValidateAnnotations(obj.UpdatedAnnotations, field.NewPath("updatedAnnotations")) if len(obj.Name) == 0 { allErrs = append(allErrs, field.Required(field.NewPath("name"), "name is required")) } allErrs = append(allErrs, ValidateRollback(&obj.RollbackTo, field.NewPath("rollback"))...) return allErrs }
func ValidateClusterAutoscaler(autoscaler *extensions.ClusterAutoscaler) field.ErrorList { allErrs := field.ErrorList{} if autoscaler.Name != "ClusterAutoscaler" { allErrs = append(allErrs, field.Invalid(field.NewPath("metadata", "name"), autoscaler.Name, "must be 'ClusterAutoscaler'")) } if autoscaler.Namespace != api.NamespaceDefault { allErrs = append(allErrs, field.Invalid(field.NewPath("metadata", "namespace"), autoscaler.Namespace, "must be 'default'")) } allErrs = append(allErrs, validateClusterAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...) return allErrs }
func ValidateThirdPartyResourceData(obj *extensions.ThirdPartyResourceData) field.ErrorList { allErrs := field.ErrorList{} if len(obj.Name) == 0 { allErrs = append(allErrs, field.Required(field.NewPath("name"), "")) } return allErrs }
func TestValidateSelfSAR(t *testing.T) { successCases := []authorizationapi.SelfSubjectAccessReviewSpec{ {ResourceAttributes: &authorizationapi.ResourceAttributes{}}, } for _, successCase := range successCases { if errs := ValidateSelfSubjectAccessReviewSpec(successCase, field.NewPath("spec")); len(errs) != 0 { t.Errorf("expected success: %v", errs) } } errorCases := []struct { name string obj authorizationapi.SelfSubjectAccessReviewSpec msg string }{ { name: "neither request", obj: authorizationapi.SelfSubjectAccessReviewSpec{}, msg: "exactly one of nonResourceAttributes or resourceAttributes must be specified", }, { name: "both requests", obj: authorizationapi.SelfSubjectAccessReviewSpec{ ResourceAttributes: &authorizationapi.ResourceAttributes{}, NonResourceAttributes: &authorizationapi.NonResourceAttributes{}, }, msg: "cannot be specified in combination with resourceAttributes", }, } for _, c := range errorCases { errs := ValidateSelfSubjectAccessReviewSpec(c.obj, field.NewPath("spec")) if len(errs) == 0 { t.Errorf("%s: expected failure for %q", c.name, c.msg) } else if !strings.Contains(errs[0].Error(), c.msg) { t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg) } errs = ValidateSelfSubjectAccessReview(&authorizationapi.SelfSubjectAccessReview{Spec: c.obj}) if len(errs) == 0 { t.Errorf("%s: expected failure for %q", c.name, c.msg) } else if !strings.Contains(errs[0].Error(), c.msg) { t.Errorf("%s: unexpected error: %q, expected: %q", c.name, errs[0], c.msg) } } }
func ValidateThirdPartyResource(obj *extensions.ThirdPartyResource) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateThirdPartyResourceName, field.NewPath("metadata"))...) versions := sets.String{} for ix := range obj.Versions { version := &obj.Versions[ix] if len(version.Name) == 0 { allErrs = append(allErrs, field.Invalid(field.NewPath("versions").Index(ix).Child("name"), version, "must not be empty")) } if versions.Has(version.Name) { allErrs = append(allErrs, field.Duplicate(field.NewPath("versions").Index(ix).Child("name"), version)) } versions.Insert(version.Name) } return allErrs }
func ValidateScale(scale *extensions.Scale) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateObjectMeta(&scale.ObjectMeta, true, apivalidation.NameIsDNSSubdomain, field.NewPath("metadata"))...) if scale.Spec.Replicas < 0 { allErrs = append(allErrs, field.Invalid(field.NewPath("spec", "replicas"), scale.Spec.Replicas, "must be greater than or equal to 0")) } return allErrs }
// ValidateEvent makes sure that the event makes sense. func ValidateEvent(event *api.Event) field.ErrorList { allErrs := field.ErrorList{} // There is no namespace required for node. // However, older client code accidentally sets event.Namespace // to api.NamespaceDefault, so we accept that too, but "" is preferred. if event.InvolvedObject.Kind == "Node" && event.Namespace != api.NamespaceDefault && event.Namespace != "" { allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "not allowed for node")) } if event.InvolvedObject.Kind != "Node" && event.Namespace != event.InvolvedObject.Namespace { allErrs = append(allErrs, field.Invalid(field.NewPath("involvedObject", "namespace"), event.InvolvedObject.Namespace, "does not match involvedObject")) } if !validation.IsDNS1123Subdomain(event.Namespace) { allErrs = append(allErrs, field.Invalid(field.NewPath("namespace"), event.Namespace, "")) } return allErrs }
// ValidateReplicaSet tests if required fields in the ReplicaSet are set. func ValidateReplicaSet(rs *extensions.ReplicaSet) field.ErrorList { allErrs := apivalidation.ValidateObjectMeta(&rs.ObjectMeta, true, ValidateReplicaSetName, field.NewPath("metadata")) allErrs = append(allErrs, ValidateReplicaSetSpec(&rs.Spec, field.NewPath("spec"))...) return allErrs }
func ValidateThirdPartyResourceUpdate(update, old *extensions.ThirdPartyResource) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))...) allErrs = append(allErrs, ValidateThirdPartyResource(update)...) return allErrs }
// ValidateIngressStatusUpdate tests if required fields in the Ingress are set when updating status. func ValidateIngressStatusUpdate(ingress, oldIngress *extensions.Ingress) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, apivalidation.ValidateLoadBalancerStatus(&ingress.Status.LoadBalancer, field.NewPath("status", "loadBalancer"))...) return allErrs }
func TestNewInvalid(t *testing.T) { testCases := []struct { Err *field.Error Details *unversioned.StatusDetails }{ { field.Duplicate(field.NewPath("field[0].name"), "bar"), &unversioned.StatusDetails{ Kind: "Kind", Name: "name", Causes: []unversioned.StatusCause{{ Type: unversioned.CauseTypeFieldValueDuplicate, Field: "field[0].name", }}, }, }, { field.Invalid(field.NewPath("field[0].name"), "bar", "detail"), &unversioned.StatusDetails{ Kind: "Kind", Name: "name", Causes: []unversioned.StatusCause{{ Type: unversioned.CauseTypeFieldValueInvalid, Field: "field[0].name", }}, }, }, { field.NotFound(field.NewPath("field[0].name"), "bar"), &unversioned.StatusDetails{ Kind: "Kind", Name: "name", Causes: []unversioned.StatusCause{{ Type: unversioned.CauseTypeFieldValueNotFound, Field: "field[0].name", }}, }, }, { field.NotSupported(field.NewPath("field[0].name"), "bar", nil), &unversioned.StatusDetails{ Kind: "Kind", Name: "name", Causes: []unversioned.StatusCause{{ Type: unversioned.CauseTypeFieldValueNotSupported, Field: "field[0].name", }}, }, }, { field.Required(field.NewPath("field[0].name"), ""), &unversioned.StatusDetails{ Kind: "Kind", Name: "name", Causes: []unversioned.StatusCause{{ Type: unversioned.CauseTypeFieldValueRequired, Field: "field[0].name", }}, }, }, } for i, testCase := range testCases { vErr, expected := testCase.Err, testCase.Details expected.Causes[0].Message = vErr.ErrorBody() err := NewInvalid(api.Kind("Kind"), "name", field.ErrorList{vErr}) status := err.(*StatusError).ErrStatus if status.Code != 422 || status.Reason != unversioned.StatusReasonInvalid { t.Errorf("%d: unexpected status: %#v", i, status) } if !reflect.DeepEqual(expected, status.Details) { t.Errorf("%d: expected %#v, got %#v", i, expected, status.Details) } } }
func ValidateHorizontalPodAutoscalerStatusUpdate(controller, oldController *extensions.HorizontalPodAutoscaler) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) status := controller.Status allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.CurrentReplicas), field.NewPath("status", "currentReplicas"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(status.DesiredReplicas), field.NewPath("status", "desiredReplicasa"))...) return allErrs }
func ValidateHorizontalPodAutoscaler(autoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList { allErrs := apivalidation.ValidateObjectMeta(&autoscaler.ObjectMeta, true, ValidateHorizontalPodAutoscalerName, field.NewPath("metadata")) allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(autoscaler.Spec, field.NewPath("spec"))...) return allErrs }
// ValidateReplicaSetUpdate tests if required fields in the ReplicaSet are set. func ValidateReplicaSetUpdate(rs, oldRs *extensions.ReplicaSet) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&rs.ObjectMeta, &oldRs.ObjectMeta, field.NewPath("metadata"))...) allErrs = append(allErrs, ValidateReplicaSetSpec(&rs.Spec, field.NewPath("spec"))...) return allErrs }
func ValidateDeployment(obj *extensions.Deployment) field.ErrorList { allErrs := apivalidation.ValidateObjectMeta(&obj.ObjectMeta, true, ValidateDeploymentName, field.NewPath("metadata")) allErrs = append(allErrs, ValidateDeploymentSpec(&obj.Spec, field.NewPath("spec"))...) return allErrs }
func ValidateDeploymentUpdate(update, old *extensions.Deployment) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, ValidateDeploymentSpec(&update.Spec, field.NewPath("spec"))...) return allErrs }
// ValidateDaemonSetStatus validates tests if required fields in the DaemonSet Status section func ValidateDaemonSetStatusUpdate(controller, oldController *extensions.DaemonSet) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, validateDaemonSetStatus(&controller.Status, field.NewPath("status"))...) return allErrs }
// ValidateDaemonSetUpdate tests if required fields in the DaemonSet are set. func ValidateDaemonSetUpdate(controller, oldController *extensions.DaemonSet) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&controller.ObjectMeta, &oldController.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, field.NewPath("spec"))...) allErrs = append(allErrs, ValidateDaemonSetTemplateUpdate(controller.Spec.Template, oldController.Spec.Template, field.NewPath("spec", "template"))...) return allErrs }
// ValidateDaemonSet tests if required fields in the DaemonSet are set. func ValidateDaemonSet(controller *extensions.DaemonSet) field.ErrorList { allErrs := apivalidation.ValidateObjectMeta(&controller.ObjectMeta, true, ValidateDaemonSetName, field.NewPath("metadata")) allErrs = append(allErrs, ValidateDaemonSetSpec(&controller.Spec, field.NewPath("spec"))...) return allErrs }
// ValidateReplicaSetStatusUpdate tests if required fields in the ReplicaSet are set. func ValidateReplicaSetStatusUpdate(rs, oldRs *extensions.ReplicaSet) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&rs.ObjectMeta, &oldRs.ObjectMeta, field.NewPath("metadata"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(rs.Status.Replicas), field.NewPath("status", "replicas"))...) allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(rs.Status.ObservedGeneration), field.NewPath("status", "observedGeneration"))...) return allErrs }
func ValidateJob(job *extensions.Job) field.ErrorList { // Jobs and rcs have the same name validation allErrs := apivalidation.ValidateObjectMeta(&job.ObjectMeta, true, apivalidation.ValidateReplicationControllerName, field.NewPath("metadata")) allErrs = append(allErrs, ValidateJobSpec(&job.Spec, field.NewPath("spec"))...) return allErrs }
func ValidateHorizontalPodAutoscalerUpdate(newAutoscaler, oldAutoscaler *extensions.HorizontalPodAutoscaler) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&newAutoscaler.ObjectMeta, &oldAutoscaler.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, validateHorizontalPodAutoscalerSpec(newAutoscaler.Spec, field.NewPath("spec"))...) return allErrs }
func ValidateJobUpdateStatus(job, oldJob *extensions.Job) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&oldJob.ObjectMeta, &job.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, ValidateJobStatusUpdate(job.Status, oldJob.Status)...) return allErrs }
// TODO: add other common fields that require global validation. func validateCommonFields(obj, old runtime.Object) (field.ErrorList, error) { allErrs := field.ErrorList{} objectMeta, err := api.ObjectMetaFor(obj) if err != nil { return nil, fmt.Errorf("failed to get new object metadata: %v", err) } oldObjectMeta, err := api.ObjectMetaFor(old) if err != nil { return nil, fmt.Errorf("failed to get old object metadata: %v", err) } allErrs = append(allErrs, validation.ValidateObjectMetaUpdate(objectMeta, oldObjectMeta, field.NewPath("metadata"))...) return allErrs, nil }
func ValidateJobStatusUpdate(status, oldStatus extensions.JobStatus) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, ValidateJobStatus(&status, field.NewPath("status"))...) return allErrs }
// BeforeCreate ensures that common operations for all resources are performed on creation. It only returns // errors that can be converted to api.Status. It invokes PrepareForCreate, then GenerateName, then Validate. // It returns nil if the object should be created. func BeforeCreate(strategy RESTCreateStrategy, ctx api.Context, obj runtime.Object) error { objectMeta, kind, kerr := objectMetaAndKind(strategy, obj) if kerr != nil { return kerr } if strategy.NamespaceScoped() { if !api.ValidNamespace(ctx, objectMeta) { return errors.NewBadRequest("the namespace of the provided object does not match the namespace sent on the request") } } else { objectMeta.Namespace = api.NamespaceNone } objectMeta.DeletionTimestamp = nil objectMeta.DeletionGracePeriodSeconds = nil strategy.PrepareForCreate(obj) api.FillObjectMetaSystemFields(ctx, objectMeta) api.GenerateName(strategy, objectMeta) if errs := strategy.Validate(ctx, obj); len(errs) > 0 { return errors.NewInvalid(kind.GroupKind(), objectMeta.Name, errs) } // Custom validation (including name validation) passed // Now run common validation on object meta // Do this *after* custom validation so that specific error messages are shown whenever possible if errs := validation.ValidateObjectMeta(objectMeta, strategy.NamespaceScoped(), validation.ValidatePathSegmentName, field.NewPath("metadata")); len(errs) > 0 { return errors.NewInvalid(kind.GroupKind(), objectMeta.Name, errs) } strategy.Canonicalize(obj) return nil }
// ValidateIngressUpdate tests if required fields in the Ingress are set. func ValidateIngressUpdate(ingress, oldIngress *extensions.Ingress) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&ingress.ObjectMeta, &oldIngress.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, ValidateIngressSpec(&ingress.Spec, field.NewPath("spec"))...) return allErrs }
func ValidateLocalSubjectAccessReview(sar *authorizationapi.LocalSubjectAccessReview) field.ErrorList { allErrs := ValidateSubjectAccessReviewSpec(sar.Spec, field.NewPath("spec")) return allErrs }
func TestCompatibility_v1_PodSecurityContext(t *testing.T) { cases := []struct { name string input string expectedKeys map[string]string absentKeys []string }{ { name: "hostNetwork = true", input: ` { "kind":"Pod", "apiVersion":"v1", "metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"}, "spec": { "hostNetwork": true, "containers":[{ "name":"a", "image":"my-container-image" }] } } `, expectedKeys: map[string]string{ "spec.hostNetwork": "true", }, }, { name: "hostNetwork = false", input: ` { "kind":"Pod", "apiVersion":"v1", "metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"}, "spec": { "hostNetwork": false, "containers":[{ "name":"a", "image":"my-container-image" }] } } `, absentKeys: []string{ "spec.hostNetwork", }, }, { name: "hostIPC = true", input: ` { "kind":"Pod", "apiVersion":"v1", "metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"}, "spec": { "hostIPC": true, "containers":[{ "name":"a", "image":"my-container-image" }] } } `, expectedKeys: map[string]string{ "spec.hostIPC": "true", }, }, { name: "hostIPC = false", input: ` { "kind":"Pod", "apiVersion":"v1", "metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"}, "spec": { "hostIPC": false, "containers":[{ "name":"a", "image":"my-container-image" }] } } `, absentKeys: []string{ "spec.hostIPC", }, }, { name: "hostPID = true", input: ` { "kind":"Pod", "apiVersion":"v1", "metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"}, "spec": { "hostPID": true, "containers":[{ "name":"a", "image":"my-container-image" }] } } `, expectedKeys: map[string]string{ "spec.hostPID": "true", }, }, { name: "hostPID = false", input: ` { "kind":"Pod", "apiVersion":"v1", "metadata":{"name":"my-pod-name", "namespace":"my-pod-namespace"}, "spec": { "hostPID": false, "containers":[{ "name":"a", "image":"my-container-image" }] } } `, absentKeys: []string{ "spec.hostPID", }, }, { name: "reseting defaults for pre-v1.1 mirror pods", input: ` { "kind":"Pod", "apiVersion":"v1", "metadata":{ "name":"my-pod-name", "namespace":"my-pod-namespace", "annotations": { "kubernetes.io/config.mirror": "mirror" } }, "spec": { "containers":[{ "name":"a", "image":"my-container-image", "resources": { "limits": { "cpu": "100m" } } }] } } `, absentKeys: []string{ "spec.terminationGracePeriodSeconds", "spec.containers[0].resources.requests", }, }, { name: "preserving defaults for v1.1+ mirror pods", input: ` { "kind":"Pod", "apiVersion":"v1", "metadata":{ "name":"my-pod-name", "namespace":"my-pod-namespace", "annotations": { "kubernetes.io/config.mirror": "cbe924f710c7e26f7693d6a341bcfad0" } }, "spec": { "containers":[{ "name":"a", "image":"my-container-image", "resources": { "limits": { "cpu": "100m" } } }] } } `, expectedKeys: map[string]string{ "spec.terminationGracePeriodSeconds": "30", "spec.containers[0].resources.requests": "map[cpu:100m]", }, }, } validator := func(obj runtime.Object) field.ErrorList { return validation.ValidatePodSpec(&(obj.(*api.Pod).Spec), field.NewPath("spec")) } for _, tc := range cases { t.Logf("Testing 1.0.0 backward compatibility for %v", tc.name) compat.TestCompatibility(t, v1.SchemeGroupVersion, []byte(tc.input), validator, tc.expectedKeys, tc.absentKeys) } }