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

OCPBUGS-35911: E2E: Add test to verify runc process excludes the cpus used by pod. #1088

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

SargunNarula
Copy link
Contributor

@SargunNarula SargunNarula commented Jun 21, 2024

Adding a test to verify that runc does not use CPUs assigned to guaranteed pods.

Original bug link - https://bugzilla.redhat.com/show_bug.cgi?id=1910386

@openshift-ci-robot
Copy link
Contributor

@SargunNarula: This pull request explicitly references no jira issue.

In response to this:

Adding a test to verify that runc does not use CPUs assigned to guaranteed pods.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot openshift-ci-robot added the jira/valid-reference Indicates that this PR references a valid Jira ticket of any type. label Jun 21, 2024
Copy link
Contributor

openshift-ci bot commented Jun 21, 2024

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: SargunNarula
Once this PR has been reviewed and has the lgtm label, please assign marsik for approval. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@SargunNarula SargunNarula changed the title NO-JIRA: E2E: Add test to verify runc uses valid cpus OCPBUGS-35911: E2E: Add test to verify runc uses valid cpus Jun 21, 2024
@openshift-ci-robot openshift-ci-robot added the jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. label Jun 21, 2024
@openshift-ci-robot
Copy link
Contributor

@SargunNarula: This pull request references Jira Issue OCPBUGS-35911, which is valid. The bug has been moved to the POST state.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.17.0) matches configured target version for branch (4.17.0)
  • bug is in the state New, which is one of the valid states (NEW, ASSIGNED, POST)

No GitHub users were found matching the public email listed for the QA contact in Jira ([email protected]), skipping review request.

The bug has been updated to refer to the pull request using the external bug tracker.

In response to this:

Adding a test to verify that runc does not use CPUs assigned to guaranteed pods.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci-robot
Copy link
Contributor

@SargunNarula: This pull request references Jira Issue OCPBUGS-35911, which is valid.

3 validation(s) were run on this bug
  • bug is open, matching expected state (open)
  • bug target version (4.17.0) matches configured target version for branch (4.17.0)
  • bug is in the state POST, which is one of the valid states (NEW, ASSIGNED, POST)

No GitHub users were found matching the public email listed for the QA contact in Jira ([email protected]), skipping review request.

In response to this:

Adding a test to verify that runc does not use CPUs assigned to guaranteed pods.

Original bug link - https://bugzilla.redhat.com/show_bug.cgi?id=1910386

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@SargunNarula SargunNarula changed the title OCPBUGS-35911: E2E: Add test to verify runc uses valid cpus OCPBUGS-35911: E2E: Add test to verify runc process excludes the cpus used by pod. Jun 21, 2024
Copy link
Contributor

@shajmakh shajmakh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this. I added few initial comments below


