func (s *strategy) Validate(pod *api.Pod, container *api.Container) field.ErrorList { if s.allowedProfiles == nil { // Unrestricted: allow all. return nil } allErrs := field.ErrorList{} fieldPath := field.NewPath("pod", "metadata", "annotations").Key(apparmor.ContainerAnnotationKeyPrefix + container.Name) profile := apparmor.GetProfileNameFromPodAnnotations(pod.Annotations, container.Name) if profile == "" { if len(s.allowedProfiles) > 0 { allErrs = append(allErrs, field.Forbidden(fieldPath, "AppArmor profile must be set")) return allErrs } return nil } if !s.allowedProfiles[profile] { msg := fmt.Sprintf("%s is not an allowed profile. Allowed values: %q", profile, s.allowedProfilesString) allErrs = append(allErrs, field.Forbidden(fieldPath, msg)) } return allErrs }
// Admit determines if the service should be admitted based on the configured network CIDR. func (r *externalIPRanger) Admit(a kadmission.Attributes) error { if a.GetResource() != kapi.Resource("services") { return nil } svc, ok := a.GetObject().(*kapi.Service) // if we can't convert then we don't handle this object so just return if !ok { return nil } var errs field.ErrorList switch { // administrator disabled externalIPs case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) == 0: errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs"), "externalIPs have been disabled")) // administrator has limited the range case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) > 0: for i, s := range svc.Spec.ExternalIPs { ip := net.ParseIP(s) if ip == nil { errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIPs must be a valid address")) continue } if networkSlice(r.reject).Contains(ip) || !networkSlice(r.admit).Contains(ip) { errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIP is not allowed")) continue } } } if len(errs) > 0 { return apierrs.NewInvalid(a.GetKind(), a.GetName(), errs) } return nil }
func validateRoleBindingSubject(subject kapi.ObjectReference, isNamespaced bool, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if len(subject.Name) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) } if len(subject.UID) != 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("uid"), fmt.Sprintf("%v", subject.UID))) } if len(subject.APIVersion) != 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("apiVersion"), subject.APIVersion)) } if len(subject.ResourceVersion) != 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("resourceVersion"), subject.ResourceVersion)) } if len(subject.FieldPath) != 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("fieldPath"), subject.FieldPath)) } switch subject.Kind { case authorizationapi.ServiceAccountKind: if reasons := validation.ValidateServiceAccountName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", "))) } if !isNamespaced && len(subject.Namespace) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), "Service account subjects for ClusterRoleBindings must have a namespace")) } case authorizationapi.UserKind: if reasons := uservalidation.ValidateUserName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", "))) } case authorizationapi.GroupKind: if reasons := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && len(reasons) != 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, strings.Join(reasons, ", "))) } case authorizationapi.SystemUserKind: isValidSAName := len(validation.ValidateServiceAccountName(subject.Name, false)) == 0 isValidUserName := len(uservalidation.ValidateUserName(subject.Name, false)) == 0 if isValidSAName || isValidUserName { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, "conforms to User.name or ServiceAccount.name restrictions")) } case authorizationapi.SystemGroupKind: if reasons := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && len(reasons) == 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), subject.Name, "conforms to Group.name restrictions")) } default: allErrs = append(allErrs, field.NotSupported(fldPath.Child("kind"), subject.Kind, []string{authorizationapi.ServiceAccountKind, authorizationapi.UserKind, authorizationapi.GroupKind, authorizationapi.SystemGroupKind, authorizationapi.SystemUserKind})) } return allErrs }
// Admit determines if the service should be admitted based on the configured network CIDR. func (r *externalIPRanger) Admit(a kadmission.Attributes) error { if a.GetResource().GroupResource() != kapi.Resource("services") { return nil } svc, ok := a.GetObject().(*kapi.Service) // if we can't convert then we don't handle this object so just return if !ok { return nil } // Determine if an ingress ip address should be allowed as an // external ip by checking the loadbalancer status of the previous // object state. Only updates need to be validated against the // ingress ip since the loadbalancer status cannot be set on // create. ingressIP := "" retrieveIngressIP := a.GetOperation() == kadmission.Update && r.allowIngressIP && svc.Spec.Type == kapi.ServiceTypeLoadBalancer if retrieveIngressIP { old, ok := a.GetOldObject().(*kapi.Service) ipPresent := ok && old != nil && len(old.Status.LoadBalancer.Ingress) > 0 if ipPresent { ingressIP = old.Status.LoadBalancer.Ingress[0].IP } } var errs field.ErrorList switch { // administrator disabled externalIPs case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) == 0: onlyIngressIP := len(svc.Spec.ExternalIPs) == 1 && svc.Spec.ExternalIPs[0] == ingressIP if !onlyIngressIP { errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs"), "externalIPs have been disabled")) } // administrator has limited the range case len(svc.Spec.ExternalIPs) > 0 && len(r.admit) > 0: for i, s := range svc.Spec.ExternalIPs { ip := net.ParseIP(s) if ip == nil { errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIPs must be a valid address")) continue } notIngressIP := s != ingressIP if (NetworkSlice(r.reject).Contains(ip) || !NetworkSlice(r.admit).Contains(ip)) && notIngressIP { errs = append(errs, field.Forbidden(field.NewPath("spec", "externalIPs").Index(i), "externalIP is not allowed")) continue } } } if len(errs) > 0 { return apierrs.NewInvalid(a.GetKind().GroupKind(), a.GetName(), errs) } return nil }
func validateImageSignature(signature *api.ImageSignature, fldPath *field.Path) field.ErrorList { allErrs := validation.ValidateObjectMeta(&signature.ObjectMeta, false, oapi.MinimalNameRequirements, fldPath.Child("metadata")) if len(signature.Labels) > 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("metadata").Child("labels"), "signature labels cannot be set")) } if len(signature.Annotations) > 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("metadata").Child("annotations"), "signature annotations cannot be set")) } if _, _, err := api.SplitImageSignatureName(signature.Name); err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("metadata").Child("name"), signature.Name, "name must be of format <imageName>@<signatureName>")) } if len(signature.Type) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("type"), "")) } if len(signature.Content) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("content"), "")) } var trustedCondition, forImageCondition *api.SignatureCondition for i := range signature.Conditions { cond := &signature.Conditions[i] if cond.Type == api.SignatureTrusted && (trustedCondition == nil || !cond.LastProbeTime.Before(trustedCondition.LastProbeTime)) { trustedCondition = cond } else if cond.Type == api.SignatureForImage && forImageCondition == nil || !cond.LastProbeTime.Before(forImageCondition.LastProbeTime) { forImageCondition = cond } } if trustedCondition != nil && forImageCondition == nil { msg := fmt.Sprintf("missing %q condition type", api.SignatureForImage) allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), signature.Conditions, msg)) } else if forImageCondition != nil && trustedCondition == nil { msg := fmt.Sprintf("missing %q condition type", api.SignatureTrusted) allErrs = append(allErrs, field.Invalid(fldPath.Child("conditions"), signature.Conditions, msg)) } if trustedCondition == nil || trustedCondition.Status == kapi.ConditionUnknown { if len(signature.ImageIdentity) != 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("imageIdentity"), signature.ImageIdentity, "must be unset for unknown signature state")) } if len(signature.SignedClaims) != 0 { allErrs = append(allErrs, field.Invalid(fldPath.Child("signedClaims"), signature.SignedClaims, "must be unset for unknown signature state")) } if signature.IssuedBy != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("issuedBy"), signature.IssuedBy, "must be unset for unknown signature state")) } if signature.IssuedTo != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("issuedTo"), signature.IssuedTo, "must be unset for unknown signature state")) } } return allErrs }
// ValidateStorageClassUpdate tests if an update to StorageClass is valid. func ValidateStorageClassUpdate(storageClass, oldStorageClass *extensions.StorageClass) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&storageClass.ObjectMeta, &oldStorageClass.ObjectMeta, field.NewPath("metadata")) if !reflect.DeepEqual(oldStorageClass.Parameters, storageClass.Parameters) { allErrs = append(allErrs, field.Forbidden(field.NewPath("parameters"), "updates to parameters are forbidden.")) } if strings.Compare(storageClass.Provisioner, oldStorageClass.Provisioner) != 0 { allErrs = append(allErrs, field.Forbidden(field.NewPath("provisioner"), "updates to provisioner are forbidden.")) } return allErrs }
// ValidateImageSignatureUpdate ensures that the new ImageSignature is valid. func ValidateImageSignatureUpdate(newImageSignature, oldImageSignature *api.ImageSignature) field.ErrorList { allErrs := validation.ValidateObjectMetaUpdate(&newImageSignature.ObjectMeta, &oldImageSignature.ObjectMeta, field.NewPath("metadata")) allErrs = append(allErrs, ValidateImageSignature(newImageSignature)...) if newImageSignature.Type != oldImageSignature.Type { allErrs = append(allErrs, field.Forbidden(field.NewPath("type"), "cannot change signature type")) } if !bytes.Equal(newImageSignature.Content, oldImageSignature.Content) { allErrs = append(allErrs, field.Forbidden(field.NewPath("content"), "cannot change signature content")) } return allErrs }
// ValidateNetworkPolicySpec tests if required fields in the networkpolicy spec are set. func ValidateNetworkPolicySpec(spec *extensions.NetworkPolicySpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(&spec.PodSelector, fldPath.Child("podSelector"))...) // Validate ingress rules. for _, i := range spec.Ingress { // TODO: Update From to be a pointer to slice as soon as auto-generation supports it. for _, f := range i.From { numFroms := 0 if f.PodSelector != nil { numFroms++ allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(f.PodSelector, fldPath.Child("podSelector"))...) } if f.NamespaceSelector != nil { if numFroms > 0 { allErrs = append(allErrs, field.Forbidden(fldPath, "may not specify more than 1 from type")) } else { numFroms++ allErrs = append(allErrs, unversionedvalidation.ValidateLabelSelector(f.NamespaceSelector, fldPath.Child("namespaces"))...) } } if numFroms == 0 { // At least one of PodSelector and NamespaceSelector must be defined. allErrs = append(allErrs, field.Required(fldPath, "must specify a from type")) } } } return allErrs }
// ValidateNetworkPolicyUpdate tests if an update to a NetworkPolicy is valid. func ValidateNetworkPolicyUpdate(np, oldNP *extensions.NetworkPolicy) field.ErrorList { allErrs := field.ErrorList{} if !reflect.DeepEqual(np, oldNP) { allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to networkpolicy spec are forbidden.")) } return allErrs }
func (v *WrappingValidator) ValidateUpdate(obj, old runtime.Object) field.ErrorList { if v.validateUpdate == nil { // if there is no update validation, fail. return field.ErrorList{field.Forbidden(field.NewPath("obj"), obj)} } return callValidateUpdate(reflect.ValueOf(obj), reflect.ValueOf(old), *v.validateUpdate) }
// ValidatePod ensures that the specified values on the pod fall within the range // of the strategy. func (s *strategy) ValidatePod(pod *api.Pod) field.ErrorList { allErrs := field.ErrorList{} podSpecFieldPath := field.NewPath("pod", "metadata", "annotations").Key(api.SeccompPodAnnotationKey) podProfile := pod.Annotations[api.SeccompPodAnnotationKey] if !s.allowAnyProfile && len(s.allowedProfiles) == 0 && podProfile != "" { allErrs = append(allErrs, field.Forbidden(podSpecFieldPath, "seccomp may not be set")) return allErrs } if !s.profileAllowed(podProfile) { msg := fmt.Sprintf("%s is not an allowed seccomp profile. Valid values are %v", podProfile, s.allowedProfilesString) allErrs = append(allErrs, field.Forbidden(podSpecFieldPath, msg)) } return allErrs }
// ValidateContainer ensures that the specified values on the container fall within // the range of the strategy. func (s *strategy) ValidateContainer(pod *api.Pod, container *api.Container) field.ErrorList { allErrs := field.ErrorList{} fieldPath := field.NewPath("pod", "metadata", "annotations").Key(api.SeccompContainerAnnotationKeyPrefix + container.Name) containerProfile := profileForContainer(pod, container) if !s.allowAnyProfile && len(s.allowedProfiles) == 0 && containerProfile != "" { allErrs = append(allErrs, field.Forbidden(fieldPath, "seccomp may not be set")) return allErrs } if !s.profileAllowed(containerProfile) { msg := fmt.Sprintf("%s is not an allowed seccomp profile. Valid values are %v", containerProfile, s.allowedProfilesString) allErrs = append(allErrs, field.Forbidden(fieldPath, msg)) } return allErrs }
// ValidateNetworkPolicyUpdate tests if an update to a NetworkPolicy is valid. func ValidateNetworkPolicyUpdate(update, old *extensions.NetworkPolicy) field.ErrorList { allErrs := field.ErrorList{} allErrs = append(allErrs, apivalidation.ValidateObjectMetaUpdate(&update.ObjectMeta, &old.ObjectMeta, field.NewPath("metadata"))...) if !reflect.DeepEqual(update.Spec, old.Spec) { allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to networkpolicy spec are forbidden.")) } return allErrs }
// ValidateUpdate is the default update validation for an end user. func (petSetStrategy) ValidateUpdate(ctx api.Context, obj, old runtime.Object) field.ErrorList { return field.ErrorList{field.Forbidden(field.NewPath("spec"), "updates to petset spec are forbidden.")} // TODO: For now we're taking the safe route and disallowing all updates to spec. // Enable on a case by case basis. //validationErrorList := validation.ValidatePetSet(obj.(*apps.PetSet)) //updateErrorList := validation.ValidatePetSetUpdate(obj.(*apps.PetSet), old.(*apps.PetSet)) //return append(validationErrorList, updateErrorList...) }
// ValidatePod ensures that the specified values on the pod fall within the range // of the strategy. func (s *withSeccompProfile) ValidatePod(pod *api.Pod) field.ErrorList { allErrs := field.ErrorList{} fieldPath := field.NewPath("pod", "metadata", "annotations", api.SeccompPodAnnotationKey) podProfile, _ := pod.Annotations[api.SeccompPodAnnotationKey] if len(s.allowedProfiles) == 0 && podProfile != "" { allErrs = append(allErrs, field.Forbidden(fieldPath, "seccomp may not be set")) return allErrs } if !isProfileAllowed(podProfile, s.allowedProfiles) { msg := fmt.Sprintf("%s is not a valid seccomp profile. Valid values are %v", podProfile, s.allowedProfiles) allErrs = append(allErrs, field.Forbidden(fieldPath, msg)) } return allErrs }
// Validate validates a new image stream. func (s Strategy) Validate(ctx kapi.Context, obj runtime.Object) field.ErrorList { stream := obj.(*api.ImageStream) user, ok := kapi.UserFrom(ctx) if !ok { return field.ErrorList{field.Forbidden(field.NewPath("imageStream"), stream.Name)} } errs := s.tagVerifier.Verify(nil, stream, user) errs = append(errs, s.tagsChanged(nil, stream)...) errs = append(errs, validation.ValidateImageStream(stream)...) return errs }
// ValidateContainer ensures that the specified values on the container fall within // the range of the strategy. func (s *withSeccompProfile) ValidateContainer(pod *api.Pod, container *api.Container) field.ErrorList { allErrs := field.ErrorList{} fieldPath := field.NewPath("pod", "metadata", "annotations", api.SeccompContainerAnnotationKeyPrefix+container.Name) // container inherits the pod profile if not set. TODO: when this is a field this can be removed and it should // be accounted for in DetermineEffectiveSecurityContext containerProfile := profileForContainer(pod, container) if len(s.allowedProfiles) == 0 && containerProfile != "" { allErrs = append(allErrs, field.Forbidden(fieldPath, "seccomp may not be set")) return allErrs } if !isProfileAllowed(containerProfile, s.allowedProfiles) { msg := fmt.Sprintf("%s is not a valid seccomp profile. Valid values are %v", containerProfile, s.allowedProfiles) allErrs = append(allErrs, field.Forbidden(fieldPath, msg)) } return allErrs }
func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if strategy.RollingUpdate == nil { return allErrs } switch strategy.Type { case extensions.RecreateDeploymentStrategyType: allErrs = append(allErrs, field.Forbidden(fldPath.Child("rollingUpdate"), "may not be specified when strategy `type` is '"+string(extensions.RecreateDeploymentStrategyType+"'"))) case extensions.RollingUpdateDeploymentStrategyType: allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...) } return allErrs }
// ValidateDaemonSetTemplateUpdate tests that certain fields in the daemon set's pod template are not updated. func ValidateDaemonSetTemplateUpdate(podTemplate, oldPodTemplate *api.PodTemplateSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} podSpec := podTemplate.Spec // podTemplate.Spec is not a pointer, so we can modify NodeSelector and NodeName directly. podSpec.NodeSelector = oldPodTemplate.Spec.NodeSelector podSpec.NodeName = oldPodTemplate.Spec.NodeName // In particular, we do not allow updates to container images at this point. if !api.Semantic.DeepEqual(oldPodTemplate.Spec, podSpec) { // TODO: Pinpoint the specific field that causes the invalid error after we have strategic merge diff allErrs = append(allErrs, field.Forbidden(fldPath.Child("spec"), "daemonSet updates may not change fields other than `nodeSelector`")) } return allErrs }
func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if strategy.RollingUpdate == nil { return allErrs } switch strategy.Type { case extensions.RecreateDeploymentStrategyType: allErrs = append(allErrs, field.Forbidden(fldPath.Child("rollingUpdate"), "should be nil when strategy type is "+extensions.RecreateDeploymentStrategyType)) case extensions.RollingUpdateDeploymentStrategyType: allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...) } return allErrs }
func ValidatePodDisruptionBudgetUpdate(pdb, oldPdb *policy.PodDisruptionBudget) field.ErrorList { allErrs := field.ErrorList{} restoreGeneration := pdb.Generation pdb.Generation = oldPdb.Generation if !reflect.DeepEqual(pdb, oldPdb) { allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to poddisruptionbudget spec are forbidden.")) } pdb.Generation = restoreGeneration return allErrs }
func (s *mustMatchPatterns) ValidateSysctl(sysctlName string, fldPath *field.Path) field.ErrorList { for _, s := range s.patterns { if s[len(s)-1] == '*' { prefix := s[:len(s)-1] if strings.HasPrefix(sysctlName, string(prefix)) { return nil } } else if sysctlName == s { return nil } } return field.ErrorList{field.Forbidden(fldPath, fmt.Sprintf("sysctl %q is not allowed", sysctlName))} }
// ValidateUpdate is the default update validation for an end user. func (s Strategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) field.ErrorList { stream := obj.(*api.ImageStream) user, ok := kapi.UserFrom(ctx) if !ok { return field.ErrorList{field.Forbidden(field.NewPath("imageStream"), stream.Name)} } oldStream := old.(*api.ImageStream) errs := s.tagVerifier.Verify(oldStream, stream, user) errs = append(errs, s.tagsChanged(oldStream, stream)...) ns, ok := kapi.NamespaceFrom(ctx) if !ok { ns = stream.Namespace } if err := s.limitVerifier.VerifyLimits(ns, stream); err != nil { errs = append(errs, field.Forbidden(field.NewPath("imageStream"), err.Error())) } errs = append(errs, validation.ValidateImageStreamUpdate(stream, oldStream)...) return errs }
func (v *TagVerifier) Verify(old, stream *api.ImageStream, user user.Info) field.ErrorList { var errors field.ErrorList oldTags := map[string]api.TagReference{} if old != nil && old.Spec.Tags != nil { oldTags = old.Spec.Tags } for tag, tagRef := range stream.Spec.Tags { if tagRef.From == nil { continue } if len(tagRef.From.Namespace) == 0 { continue } if stream.Namespace == tagRef.From.Namespace { continue } if oldRef, ok := oldTags[tag]; ok && !tagRefChanged(oldRef, tagRef, stream.Namespace) { continue } streamName, _, err := parseFromReference(stream, tagRef.From) fromPath := field.NewPath("spec", "tags").Key(tag).Child("from") if err != nil { errors = append(errors, field.Invalid(fromPath.Child("name"), tagRef.From.Name, "must be of the form <tag>, <repo>:<tag>, <id>, or <repo>@<id>")) continue } subjectAccessReview := authorizationapi.SubjectAccessReview{ Action: authorizationapi.AuthorizationAttributes{ Verb: "get", Group: api.GroupName, Resource: "imagestreams", ResourceName: streamName, }, User: user.GetName(), Groups: sets.NewString(user.GetGroups()...), } ctx := kapi.WithNamespace(kapi.NewContext(), tagRef.From.Namespace) glog.V(4).Infof("Performing SubjectAccessReview for user=%s, groups=%v to %s/%s", user.GetName(), user.GetGroups(), tagRef.From.Namespace, streamName) resp, err := v.subjectAccessReviewClient.CreateSubjectAccessReview(ctx, &subjectAccessReview) if err != nil || resp == nil || (resp != nil && !resp.Allowed) { errors = append(errors, field.Forbidden(fromPath, fmt.Sprintf("%s/%s", tagRef.From.Namespace, streamName))) continue } } return errors }
func ValidateLabelSelectorRequirement(sr extensions.LabelSelectorRequirement, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} switch sr.Operator { case extensions.LabelSelectorOpIn, extensions.LabelSelectorOpNotIn: if len(sr.Values) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified when `operator` is 'In' or 'NotIn'")) } case extensions.LabelSelectorOpExists, extensions.LabelSelectorOpDoesNotExist: if len(sr.Values) > 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("values"), "may not be specified when `operator` is 'Exists' or 'DoesNotExist'")) } default: allErrs = append(allErrs, field.Invalid(fldPath.Child("operator"), sr.Operator, "not a valid selector operator")) } allErrs = append(allErrs, apivalidation.ValidateLabelName(sr.Key, fldPath.Child("key"))...) return allErrs }
func (s StatusStrategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) field.ErrorList { newIS := obj.(*api.ImageStream) errs := field.ErrorList{} ns, ok := kapi.NamespaceFrom(ctx) if !ok { ns = newIS.Namespace } err := s.limitVerifier.VerifyLimits(ns, newIS) if err != nil { errs = append(errs, field.Forbidden(field.NewPath("imageStream"), err.Error())) } // TODO: merge valid fields after update errs = append(errs, validation.ValidateImageStreamStatusUpdate(newIS, old.(*api.ImageStream))...) return errs }
func ValidatePodLogOptions(opts *v1.PodLogOptions) field.ErrorList { allErrs := field.ErrorList{} if opts.TailLines != nil && *opts.TailLines < 0 { allErrs = append(allErrs, field.Invalid(field.NewPath("tailLines"), *opts.TailLines, isNegativeErrorMsg)) } if opts.LimitBytes != nil && *opts.LimitBytes < 1 { allErrs = append(allErrs, field.Invalid(field.NewPath("limitBytes"), *opts.LimitBytes, "must be greater than 0")) } switch { case opts.SinceSeconds != nil && opts.SinceTime != nil: allErrs = append(allErrs, field.Forbidden(field.NewPath(""), "at most one of `sinceTime` or `sinceSeconds` may be specified")) case opts.SinceSeconds != nil: if *opts.SinceSeconds < 1 { allErrs = append(allErrs, field.Invalid(field.NewPath("sinceSeconds"), *opts.SinceSeconds, "must be greater than 0")) } } return allErrs }
func Validate(config *api.ClusterResourceOverrideConfig) field.ErrorList { allErrs := field.ErrorList{} if config == nil { return allErrs } if config.LimitCPUToMemoryPercent == 0 && config.CPURequestToLimitPercent == 0 && config.MemoryRequestToLimitPercent == 0 { allErrs = append(allErrs, field.Forbidden(field.NewPath(api.PluginName), "plugin enabled but no percentages were specified")) } if config.LimitCPUToMemoryPercent < 0 { allErrs = append(allErrs, field.Invalid(field.NewPath(api.PluginName, "LimitCPUToMemoryPercent"), config.LimitCPUToMemoryPercent, "must be positive")) } if config.CPURequestToLimitPercent < 0 || config.CPURequestToLimitPercent > 100 { allErrs = append(allErrs, field.Invalid(field.NewPath(api.PluginName, "CPURequestToLimitPercent"), config.CPURequestToLimitPercent, "must be between 0 and 100")) } if config.MemoryRequestToLimitPercent < 0 || config.MemoryRequestToLimitPercent > 100 { allErrs = append(allErrs, field.Invalid(field.NewPath(api.PluginName, "MemoryRequestToLimitPercent"), config.MemoryRequestToLimitPercent, "must be between 0 and 100")) } return allErrs }
func ValidateDeploymentStrategy(strategy *extensions.DeploymentStrategy, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} switch strategy.Type { case extensions.RecreateDeploymentStrategyType: if strategy.RollingUpdate != nil { allErrs = append(allErrs, field.Forbidden(fldPath.Child("rollingUpdate"), "may not be specified when strategy `type` is '"+string(extensions.RecreateDeploymentStrategyType+"'"))) } case extensions.RollingUpdateDeploymentStrategyType: // This should never happen since it's set and checked in defaults.go if strategy.RollingUpdate == nil { allErrs = append(allErrs, field.Required(fldPath.Child("rollingUpdate"), "this should be defaulted and never be nil")) } else { allErrs = append(allErrs, ValidateRollingUpdateDeployment(strategy.RollingUpdate, fldPath.Child("rollingUpdate"))...) } default: validValues := []string{string(extensions.RecreateDeploymentStrategyType), string(extensions.RollingUpdateDeploymentStrategyType)} allErrs = append(allErrs, field.NotSupported(fldPath, strategy, validValues)) } return allErrs }
// ValidatePetSetUpdate tests if required fields in the PetSet are set. func ValidatePetSetUpdate(petSet, oldPetSet *apps.PetSet) field.ErrorList { allErrs := field.ErrorList{} // TODO: For now we're taking the safe route and disallowing all updates to spec except for Spec.Replicas. // Enable on a case by case basis. restoreReplicas := petSet.Spec.Replicas petSet.Spec.Replicas = oldPetSet.Spec.Replicas // The generation changes for this update restoreGeneration := petSet.Generation petSet.Generation = oldPetSet.Generation if !reflect.DeepEqual(petSet, oldPetSet) { allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to petset spec for fields other than 'replicas' are forbidden.")) } petSet.Spec.Replicas = restoreReplicas petSet.Generation = restoreGeneration allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(petSet.Spec.Replicas), field.NewPath("spec", "replicas"))...) return allErrs }