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 }
// ValidateStorageClassUpdate tests if an update to StorageClass is valid. func ValidateStorageClassUpdate(storageClass, oldStorageClass *storage.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 }
// 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 }
// 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 }
func ValidateNoNewFinalizers(newFinalizers []string, oldFinalizers []string, fldPath *field.Path) field.ErrorList { const newFinalizersErrorMsg string = `no new finalizers can be added if the object is being deleted` allErrs := field.ErrorList{} extra := sets.NewString(newFinalizers...).Difference(sets.NewString(oldFinalizers...)) if len(extra) != 0 { allErrs = append(allErrs, field.Forbidden(fldPath, fmt.Sprintf("no new finalizers can be added if the object is being deleted, found new finalizers %#v", extra.List()))) } 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))} }
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.")) } allErrs = append(allErrs, ValidatePodDisruptionBudgetStatus(pdb.Status, field.NewPath("status"))...) pdb.Generation = restoreGeneration return allErrs }
func ValidateLabelSelectorRequirement(sr metav1.LabelSelectorRequirement, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} switch sr.Operator { case metav1.LabelSelectorOpIn, metav1.LabelSelectorOpNotIn: if len(sr.Values) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("values"), "must be specified when `operator` is 'In' or 'NotIn'")) } case metav1.LabelSelectorOpExists, metav1.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, ValidateLabelName(sr.Key, fldPath.Child("key"))...) return allErrs }
// ValidateObjectMeta validates an object's metadata on creation. It expects that name generation has already // been performed. // It doesn't return an error for rootscoped resources with namespace, because namespace should already be cleared before. func ValidateObjectMeta(meta *metav1.ObjectMeta, requiresNamespace bool, nameFn apimachineyvalidation.ValidateNameFunc, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if len(meta.GenerateName) != 0 { for _, msg := range nameFn(meta.GenerateName, true) { allErrs = append(allErrs, field.Invalid(fldPath.Child("generateName"), meta.GenerateName, msg)) } } // If the generated name validates, but the calculated value does not, it's a problem with generation, and we // report it here. This may confuse users, but indicates a programming bug and still must be validated. // If there are multiple fields out of which one is required then add an or as a separator if len(meta.Name) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("name"), "name or generateName is required")) } else { for _, msg := range nameFn(meta.Name, false) { allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), meta.Name, msg)) } } if requiresNamespace { if len(meta.Namespace) == 0 { allErrs = append(allErrs, field.Required(fldPath.Child("namespace"), "")) } else { for _, msg := range apimachineyvalidation.ValidateNamespaceName(meta.Namespace, false) { allErrs = append(allErrs, field.Invalid(fldPath.Child("namespace"), meta.Namespace, msg)) } } } else { if len(meta.Namespace) != 0 { allErrs = append(allErrs, field.Forbidden(fldPath.Child("namespace"), "not allowed on this type")) } } if len(meta.ClusterName) != 0 { for _, msg := range ValidateClusterName(meta.ClusterName, false) { allErrs = append(allErrs, field.Invalid(fldPath.Child("clusterName"), meta.ClusterName, msg)) } } allErrs = append(allErrs, apimachineyvalidation.ValidateNonnegativeField(meta.Generation, fldPath.Child("generation"))...) allErrs = append(allErrs, v1validation.ValidateLabels(meta.Labels, fldPath.Child("labels"))...) allErrs = append(allErrs, ValidateAnnotations(meta.Annotations, fldPath.Child("annotations"))...) allErrs = append(allErrs, ValidateOwnerReferences(meta.OwnerReferences, fldPath.Child("ownerReferences"))...) for _, finalizer := range meta.Finalizers { allErrs = append(allErrs, ValidateFinalizerName(finalizer, fldPath.Child("finalizers"))...) } return allErrs }
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 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 }
// ValidateStatefulSetUpdate tests if required fields in the StatefulSet are set. func ValidateStatefulSetUpdate(statefulSet, oldStatefulSet *apps.StatefulSet) field.ErrorList { allErrs := apivalidation.ValidateObjectMetaUpdate(&statefulSet.ObjectMeta, &oldStatefulSet.ObjectMeta, field.NewPath("metadata")) // TODO: For now we're taking the safe route and disallowing all updates to // spec except for Replicas, for scaling, and Template.Spec.containers.image // for rolling-update. Enable others on a case by case basis. restoreReplicas := statefulSet.Spec.Replicas statefulSet.Spec.Replicas = oldStatefulSet.Spec.Replicas restoreContainers := statefulSet.Spec.Template.Spec.Containers statefulSet.Spec.Template.Spec.Containers = oldStatefulSet.Spec.Template.Spec.Containers if !reflect.DeepEqual(statefulSet.Spec, oldStatefulSet.Spec) { allErrs = append(allErrs, field.Forbidden(field.NewPath("spec"), "updates to statefulset spec for fields other than 'replicas' and 'containers' are forbidden.")) } statefulSet.Spec.Replicas = restoreReplicas statefulSet.Spec.Template.Spec.Containers = restoreContainers allErrs = append(allErrs, apivalidation.ValidateNonnegativeField(int64(statefulSet.Spec.Replicas), field.NewPath("spec", "replicas"))...) containerErrs, _ := apivalidation.ValidateContainerUpdates(statefulSet.Spec.Template.Spec.Containers, oldStatefulSet.Spec.Template.Spec.Containers, field.NewPath("spec").Child("template").Child("containers")) allErrs = append(allErrs, containerErrs...) return allErrs }