AfterEach(func() {
cmd := []string{"rm", "-f", "/rootfs/var/roothome/create"}
nodes.ExecCommand(ctx, workerRTNode, cmd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's add error handling here please

Copy link
Contributor Author

@SargunNarula SargunNarula Jul 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test fails at this line with context deadline error, every time Expect error is added. I have manually verified that If expect is removed, the rm task gets completed at the system. I tried using custom context with context.WithDeadline & context.WithTimeout but still the test failed. This happens at the next error handling part as well.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wouldn't completely ignore the error though, a warning report or a klog.Error is fine.
also we can make sure that after this command is executed the file was indeed deleted as a workaround for handling the error

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to what Shereen wrote

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the intermediate file logic, hence this command is not required. On the other places added the error handling.

for _, containerID := range containerIDs {
path := fmt.Sprintf("/rootfs/var/run/containers/storage/overlay-containers/%s/userdata/config.json", containerID)
cmd := []string{"/bin/bash", "-c", fmt.Sprintf("cat %s >> /rootfs/var/roothome/create", path)}
nodes.ExecCommand(ctx, workerRTNode, cmd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's please add error handling in all places

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a comment above regarding facing context deadline error, it is applicable here too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With new logic, file handling is not performed. Yet error handling is added at places required.

@mrniranjan
Copy link
Contributor

looks good to me from my side.

@SargunNarula SargunNarula force-pushed the runc_cpu_isolation branch 2 times, most recently from 02e4f19 to 73a257b Compare September 24, 2024 11:46
deleteTestPod(ctx, bestEffortPod)
})

It("[test_id: 74461] Verify that runc excludes the cpus used by guaranteed pod", func() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's please add By() and logs where it fits to help view the flow of the test when debugging

Copy link
Contributor

@ffromani ffromani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the testing logic can be maybe simplified, but no major objections it seems
questions and possible improvements inside

Expect(err).ToNot(HaveOccurred())
for _, containerID := range containerIDs {
path := fmt.Sprintf("/rootfs/var/run/containers/storage/overlay-containers/%s/userdata/config.json", containerID)
cmd := []string{"/bin/bash", "-c", fmt.Sprintf("cat %s >> /rootfs/var/roothome/create", path)}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to copy the data into an intermediate file and can't we read it directly and store in a variable in this test?
if we need an itermediate file, since we go in append mode, let's make sure the file is actually empty before the test starts. If because a bug the file is not created properly, we will have corrupted state very hard to notice.
Another approach (possibly better) is to create a temp file for this test.

I think the simpler solution is to just avoid the intermediate file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @ffromani , for the simpler solution advice. Revised with latest commit.

})

func getPod(ctx context.Context, workerRTNode *corev1.Node, guaranteed bool) (*corev1.Pod, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this can't fail , let's just omit the error return value.
I'd call it makePod rather than getPod

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revised with latest commit.

Comment on lines 953 to 954
overlapFound := !guaranteedPodCpus.Intersection(runcCpus).IsEmpty()
Expect(overlapFound).ToNot(BeTrue(), fmt.Sprintf("Overlap found between guaranteedPod cpus (%s) and runtime Cpus (%s), not expected behaviour", guaranteedPodCpus, runcCpus))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or

overlap := guaranteedPodCpus.Intersection(runcCpus).List()
Expect(overlap).To(BeEmpty(), "Overlap found between guaranteedPod cpus (%s) and runtime Cpus (%s), not expected behaviour", guaranteedPodCpus, runcCpus)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a much better way, Thanks. Revised.


AfterEach(func() {
cmd := []string{"rm", "-f", "/rootfs/var/roothome/create"}
nodes.ExecCommand(ctx, workerRTNode, cmd)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to what Shereen wrote

Adding a test to verify that runc does not use CPUs assigned to guaranteed pods.

Signed-off-by: Sargun Narula <[email protected]>
Comment on lines +941 to +942
Expect(len(hostnameMatches)).ToNot(Equal(0), "Failed to extract hostname information")
Expect(len(cpusMatches)).ToNot(Equal(0), "Failed to extract cpus information")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Expect().ToNot(Equal(0)) = Expect().ToNot(BeEmpty())

Comment on lines +909 to +910
bestEffortPod = makePod(ctx, workerRTNode, false)
err = testclient.Client.Create(ctx, bestEffortPod)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how do we guarantee that the pod will be created with a different name from the GU pod?

_, err = pods.WaitForCondition(ctx, client.ObjectKeyFromObject(guaranteedPod), corev1.PodReady, corev1.ConditionTrue, 5*time.Minute)
Expect(err).ToNot(HaveOccurred(), "Guaranteed pod did not become ready in time")
Expect(guaranteedPod.Status.QOSClass).To(Equal(corev1.PodQOSGuaranteed), "Guaranteed pod does not have the correct QOSClass")

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an info report would be helpful here, something like:
klog.InfoS("<QoS> pod %s/%s was successfully created", updatedPodObj.Namespace,updatedPodObj.Name)
same for the best-effort

Comment on lines +892 to +896
AfterEach(func() {
By("Cleaning up pods")
deleteTestPod(ctx, guaranteedPod)
deleteTestPod(ctx, bestEffortPod)
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can avoid after each because the creation of the pods is done in the specific It(), you can convert that to defer after each pods creation (as close as possible to the creation):

guaranteedPod = makePod(ctx, workerRTNode, true)
err := testclient.Client.Create(ctx, guaranteedPod)
Expect(err).ToNot(HaveOccurred(), "Failed to create guaranteed pod")
defer deleteTestPod(ctx, guaranteedPod)

Copy link
Contributor

@ffromani ffromani left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this tests checks the correct thing. We do check a BE pod has no overlap with CPUs exclusively assigned to a Guaranteed pod, but the problem here is not what happens at runtime, but what happened at pod creation time. Once the pod goes running, runc is terminated, and there's no trace of where did it run

Copy link
Contributor

openshift-ci bot commented Sep 27, 2024

@SargunNarula: all tests passed!

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

@SargunNarula
Copy link
Contributor Author

@ffromani The original issue identified was that when launching a guaranteed pod running a cyclic test, the runc container creation process was observed to be running on isolated CPUs. This process inadvertently utilized the CPUs allocated to the cyclic test.

The resolution involved ensuring that the cpuset.cpus configuration is passed during container creation.

Additionally, since runc follows a two-step creation process, the initialization process (executed as /usr/bin/pod, which is a symlink to /usr/bin/runc) is started within a container. This container is assigned the cpuset.cpus values. This behavior can be confirmed by examining the config.json of the initialization container to verify that the appropriate CPU allocation is applied, reserved CPUs in the case of a guaranteed pod, or all available CPUs in the case of a Best-Effort (BE) pod.

Reference:

Based on these observations, the current patch may not effectively validate this scenario. I will work on a revised patch to accurately verify the CPUs being utilized.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
jira/valid-bug Indicates that a referenced Jira bug is valid for the branch this PR is targeting. jira/valid-reference Indicates that this PR references a valid Jira ticket of any type.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants