mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-10 12:32:03 +00:00
Update the validation logic to test PodTemplateSpec
This commit is contained in:
parent
a68a493e4b
commit
72bf12c86d
@ -167,7 +167,7 @@ func validateVolumeMounts(mounts []api.VolumeMount, volumes util.StringSet) errs
|
|||||||
if len(mnt.Name) == 0 {
|
if len(mnt.Name) == 0 {
|
||||||
mErrs = append(mErrs, errs.NewFieldRequired("name", mnt.Name))
|
mErrs = append(mErrs, errs.NewFieldRequired("name", mnt.Name))
|
||||||
} else if !volumes.Has(mnt.Name) {
|
} else if !volumes.Has(mnt.Name) {
|
||||||
mErrs = append(mErrs, errs.NewNotFound("name", mnt.Name))
|
mErrs = append(mErrs, errs.NewFieldNotFound("name", mnt.Name))
|
||||||
}
|
}
|
||||||
if len(mnt.MountPath) == 0 {
|
if len(mnt.MountPath) == 0 {
|
||||||
mErrs = append(mErrs, errs.NewFieldRequired("mountPath", mnt.MountPath))
|
mErrs = append(mErrs, errs.NewFieldRequired("mountPath", mnt.MountPath))
|
||||||
@ -293,6 +293,7 @@ var supportedManifestVersions = util.NewStringSet("v1beta1", "v1beta2")
|
|||||||
// This includes checking formatting and uniqueness. It also canonicalizes the
|
// This includes checking formatting and uniqueness. It also canonicalizes the
|
||||||
// structure by setting default values and implementing any backwards-compatibility
|
// structure by setting default values and implementing any backwards-compatibility
|
||||||
// tricks.
|
// tricks.
|
||||||
|
// TODO: replaced by ValidatePodSpec
|
||||||
func ValidateManifest(manifest *api.ContainerManifest) errs.ValidationErrorList {
|
func ValidateManifest(manifest *api.ContainerManifest) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
@ -348,6 +349,21 @@ func ValidatePod(pod *api.Pod) errs.ValidationErrorList {
|
|||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidatePodSpec tests that the specified PodSpec has valid data.
|
||||||
|
// This includes checking formatting and uniqueness. It also canonicalizes the
|
||||||
|
// structure by setting default values and implementing any backwards-compatibility
|
||||||
|
// tricks.
|
||||||
|
func ValidatePodSpec(spec *api.PodSpec) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
|
||||||
|
allVolumes, vErrs := validateVolumes(spec.Volumes)
|
||||||
|
allErrs = append(allErrs, vErrs.Prefix("volumes")...)
|
||||||
|
allErrs = append(allErrs, validateContainers(spec.Containers, allVolumes).Prefix("containers")...)
|
||||||
|
allErrs = append(allErrs, validateRestartPolicy(&spec.RestartPolicy).Prefix("restartPolicy")...)
|
||||||
|
allErrs = append(allErrs, validateLabels(spec.NodeSelector).Prefix("nodeSelector")...)
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
func validateLabels(labels map[string]string) errs.ValidationErrorList {
|
func validateLabels(labels map[string]string) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
for k := range labels {
|
for k := range labels {
|
||||||
@ -435,30 +451,44 @@ func ValidateReplicationController(controller *api.ReplicationController) errs.V
|
|||||||
if !util.IsDNSSubdomain(controller.Namespace) {
|
if !util.IsDNSSubdomain(controller.Namespace) {
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", controller.Namespace))
|
allErrs = append(allErrs, errs.NewFieldInvalid("namespace", controller.Namespace))
|
||||||
}
|
}
|
||||||
allErrs = append(allErrs, ValidateReplicationControllerState(&controller.DesiredState).Prefix("desiredState")...)
|
allErrs = append(allErrs, ValidateReplicationControllerSpec(&controller.Spec).Prefix("spec")...)
|
||||||
allErrs = append(allErrs, validateLabels(controller.Labels)...)
|
allErrs = append(allErrs, validateLabels(controller.Labels)...)
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
// ValidateReplicationControllerState tests if required fields in the replication controller state are set.
|
// ValidateReplicationControllerSpec tests if required fields in the replication controller spec are set.
|
||||||
func ValidateReplicationControllerState(state *api.ReplicationControllerState) errs.ValidationErrorList {
|
func ValidateReplicationControllerSpec(spec *api.ReplicationControllerSpec) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
if labels.Set(state.ReplicaSelector).AsSelector().Empty() {
|
|
||||||
allErrs = append(allErrs, errs.NewFieldRequired("replicaSelector", state.ReplicaSelector))
|
selector := labels.Set(spec.Selector).AsSelector()
|
||||||
|
if selector.Empty() {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldRequired("selector", spec.Selector))
|
||||||
}
|
}
|
||||||
selector := labels.Set(state.ReplicaSelector).AsSelector()
|
if spec.Replicas < 0 {
|
||||||
labels := labels.Set(state.PodTemplate.Labels)
|
allErrs = append(allErrs, errs.NewFieldInvalid("replicas", spec.Replicas))
|
||||||
if !selector.Matches(labels) {
|
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid("podTemplate.labels", state.PodTemplate))
|
|
||||||
}
|
}
|
||||||
allErrs = append(allErrs, validateLabels(labels)...)
|
|
||||||
if state.Replicas < 0 {
|
if spec.Template == nil {
|
||||||
allErrs = append(allErrs, errs.NewFieldInvalid("replicas", state.Replicas))
|
allErrs = append(allErrs, errs.NewFieldRequired("template", spec.Template))
|
||||||
|
} else {
|
||||||
|
labels := labels.Set(spec.Template.Labels)
|
||||||
|
if !selector.Matches(labels) {
|
||||||
|
allErrs = append(allErrs, errs.NewFieldInvalid("template.labels", spec.Template.Labels))
|
||||||
|
}
|
||||||
|
allErrs = append(allErrs, validateLabels(spec.Template.Labels).Prefix("template.labels")...)
|
||||||
|
allErrs = append(allErrs, ValidatePodTemplateSpec(spec.Template).Prefix("template")...)
|
||||||
}
|
}
|
||||||
allErrs = append(allErrs, ValidateManifest(&state.PodTemplate.DesiredState.Manifest).Prefix("podTemplate.desiredState.manifest")...)
|
|
||||||
allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(state.PodTemplate.DesiredState.Manifest.Volumes).Prefix("podTemplate.desiredState.manifest")...)
|
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ValidatePodTemplateSpec validates the spec of a pod template
|
||||||
|
func ValidatePodTemplateSpec(spec *api.PodTemplateSpec) errs.ValidationErrorList {
|
||||||
|
allErrs := errs.ValidationErrorList{}
|
||||||
|
allErrs = append(allErrs, ValidatePodSpec(&spec.Spec).Prefix("spec")...)
|
||||||
|
allErrs = append(allErrs, ValidateReadOnlyPersistentDisks(spec.Spec.Volumes).Prefix("spec.volumes")...)
|
||||||
|
return allErrs
|
||||||
|
}
|
||||||
|
|
||||||
func ValidateReadOnlyPersistentDisks(volumes []api.Volume) errs.ValidationErrorList {
|
func ValidateReadOnlyPersistentDisks(volumes []api.Volume) errs.ValidationErrorList {
|
||||||
allErrs := errs.ValidationErrorList{}
|
allErrs := errs.ValidationErrorList{}
|
||||||
for _, vol := range volumes {
|
for _, vol := range volumes {
|
||||||
|
@ -862,43 +862,41 @@ func TestValidateService(t *testing.T) {
|
|||||||
func TestValidateReplicationController(t *testing.T) {
|
func TestValidateReplicationController(t *testing.T) {
|
||||||
validSelector := map[string]string{"a": "b"}
|
validSelector := map[string]string{"a": "b"}
|
||||||
validPodTemplate := api.PodTemplate{
|
validPodTemplate := api.PodTemplate{
|
||||||
DesiredState: api.PodState{
|
Spec: api.PodTemplateSpec{
|
||||||
Manifest: api.ContainerManifest{
|
ObjectMeta: api.ObjectMeta{
|
||||||
Version: "v1beta1",
|
Labels: validSelector,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Labels: validSelector,
|
|
||||||
}
|
}
|
||||||
invalidVolumePodTemplate := api.PodTemplate{
|
invalidVolumePodTemplate := api.PodTemplate{
|
||||||
DesiredState: api.PodState{
|
Spec: api.PodTemplateSpec{
|
||||||
Manifest: api.ContainerManifest{
|
Spec: api.PodSpec{
|
||||||
Version: "v1beta1",
|
|
||||||
Volumes: []api.Volume{{Name: "gcepd", Source: &api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{"my-PD", "ext4", 1, false}}}},
|
Volumes: []api.Volume{{Name: "gcepd", Source: &api.VolumeSource{GCEPersistentDisk: &api.GCEPersistentDisk{"my-PD", "ext4", 1, false}}}},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
invalidSelector := map[string]string{"NoUppercaseOrSpecialCharsLike=Equals": "b"}
|
||||||
invalidPodTemplate := api.PodTemplate{
|
invalidPodTemplate := api.PodTemplate{
|
||||||
DesiredState: api.PodState{
|
Spec: api.PodTemplateSpec{
|
||||||
Manifest: api.ContainerManifest{
|
Spec: api.PodSpec{},
|
||||||
Version: "v1beta1",
|
ObjectMeta: api.ObjectMeta{
|
||||||
|
Labels: invalidSelector,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Labels: invalidSelector,
|
|
||||||
}
|
}
|
||||||
successCases := []api.ReplicationController{
|
successCases := []api.ReplicationController{
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
ReplicaSelector: validSelector,
|
Selector: validSelector,
|
||||||
PodTemplate: validPodTemplate,
|
Template: &validPodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc-123", Namespace: api.NamespaceDefault},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
ReplicaSelector: validSelector,
|
Selector: validSelector,
|
||||||
PodTemplate: validPodTemplate,
|
Template: &validPodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -911,49 +909,49 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
errorCases := map[string]api.ReplicationController{
|
errorCases := map[string]api.ReplicationController{
|
||||||
"zero-length ID": {
|
"zero-length ID": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "", Namespace: api.NamespaceDefault},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
ReplicaSelector: validSelector,
|
Selector: validSelector,
|
||||||
PodTemplate: validPodTemplate,
|
Template: &validPodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"missing-namespace": {
|
"missing-namespace": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
|
ObjectMeta: api.ObjectMeta{Name: "abc-123"},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
ReplicaSelector: validSelector,
|
Selector: validSelector,
|
||||||
PodTemplate: validPodTemplate,
|
Template: &validPodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"empty selector": {
|
"empty selector": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
PodTemplate: validPodTemplate,
|
Template: &validPodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"selector_doesnt_match": {
|
"selector_doesnt_match": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
ReplicaSelector: map[string]string{"foo": "bar"},
|
Selector: map[string]string{"foo": "bar"},
|
||||||
PodTemplate: validPodTemplate,
|
Template: &validPodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"invalid manifest": {
|
"invalid manifest": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
ReplicaSelector: validSelector,
|
Selector: validSelector,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"read-write presistent disk": {
|
"read-write presistent disk": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc"},
|
ObjectMeta: api.ObjectMeta{Name: "abc"},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
ReplicaSelector: validSelector,
|
Selector: validSelector,
|
||||||
PodTemplate: invalidVolumePodTemplate,
|
Template: &invalidVolumePodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"negative_replicas": {
|
"negative_replicas": {
|
||||||
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
ObjectMeta: api.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
Replicas: -1,
|
Replicas: -1,
|
||||||
ReplicaSelector: validSelector,
|
Selector: validSelector,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"invalid_label": {
|
"invalid_label": {
|
||||||
@ -964,9 +962,9 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
ReplicaSelector: validSelector,
|
Selector: validSelector,
|
||||||
PodTemplate: validPodTemplate,
|
Template: &validPodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"invalid_label 2": {
|
"invalid_label 2": {
|
||||||
@ -977,8 +975,8 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
"NoUppercaseOrSpecialCharsLike=Equals": "bar",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
DesiredState: api.ReplicationControllerState{
|
Spec: api.ReplicationControllerSpec{
|
||||||
PodTemplate: invalidPodTemplate,
|
Template: &invalidPodTemplate.Spec,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@ -989,13 +987,14 @@ func TestValidateReplicationController(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for i := range errs {
|
for i := range errs {
|
||||||
field := errs[i].(errors.ValidationError).Field
|
field := errs[i].(errors.ValidationError).Field
|
||||||
if !strings.HasPrefix(field, "desiredState.podTemplate.") &&
|
if !strings.HasPrefix(field, "spec.template.") &&
|
||||||
field != "name" &&
|
field != "name" &&
|
||||||
field != "namespace" &&
|
field != "namespace" &&
|
||||||
field != "desiredState.replicaSelector" &&
|
field != "spec.selector" &&
|
||||||
|
field != "spec.template" &&
|
||||||
field != "GCEPersistentDisk.ReadOnly" &&
|
field != "GCEPersistentDisk.ReadOnly" &&
|
||||||
field != "desiredState.replicas" &&
|
field != "spec.replicas" &&
|
||||||
field != "desiredState.label" &&
|
field != "spec.template.label" &&
|
||||||
field != "label" {
|
field != "label" {
|
||||||
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
t.Errorf("%s: missing prefix for: %v", k, errs[i])
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user