// ValidatePetSetSpec tests if required fields in the PetSet spec are set. func ValidatePetSetSpec(spec *apps.PetSetSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...) if spec.Selector == nil { allErrs = append(allErrs, field.Required(fldPath.Child("selector"), "")) } else { allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(spec.Selector, fldPath.Child("selector"))...) if len(spec.Selector.MatchLabels)+len(spec.Selector.MatchExpressions) == 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "empty selector is not valid for petset.")) } } selector, err := unversioned.LabelSelectorAsSelector(spec.Selector) if err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("selector"), spec.Selector, "")) } else { allErrs = append(allErrs, ValidatePodTemplateSpecForPetSet(&spec.Template, selector, fldPath.Child("template"))...) } if spec.Template.Spec.RestartPolicy != api.RestartPolicyAlways { allErrs = append(allErrs, field.NotSupported(fldPath.Child("template", "spec", "restartPolicy"), spec.Template.Spec.RestartPolicy, []string{string(api.RestartPolicyAlways)})) } return allErrs }
func ValidateCrossVersionObjectReference(ref autoscaling.CrossVersionObjectReference, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if len(ref.Kind) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("kind"), "")) } else { for _, msg := range apivalidation.IsValidPathSegmentName(ref.Kind) { allErrs = append(allErrs, field.Invalid(fldPath.Child("kind"), ref.Kind, msg)) } } if len(ref.Name) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) } else { for _, msg := range apivalidation.IsValidPathSegmentName(ref.Name) { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), ref.Name, msg)) } } return allErrs }
func validateHorizontalPodAutoscalerAnnotations(annotations map[string]string, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if annotationValue, found := annotations[podautoscaler.HpaCustomMetricsTargetAnnotationName]; found { // Try to parse the annotation var targetList extensions.CustomMetricTargetList if err := json.Unmarshal([]byte(annotationValue), &targetList); err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations"), annotations, "failed to parse custom metrics target annotation")) } else { if len(targetList.Items) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("annotations", "items"), "custom metrics target must not be empty")) } for _, target := range targetList.Items { if target.Name == "" { allErrs = append(allErrs, field.Required(fldPath.Child("annotations", "items", "name"), "missing custom metric target name")) } if target.TargetValue.MilliValue() <= 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("annotations", "items", "value"), target.TargetValue, "custom metric target value must be greater than 0")) } } } } return allErrs }
// Validates the given template and ensures that it is in accordance with the desired selector. func ValidatePodTemplateSpecForPetSet(template *api.PodTemplateSpec, selector labels.Selector, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if template == nil { allErrs = append(allErrs, field.Required(fldPath, "")) } else { if !selector.Empty() { // Verify that the PetSet selector matches the labels in template. labels := labels.Set(template.Labels) if !selector.Matches(labels) { allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata", "labels"), template.Labels, "`selector` does not match template `labels`")) } } // TODO: Add validation for PodSpec, currently this will check volumes, which we know will // fail. We should really check that the union of the given volumes and volumeClaims match // volume mounts in the containers. // allErrs = append(allErrs, apivalidation.ValidatePodTemplateSpec(template, fldPath)...) allErrs = append(allErrs, unversionedvalidation.ValidateLabels(template.Labels, fldPath.Child("labels"))...) allErrs = append(allErrs, apivalidation.ValidateAnnotations(template.Annotations, fldPath.Child("annotations"))...) allErrs = append(allErrs, apivalidation.ValidatePodSpecificAnnotations(template.Annotations, fldPath.Child("annotations"))...) } 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.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) } } }