Merge pull request #46909 from derekwaynecarr/fix-env-var-validation

Automatic merge from submit-queue (batch tested with PRs 47726, 47693, 46909, 46812)

pod spec was not validating envFrom

**What this PR does / why we need it**:
adds missing validation for envFrom in a pod.spec.containers.envFrom
fixes validation of pod.spec.containers.env.configMapRef.name
fixes validation of pod.spec.containers.env.secretRef.name

**Which issue this PR fixes** 
Fixes https://github.com/kubernetes/kubernetes/issues/46908
This commit is contained in:
Kubernetes Submit Queue
2017-06-19 18:34:04 -07:00
committed by GitHub
2 changed files with 88 additions and 4 deletions

View File

@@ -1551,6 +1551,7 @@ func validateContainerPorts(ports []api.ContainerPort, fldPath *field.Path) fiel
return allErrs return allErrs
} }
// ValidateEnv validates env vars
func ValidateEnv(vars []api.EnvVar, fldPath *field.Path) field.ErrorList { func ValidateEnv(vars []api.EnvVar, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
@@ -1721,8 +1722,9 @@ func validateContainerResourceDivisor(rName string, divisor resource.Quantity, f
func validateConfigMapKeySelector(s *api.ConfigMapKeySelector, fldPath *field.Path) field.ErrorList { func validateConfigMapKeySelector(s *api.ConfigMapKeySelector, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if len(s.Name) == 0 { nameFn := ValidateNameFunc(ValidateSecretName)
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) for _, msg := range nameFn(s.Name, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), s.Name, msg))
} }
if len(s.Key) == 0 { if len(s.Key) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("key"), "")) allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
@@ -1738,8 +1740,9 @@ func validateConfigMapKeySelector(s *api.ConfigMapKeySelector, fldPath *field.Pa
func validateSecretKeySelector(s *api.SecretKeySelector, fldPath *field.Path) field.ErrorList { func validateSecretKeySelector(s *api.SecretKeySelector, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{} allErrs := field.ErrorList{}
if len(s.Name) == 0 { nameFn := ValidateNameFunc(ValidateSecretName)
allErrs = append(allErrs, field.Required(fldPath.Child("name"), "")) for _, msg := range nameFn(s.Name, false) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("name"), s.Name, msg))
} }
if len(s.Key) == 0 { if len(s.Key) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("key"), "")) allErrs = append(allErrs, field.Required(fldPath.Child("key"), ""))
@@ -2011,6 +2014,7 @@ func validateContainers(containers []api.Container, volumes sets.String, fldPath
allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...) allErrs = append(allErrs, validateProbe(ctr.ReadinessProbe, idxPath.Child("readinessProbe"))...)
allErrs = append(allErrs, validateContainerPorts(ctr.Ports, idxPath.Child("ports"))...) allErrs = append(allErrs, validateContainerPorts(ctr.Ports, idxPath.Child("ports"))...)
allErrs = append(allErrs, ValidateEnv(ctr.Env, idxPath.Child("env"))...) allErrs = append(allErrs, ValidateEnv(ctr.Env, idxPath.Child("env"))...)
allErrs = append(allErrs, ValidateEnvFrom(ctr.EnvFrom, idxPath.Child("envFrom"))...)
allErrs = append(allErrs, ValidateVolumeMounts(ctr.VolumeMounts, volumes, idxPath.Child("volumeMounts"))...) allErrs = append(allErrs, ValidateVolumeMounts(ctr.VolumeMounts, volumes, idxPath.Child("volumeMounts"))...)
allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, idxPath.Child("imagePullPolicy"))...) allErrs = append(allErrs, validatePullPolicy(ctr.ImagePullPolicy, idxPath.Child("imagePullPolicy"))...)
allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, idxPath.Child("resources"))...) allErrs = append(allErrs, ValidateResourceRequirements(&ctr.Resources, idxPath.Child("resources"))...)

View File

