Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[release-4.14] OCPBUGS-27347: UPSTREAM: <carry>: Update management webhook pod admission logic #1855

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,13 @@ func (a *managementCPUsOverride) Admit(ctx context.Context, attr admission.Attri
return err
}

if _, found := ns.Annotations[namespaceAllowedAnnotation]; !found && len(workloadType) > 0 {
pod.Annotations[workloadAdmissionWarning] = fmt.Sprintf(
"skipping pod CPUs requests modifications because the %s namespace is not annotated with %s to allow workload partitioning",
ns.GetName(), namespaceAllowedAnnotation)
return nil
}

if !doesNamespaceAllowWorkloadType(ns.Annotations, workloadType) {
return admission.NewForbidden(attr, fmt.Errorf("%s the pod namespace %q does not allow the workload type %s", PluginName, ns.Name, workloadType))
}
Expand Down Expand Up @@ -449,10 +456,13 @@ func podHasBothCPULimitAndRequest(containers []coreapi.Container) bool {
return false
}

// doesNamespaceAllowWorkloadType will return false when a workload type does not match any present ones.
func doesNamespaceAllowWorkloadType(annotations map[string]string, workloadType string) bool {
v, found := annotations[namespaceAllowedAnnotation]
// When a namespace contains no annotation for workloads we infer that to mean all workload types are allowed.
// The mutation hook will strip all workload annotation from pods that contain them in that circumstance.
if !found {
return false
return true
}

for _, t := range strings.Split(v, ",") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ func TestAdmit(t *testing.T) {
}{
{
name: "should return admission error when the pod namespace does not allow the workload type",
pod: testManagedPod("500m", "250m", "500Mi", "250Mi"),
pod: testManagedPodWithWorkloadAnnotation("500m", "250m", "500Mi", "250Mi", "non-existent"),
expectedCpuRequest: resource.MustParse("250m"),
namespace: testNamespace(),
namespace: testManagedNamespace(),
nodes: []*corev1.Node{testNodeWithManagementResource()},
infra: testClusterSNOInfra(),
expectedError: fmt.Errorf("the pod namespace %q does not allow the workload type management", "namespace"),
expectedError: fmt.Errorf("the pod namespace %q does not allow the workload type non-existent", "managed-namespace"),
},
{
name: "should ignore pods that do not have managed annotation",
Expand Down Expand Up @@ -167,6 +167,25 @@ func TestAdmit(t *testing.T) {
expectedError: fmt.Errorf(`failed to get workload annotation effect: the workload annotation value map["test":"test"] does not have "effect" key`),
infra: testClusterSNOInfra(),
},
{
name: "should return admission warning when the pod has workload annotation but the namespace does not",
pod: testManagedPodWithAnnotations(
"500m",
"250m",
"500Mi",
"250Mi",
map[string]string{
fmt.Sprintf("%s%s", podWorkloadTargetAnnotationPrefix, workloadTypeManagement): `{"test": "test"}`,
},
),
expectedCpuRequest: resource.MustParse("250m"),
expectedAnnotations: map[string]string{
workloadAdmissionWarning: "skipping pod CPUs requests modifications because the namespace namespace is not annotated with workload.openshift.io/allowed to allow workload partitioning",
},
namespace: testNamespace(),
nodes: []*corev1.Node{testNodeWithManagementResource()},
infra: testClusterSNOInfra(),
},
{
name: "should delete CPU requests and update workload CPU annotations for the burstable pod with managed annotation",
pod: testManagedPod("", "250m", "500Mi", "250Mi"),
Expand Down Expand Up @@ -437,16 +456,28 @@ func TestValidate(t *testing.T) {
expectedError: fmt.Errorf("the pod without workload annotations can not have containers with workload resources %q", "management.workload.openshift.io/cores"),
},
{
name: "should return invalid error when the pod has workload annotation, but the pod namespace does not have allowed annotation",
pod: testManagedPod(
name: "should return invalid error when the pod has workload annotation, but the pod namespace does not have allowed workload type",
pod: testManagedPodWithWorkloadAnnotation(
"500m",
"250m",
"500Mi",
"250Mi",
"non-existent",
),
namespace: testNamespace(),
namespace: testManagedNamespace(),
nodes: []*corev1.Node{testNodeWithManagementResource()},
expectedError: fmt.Errorf("the pod can not have workload annotation, when the namespace %q does not allow it", "namespace"),
expectedError: fmt.Errorf("the pod can not have workload annotation, when the namespace %q does not allow it", "managed-namespace"),
},
{
name: "should not return any errors when the pod has workload annotation, but the pod namespace has no annotations",
pod: testManagedPod(
"500m",
"250m",
"500Mi",
"250Mi",
),
namespace: testNamespace(),
nodes: []*corev1.Node{testNodeWithManagementResource()},
},
{
name: "should not return any errors when the pod and namespace valid",
Expand Down Expand Up @@ -532,19 +563,12 @@ func testManagedStaticPod(cpuLimit, cpuRequest, memoryLimit, memoryRequest strin
}

func testManagedPod(cpuLimit, cpuRequest, memoryLimit, memoryRequest string) *kapi.Pod {
pod := testPod(cpuLimit, cpuRequest, memoryLimit, memoryRequest)

pod.Annotations = map[string]string{}
for _, c := range pod.Spec.InitContainers {
cpusetAnnotation := fmt.Sprintf("%s%s", containerResourcesAnnotationPrefix, c.Name)
pod.Annotations[cpusetAnnotation] = `{"cpuset": "0-1"}`
}
for _, c := range pod.Spec.Containers {
cpusetAnnotation := fmt.Sprintf("%s%s", containerResourcesAnnotationPrefix, c.Name)
pod.Annotations[cpusetAnnotation] = `{"cpuset": "0-1"}`
}
return testManagedPodWithWorkloadAnnotation(cpuLimit, cpuRequest, memoryLimit, memoryRequest, workloadTypeManagement)
}

managementWorkloadAnnotation := fmt.Sprintf("%s%s", podWorkloadTargetAnnotationPrefix, workloadTypeManagement)
func testManagedPodWithWorkloadAnnotation(cpuLimit, cpuRequest, memoryLimit, memoryRequest string, workloadType string) *kapi.Pod {
pod := testPod(cpuLimit, cpuRequest, memoryLimit, memoryRequest)
managementWorkloadAnnotation := fmt.Sprintf("%s%s", podWorkloadTargetAnnotationPrefix, workloadType)
pod.Annotations = map[string]string{
managementWorkloadAnnotation: fmt.Sprintf(`{"%s":"%s"}`, podWorkloadAnnotationEffect, workloadEffectPreferredDuringScheduling),
}
Expand Down