|
|
|
@ -3785,8 +3785,13 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
errorCases := map[string]api.Pod{
|
|
|
|
|
errorCases := map[string]struct {
|
|
|
|
|
spec api.Pod
|
|
|
|
|
expectedError string
|
|
|
|
|
}{
|
|
|
|
|
"bad name": {
|
|
|
|
|
expectedError: "metadata.name",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "", Namespace: "ns"},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
RestartPolicy: api.RestartPolicyAlways,
|
|
|
|
@ -3794,7 +3799,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"bad namespace": {
|
|
|
|
|
expectedError: "metadata.namespace",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: ""},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
RestartPolicy: api.RestartPolicyAlways,
|
|
|
|
@ -3802,13 +3810,19 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"bad spec": {
|
|
|
|
|
expectedError: "spec.containers[0].name",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: "ns"},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
Containers: []api.Container{{}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"bad label": {
|
|
|
|
|
expectedError: "NoUppercaseOrSpecialCharsLike=Equals",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "abc",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -3822,7 +3836,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid node selector requirement in node affinity, operator can't be null": {
|
|
|
|
|
expectedError: "spec.affinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].operator",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -3843,7 +3860,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid preferredSchedulingTerm in node affinity, weight should be in range 1-100": {
|
|
|
|
|
expectedError: "must be in the range 1-100",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -3867,7 +3887,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid requiredDuringSchedulingIgnoredDuringExecution node selector, nodeSelectorTerms must have at least one term": {
|
|
|
|
|
expectedError: "spec.affinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -3880,7 +3903,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid requiredDuringSchedulingIgnoredDuringExecution node selector term, matchExpressions must have at least one node selector requirement": {
|
|
|
|
|
expectedError: "spec.affinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -3897,7 +3923,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid weight in preferredDuringSchedulingIgnoredDuringExecution in pod affinity annotations, weight should be in range 1-100": {
|
|
|
|
|
expectedError: "must be in the range 1-100",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -3925,7 +3954,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid labelSelector in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, values should be empty if the operator is Exists": {
|
|
|
|
|
expectedError: "spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.matchExpressions.matchExpressions[0].values",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -3953,7 +3985,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid name space in preferredDuringSchedulingIgnoredDuringExecution in podaffinity annotations, name space shouldbe valid": {
|
|
|
|
|
expectedError: "spec.affinity.podAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.namespace",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -3980,7 +4015,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid pod affinity, empty topologyKey is not allowed for hard pod affinity": {
|
|
|
|
|
expectedError: "can only be empty for PreferredDuringScheduling pod anti affinity",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4004,7 +4042,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid pod anti-affinity, empty topologyKey is not allowed for hard pod anti-affinity": {
|
|
|
|
|
expectedError: "can only be empty for PreferredDuringScheduling pod anti affinity",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4028,7 +4069,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid pod anti-affinity, empty topologyKey is not allowed for soft pod affinity": {
|
|
|
|
|
expectedError: "can only be empty for PreferredDuringScheduling pod anti affinity",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4055,43 +4099,61 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid toleration key": {
|
|
|
|
|
expectedError: "spec.tolerations[0].key",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
|
},
|
|
|
|
|
Spec: extendPodSpecwithTolerations(validPodSpec(nil), []api.Toleration{{Key: "nospecialchars^=@", Operator: "Equal", Value: "bar", Effect: "NoSchedule"}}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid toleration operator": {
|
|
|
|
|
expectedError: "spec.tolerations[0].operator",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
|
},
|
|
|
|
|
Spec: extendPodSpecwithTolerations(validPodSpec(nil), []api.Toleration{{Key: "foo", Operator: "In", Value: "bar", Effect: "NoSchedule"}}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"value must be empty when `operator` is 'Exists'": {
|
|
|
|
|
expectedError: "spec.tolerations[0].operator",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
|
},
|
|
|
|
|
Spec: extendPodSpecwithTolerations(validPodSpec(nil), []api.Toleration{{Key: "foo", Operator: "Exists", Value: "bar", Effect: "NoSchedule"}}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
"operator must be 'Exists' when `key` is empty": {
|
|
|
|
|
expectedError: "spec.tolerations[0].operator",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
|
},
|
|
|
|
|
Spec: extendPodSpecwithTolerations(validPodSpec(nil), []api.Toleration{{Operator: "Equal", Value: "bar", Effect: "NoSchedule"}}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"effect must be 'NoExecute' when `TolerationSeconds` is set": {
|
|
|
|
|
expectedError: "spec.tolerations[0].effect",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "pod-forgiveness-invalid",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
|
},
|
|
|
|
|
Spec: extendPodSpecwithTolerations(validPodSpec(nil), []api.Toleration{{Key: "node.alpha.kubernetes.io/notReady", Operator: "Exists", Effect: "NoSchedule", TolerationSeconds: &[]int64{20}[0]}}),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"must be a valid pod seccomp profile": {
|
|
|
|
|
expectedError: "must be a valid seccomp profile",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4101,7 +4163,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"must be a valid container seccomp profile": {
|
|
|
|
|
expectedError: "must be a valid seccomp profile",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4111,7 +4176,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"must be a non-empty container name in seccomp annotation": {
|
|
|
|
|
expectedError: "name part must be non-empty",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4121,7 +4189,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"must be a non-empty container profile in seccomp annotation": {
|
|
|
|
|
expectedError: "must be a valid seccomp profile",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4131,7 +4202,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"must be a relative path in a node-local seccomp profile annotation": {
|
|
|
|
|
expectedError: "must be a relative path",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4141,7 +4215,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"must not start with '../'": {
|
|
|
|
|
expectedError: "must not contain '..'",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4151,7 +4228,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"AppArmor profile must apply to a container": {
|
|
|
|
|
expectedError: "metadata.annotations[container.apparmor.security.beta.kubernetes.io/fake-ctr]",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4168,7 +4248,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"AppArmor profile format must be valid": {
|
|
|
|
|
expectedError: "invalid AppArmor profile name",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4178,7 +4261,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"only default AppArmor profile may start with runtime/": {
|
|
|
|
|
expectedError: "invalid AppArmor profile name",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4188,7 +4274,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid sysctl annotation": {
|
|
|
|
|
expectedError: "metadata.annotations[security.alpha.kubernetes.io/sysctls]",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4198,7 +4287,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid comma-separated sysctl annotation": {
|
|
|
|
|
expectedError: "not of the format sysctl_name=value",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4208,7 +4300,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid unsafe sysctl annotation": {
|
|
|
|
|
expectedError: "metadata.annotations[security.alpha.kubernetes.io/sysctls]",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4218,7 +4313,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"intersecting safe sysctls and unsafe sysctls annotations": {
|
|
|
|
|
expectedError: "can not be safe and unsafe",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: "123",
|
|
|
|
|
Namespace: "ns",
|
|
|
|
@ -4229,7 +4327,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
Spec: validPodSpec(nil),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid opaque integer resource requirement: request must be <= limit": {
|
|
|
|
|
expectedError: "must be greater than or equal to pod.alpha.kubernetes.io/opaque-int-resource-A",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
Containers: []api.Container{
|
|
|
|
@ -4251,7 +4352,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid fractional opaque integer resource in container request": {
|
|
|
|
|
expectedError: "must be an integer",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
Containers: []api.Container{
|
|
|
|
@ -4270,7 +4374,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid fractional opaque integer resource in init container request": {
|
|
|
|
|
expectedError: "must be an integer",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
InitContainers: []api.Container{
|
|
|
|
@ -4290,7 +4397,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid fractional opaque integer resource in container limit": {
|
|
|
|
|
expectedError: "must be an integer",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
Containers: []api.Container{
|
|
|
|
@ -4312,7 +4422,10 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"invalid fractional opaque integer resource in init container limit": {
|
|
|
|
|
expectedError: "must be an integer",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns"},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
InitContainers: []api.Container{
|
|
|
|
@ -4335,10 +4448,37 @@ func TestValidatePod(t *testing.T) {
|
|
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"mirror-pod present without nodeName": {
|
|
|
|
|
expectedError: "mirror",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{api.MirrorPodAnnotationKey: ""}},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
|
|
|
|
RestartPolicy: api.RestartPolicyAlways,
|
|
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
"mirror-pod populated without nodeName": {
|
|
|
|
|
expectedError: "mirror",
|
|
|
|
|
spec: api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "123", Namespace: "ns", Annotations: map[string]string{api.MirrorPodAnnotationKey: "foo"}},
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
Containers: []api.Container{{Name: "ctr", Image: "image", ImagePullPolicy: "IfNotPresent", TerminationMessagePolicy: "File"}},
|
|
|
|
|
RestartPolicy: api.RestartPolicyAlways,
|
|
|
|
|
DNSPolicy: api.DNSClusterFirst,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
for k, v := range errorCases {
|
|
|
|
|
if errs := ValidatePod(&v); len(errs) == 0 {
|
|
|
|
|
if errs := ValidatePod(&v.spec); len(errs) == 0 {
|
|
|
|
|
t.Errorf("expected failure for %q", k)
|
|
|
|
|
} else if v.expectedError == "" {
|
|
|
|
|
t.Errorf("missing expectedError for %q, got %q", k, errs.ToAggregate().Error())
|
|
|
|
|
} else if actualError := errs.ToAggregate().Error(); !strings.Contains(actualError, v.expectedError) {
|
|
|
|
|
t.Errorf("expected error for %q to contain %q, got %q", k, v.expectedError, actualError)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -4476,10 +4616,10 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
tests := []struct {
|
|
|
|
|
a api.Pod
|
|
|
|
|
b api.Pod
|
|
|
|
|
isValid bool
|
|
|
|
|
err string
|
|
|
|
|
test string
|
|
|
|
|
}{
|
|
|
|
|
{api.Pod{}, api.Pod{}, true, "nothing"},
|
|
|
|
|
{api.Pod{}, api.Pod{}, "", "nothing"},
|
|
|
|
|
{
|
|
|
|
|
api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "foo"},
|
|
|
|
@ -4487,7 +4627,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
api.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "bar"},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"metadata.name",
|
|
|
|
|
"ids",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4507,7 +4647,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"labels",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4527,7 +4667,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"annotations",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4556,7 +4696,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"may not add or remove containers",
|
|
|
|
|
"more containers",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4585,7 +4725,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"may not add or remove containers",
|
|
|
|
|
"more init containers",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4597,7 +4737,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", DeletionTimestamp: &now},
|
|
|
|
|
Spec: api.PodSpec{Containers: []api.Container{{Image: "foo:V1"}}},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"deletion timestamp filled out",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4609,7 +4749,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{Name: "foo", DeletionTimestamp: &now, DeletionGracePeriodSeconds: &grace2},
|
|
|
|
|
Spec: api.PodSpec{Containers: []api.Container{{Image: "foo:V1"}}},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"metadata.deletionGracePeriodSeconds",
|
|
|
|
|
"deletion grace period seconds cleared",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4633,7 +4773,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"image change",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4657,7 +4797,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"init container image change",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4679,7 +4819,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec.containers[0].image",
|
|
|
|
|
"image change to empty",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4701,7 +4841,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec.initContainers[0].image",
|
|
|
|
|
"init container image change to empty",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4711,7 +4851,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
api.Pod{
|
|
|
|
|
Spec: api.PodSpec{},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"activeDeadlineSeconds no change, nil",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4725,7 +4865,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
ActiveDeadlineSeconds: &activeDeadlineSecondsPositive,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"activeDeadlineSeconds no change, set",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4735,7 +4875,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
api.Pod{},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"activeDeadlineSeconds change to positive from nil",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4749,7 +4889,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
ActiveDeadlineSeconds: &activeDeadlineSecondsLarger,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"activeDeadlineSeconds change to smaller positive",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4763,7 +4903,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
ActiveDeadlineSeconds: &activeDeadlineSecondsPositive,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec.activeDeadlineSeconds",
|
|
|
|
|
"activeDeadlineSeconds change to larger positive",
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
@ -4774,7 +4914,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
api.Pod{},
|
|
|
|
|
false,
|
|
|
|
|
"spec.activeDeadlineSeconds",
|
|
|
|
|
"activeDeadlineSeconds change to negative from nil",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4788,7 +4928,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
ActiveDeadlineSeconds: &activeDeadlineSecondsPositive,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec.activeDeadlineSeconds",
|
|
|
|
|
"activeDeadlineSeconds change to negative from positive",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4802,7 +4942,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
ActiveDeadlineSeconds: &activeDeadlineSecondsPositive,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"activeDeadlineSeconds change to zero from positive",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4812,7 +4952,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
api.Pod{},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"activeDeadlineSeconds change to zero from nil",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4822,7 +4962,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
ActiveDeadlineSeconds: &activeDeadlineSecondsPositive,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec.activeDeadlineSeconds",
|
|
|
|
|
"activeDeadlineSeconds change to nil from positive",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4852,7 +4992,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec: Forbidden: pod updates may not change fields",
|
|
|
|
|
"cpu change",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4882,7 +5022,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec: Forbidden: pod updates may not change fields",
|
|
|
|
|
"port change",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4902,7 +5042,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"bad label change",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4924,7 +5064,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
Tolerations: []api.Toleration{{Key: "key1", Value: "value1"}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec.tolerations: Forbidden",
|
|
|
|
|
"existing toleration value modified in pod spec updates",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4946,7 +5086,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
Tolerations: []api.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec.tolerations: Forbidden",
|
|
|
|
|
"existing toleration value modified in pod spec updates with modified tolerationSeconds",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4967,7 +5107,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
NodeName: "node1",
|
|
|
|
|
Tolerations: []api.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{20}[0]}},
|
|
|
|
|
}},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"modified tolerationSeconds in existing toleration value in pod spec updates",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -4988,7 +5128,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
Tolerations: []api.Toleration{{Key: "key1", Value: "value1"}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
false,
|
|
|
|
|
"spec.tolerations: Forbidden",
|
|
|
|
|
"toleration modified in updates to an unscheduled pod",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -5010,7 +5150,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
Tolerations: []api.Toleration{{Key: "key1", Value: "value1"}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"tolerations unmodified in updates to a scheduled pod",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -5034,7 +5174,7 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
Tolerations: []api.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
true,
|
|
|
|
|
"",
|
|
|
|
|
"added valid new toleration to existing tolerations in pod spec updates",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
@ -5053,22 +5193,48 @@ func TestValidatePodUpdate(t *testing.T) {
|
|
|
|
|
Spec: api.PodSpec{
|
|
|
|
|
NodeName: "node1", Tolerations: []api.Toleration{{Key: "key1", Value: "value1", Operator: "Equal", Effect: "NoExecute", TolerationSeconds: &[]int64{10}[0]}},
|
|
|
|
|
}},
|
|
|
|
|
false,
|
|
|
|
|
"spec.tolerations[1].effect",
|
|
|
|
|
"added invalid new toleration to existing tolerations in pod spec updates",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: api.PodSpec{NodeName: "foo"}},
|
|
|
|
|
api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}},
|
|
|
|
|
"spec: Forbidden: pod updates may not change fields",
|
|
|
|
|
"removed nodeName from pod spec",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Annotations: map[string]string{api.MirrorPodAnnotationKey: ""}}, Spec: api.PodSpec{NodeName: "foo"}},
|
|
|
|
|
api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: api.PodSpec{NodeName: "foo"}},
|
|
|
|
|
"metadata.annotations[kubernetes.io/config.mirror]",
|
|
|
|
|
"removed mirror pod annotation",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo"}, Spec: api.PodSpec{NodeName: "foo"}},
|
|
|
|
|
api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Annotations: map[string]string{api.MirrorPodAnnotationKey: ""}}, Spec: api.PodSpec{NodeName: "foo"}},
|
|
|
|
|
"metadata.annotations[kubernetes.io/config.mirror]",
|
|
|
|
|
"added mirror pod annotation",
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Annotations: map[string]string{api.MirrorPodAnnotationKey: "foo"}}, Spec: api.PodSpec{NodeName: "foo"}},
|
|
|
|
|
api.Pod{ObjectMeta: metav1.ObjectMeta{Name: "foo", Annotations: map[string]string{api.MirrorPodAnnotationKey: "bar"}}, Spec: api.PodSpec{NodeName: "foo"}},
|
|
|
|
|
"metadata.annotations[kubernetes.io/config.mirror]",
|
|
|
|
|
"changed mirror pod annotation",
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, test := range tests {
|
|
|
|
|
test.a.ObjectMeta.ResourceVersion = "1"
|
|
|
|
|
test.b.ObjectMeta.ResourceVersion = "1"
|
|
|
|
|
errs := ValidatePodUpdate(&test.a, &test.b)
|
|
|
|
|
if test.isValid {
|
|
|
|
|
if test.err == "" {
|
|
|
|
|
if len(errs) != 0 {
|
|
|
|
|
t.Errorf("unexpected invalid: %s (%+v)\nA: %+v\nB: %+v", test.test, errs, test.a, test.b)
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if len(errs) == 0 {
|
|
|
|
|
t.Errorf("unexpected valid: %s\nA: %+v\nB: %+v", test.test, test.a, test.b)
|
|
|
|
|
} else if actualErr := errs.ToAggregate().Error(); !strings.Contains(actualErr, test.err) {
|
|
|
|
|
t.Errorf("unexpected error message: %s\nExpected error: %s\nActual error: %s", test.test, test.err, actualErr)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|