@@ -2733,6 +2733,34 @@ func TestValidateEnv(t *testing.T) {
}}, }},
expectedError: `[0].valueFrom: Invalid value: "": may not have more than one field specified at a time`, expectedError: `[0].valueFrom: Invalid value: "": may not have more than one field specified at a time`,
}, },
{
name: "valueFrom.secretKeyRef.name invalid",
envs: []api.EnvVar{{
Name: "abc",
ValueFrom: &api.EnvVarSource{
SecretKeyRef: &api.SecretKeySelector{
LocalObjectReference: api.LocalObjectReference{
Name: "$%^&*#",
},
Key: "a-key",
},
},
}},
},
{
name: "valueFrom.configMapKeyRef.name invalid",
envs: []api.EnvVar{{
Name: "abc",
ValueFrom: &api.EnvVarSource{
ConfigMapKeyRef: &api.ConfigMapKeySelector{
LocalObjectReference: api.LocalObjectReference{
Name: "$%^&*#",
},
Key: "some-key",
},
},
}},
},
{ {
name: "missing FieldPath on ObjectFieldSelector", name: "missing FieldPath on ObjectFieldSelector",
envs: []api.EnvVar{{ envs: []api.EnvVar{{
@@ -2939,6 +2967,26 @@ func TestValidateEnvFrom(t *testing.T) {
}, },
expectedError: "field: Invalid value: \"\": may not have more than one field specified at a time", expectedError: "field: Invalid value: \"\": may not have more than one field specified at a time",
}, },
{
name: "invalid secret ref name",
envs: []api.EnvFromSource{
{
SecretRef: &api.SecretEnvSource{
LocalObjectReference: api.LocalObjectReference{Name: "$%^&*#"}},
},
},
expectedError: "field[0].secretRef.name: Invalid value: \"$%^&*#\": " + dnsSubdomainLabelErrMsg,
},
{
name: "invalid config ref name",
envs: []api.EnvFromSource{
{
ConfigMapRef: &api.ConfigMapEnvSource{
LocalObjectReference: api.LocalObjectReference{Name: "$%^&*#"}},
},
},
expectedError: "field[0].configMapRef.name: Invalid value: \"$%^&*#\": " + dnsSubdomainLabelErrMsg,
},
} }
for _, tc := range errorCases { for _, tc := range errorCases {
if errs := ValidateEnvFrom(tc.envs, field.NewPath("field")); len(errs) == 0 { if errs := ValidateEnvFrom(tc.envs, field.NewPath("field")); len(errs) == 0 {
@@ -3253,6 +3301,21 @@ func TestValidateContainers(t *testing.T) {
ImagePullPolicy: "IfNotPresent", ImagePullPolicy: "IfNotPresent",
TerminationMessagePolicy: "File", TerminationMessagePolicy: "File",
}, },
{
Name: "env-from-source",
Image: "image",
ImagePullPolicy: "IfNotPresent",
TerminationMessagePolicy: "File",
EnvFrom: []api.EnvFromSource{
{
ConfigMapRef: &api.ConfigMapEnvSource{
LocalObjectReference: api.LocalObjectReference{
Name: "test",
},
},
},
},
},
{Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", SecurityContext: fakeValidSecurityContext(true)}, {Name: "abc-1234", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File", SecurityContext: fakeValidSecurityContext(true)},
} }
if errs := validateContainers(successCase, volumes, field.NewPath("field")); len(errs) != 0 { if errs := validateContainers(successCase, volumes, field.NewPath("field")); len(errs) != 0 {
@@ -3483,6 +3546,23 @@ func TestValidateContainers(t *testing.T) {
TerminationMessagePolicy: "File", TerminationMessagePolicy: "File",
}, },
}, },
"Invalid env from": {
{
Name: "env-from-source",
Image: "image",
ImagePullPolicy: "IfNotPresent",
TerminationMessagePolicy: "File",
EnvFrom: []api.EnvFromSource{
{
ConfigMapRef: &api.ConfigMapEnvSource{
LocalObjectReference: api.LocalObjectReference{
Name: "$%^&*#",
},
},
},
},
},
},
} }
for k, v := range errorCases { for k, v := range errorCases {
if errs := validateContainers(v, volumes, field.NewPath("field")); len(errs) == 0 { if errs := validateContainers(v, volumes, field.NewPath("field")); len(errs) == 0 {