// hasHostPort checks the port definitions on the container for HostPort > 0. func (s *simpleProvider) hasInvalidHostPort(container *api.Container, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} for _, cp := range container.Ports { if cp.HostPort > 0 && !s.isValidHostPort(int(cp.HostPort)) { detail := fmt.Sprintf("Host port %d is not allowed to be used. Allowed ports: %v", cp.HostPort, s.psp.Spec.HostPorts) allErrs = append(allErrs, field.Invalid(fldPath.Child("hostPort"), cp.HostPort, detail)) } } return allErrs }
func ValidateSelfSubjectAccessReviewSpec(spec authorizationapi.SelfSubjectAccessReviewSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if spec.ResourceAttributes != nil && spec.NonResourceAttributes != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("nonResourceAttributes"), spec.NonResourceAttributes, `cannot be specified in combination with resourceAttributes`)) } if spec.ResourceAttributes == nil && spec.NonResourceAttributes == nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("resourceAttributes"), spec.NonResourceAttributes, `exactly one of nonResourceAttributes or resourceAttributes must be specified`)) } return allErrs }
// 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 validateHorizontalPodAutoscalerSpec(autoscaler autoscaling.HorizontalPodAutoscalerSpec, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if autoscaler.MinReplicas != nil && *autoscaler.MinReplicas < 1 { allErrs = append(allErrs, field.Invalid(fldPath.Child("minReplicas"), *autoscaler.MinReplicas, "must be greater than 0")) } if autoscaler.MaxReplicas < 1 { allErrs = append(allErrs, field.Invalid(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, "must be greater than 0")) } if autoscaler.MinReplicas != nil && autoscaler.MaxReplicas < *autoscaler.MinReplicas { allErrs = append(allErrs, field.Invalid(fldPath.Child("maxReplicas"), autoscaler.MaxReplicas, "must be greater than or equal to `minReplicas`")) } if autoscaler.TargetCPUUtilizationPercentage != nil && *autoscaler.TargetCPUUtilizationPercentage < 1 { allErrs = append(allErrs, field.Invalid(fldPath.Child("targetCPUUtilizationPercentage"), autoscaler.TargetCPUUtilizationPercentage, "must be greater than 0")) } if refErrs := ValidateCrossVersionObjectReference(autoscaler.ScaleTargetRef, fldPath.Child("scaleTargetRef")); len(refErrs) > 0 { allErrs = append(allErrs, refErrs...) } 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 }
// Ensure a pod's SecurityContext is in compliance with the given constraints. func (s *simpleProvider) ValidatePodSecurityContext(pod *api.Pod, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if pod.Spec.SecurityContext == nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("securityContext"), pod.Spec.SecurityContext, "No security context is set")) return allErrs } fsGroups := []int64{} if pod.Spec.SecurityContext.FSGroup != nil { fsGroups = append(fsGroups, *pod.Spec.SecurityContext.FSGroup) } allErrs = append(allErrs, s.strategies.FSGroupStrategy.Validate(pod, fsGroups)...) allErrs = append(allErrs, s.strategies.SupplementalGroupStrategy.Validate(pod, pod.Spec.SecurityContext.SupplementalGroups)...) // make a dummy container context to reuse the selinux strategies container := &api.Container{ Name: pod.Name, SecurityContext: &api.SecurityContext{ SELinuxOptions: pod.Spec.SecurityContext.SELinuxOptions, }, } allErrs = append(allErrs, s.strategies.SELinuxStrategy.Validate(pod, container)...) if !s.psp.Spec.HostNetwork && pod.Spec.SecurityContext.HostNetwork { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostNetwork"), pod.Spec.SecurityContext.HostNetwork, "Host network is not allowed to be used")) } if !s.psp.Spec.HostPID && pod.Spec.SecurityContext.HostPID { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostPID"), pod.Spec.SecurityContext.HostPID, "Host PID is not allowed to be used")) } if !s.psp.Spec.HostIPC && pod.Spec.SecurityContext.HostIPC { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostIPC"), pod.Spec.SecurityContext.HostIPC, "Host IPC is not allowed to be used")) } 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 }
// Ensure a container's SecurityContext is in compliance with the given constraints func (s *simpleProvider) ValidateContainerSecurityContext(pod *api.Pod, container *api.Container, fldPath *field.Path) field.ErrorList { allErrs := field.ErrorList{} if container.SecurityContext == nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("securityContext"), container.SecurityContext, "No security context is set")) return allErrs } sc := container.SecurityContext allErrs = append(allErrs, s.strategies.RunAsUserStrategy.Validate(pod, container)...) allErrs = append(allErrs, s.strategies.SELinuxStrategy.Validate(pod, container)...) if !s.psp.Spec.Privileged && *sc.Privileged { allErrs = append(allErrs, field.Invalid(fldPath.Child("privileged"), *sc.Privileged, "Privileged containers are not allowed")) } allErrs = append(allErrs, s.strategies.CapabilitiesStrategy.Validate(pod, container)...) if len(pod.Spec.Volumes) > 0 && !psputil.PSPAllowsAllVolumes(s.psp) { allowedVolumes := psputil.FSTypeToStringSet(s.psp.Spec.Volumes) for i, v := range pod.Spec.Volumes { fsType, err := psputil.GetVolumeFSType(v) if err != nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("volumes").Index(i), string(fsType), err.Error())) continue } if !allowedVolumes.Has(string(fsType)) { allErrs = append(allErrs, field.Invalid( fldPath.Child("volumes").Index(i), string(fsType), fmt.Sprintf("%s volumes are not allowed to be used", string(fsType)))) } } } if !s.psp.Spec.HostNetwork && pod.Spec.SecurityContext.HostNetwork { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostNetwork"), pod.Spec.SecurityContext.HostNetwork, "Host network is not allowed to be used")) } containersPath := fldPath.Child("containers") for idx, c := range pod.Spec.Containers { idxPath := containersPath.Index(idx) allErrs = append(allErrs, s.hasInvalidHostPort(&c, idxPath)...) } if !s.psp.Spec.HostPID && pod.Spec.SecurityContext.HostPID { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostPID"), pod.Spec.SecurityContext.HostPID, "Host PID is not allowed to be used")) } if !s.psp.Spec.HostIPC && pod.Spec.SecurityContext.HostIPC { allErrs = append(allErrs, field.Invalid(fldPath.Child("hostIPC"), pod.Spec.SecurityContext.HostIPC, "Host IPC is not allowed to be used")) } if s.psp.Spec.ReadOnlyRootFilesystem { if sc.ReadOnlyRootFilesystem == nil { allErrs = append(allErrs, field.Invalid(fldPath.Child("readOnlyRootFilesystem"), sc.ReadOnlyRootFilesystem, "ReadOnlyRootFilesystem may not be nil and must be set to true")) } else if !*sc.ReadOnlyRootFilesystem { allErrs = append(allErrs, field.Invalid(fldPath.Child("readOnlyRootFilesystem"), *sc.ReadOnlyRootFilesystem, "ReadOnlyRootFilesystem must be set to true")) } } return allErrs }