Skip to content

Commit

Permalink
Added daemonset for inspecting nodes configuration
Browse files Browse the repository at this point in the history
On hypershift there is no MCO, hence there are no machine-config-daemon pods.
A different resolution is needed for accessing the underlying node for inspecting configurations.
This commit adds a daemonset that will start upon test suites - on every node we will deploy a pod with escalated privileges and host fs mounted.
This API will be used for both hypershift and non-hypershift systems.

Signed-off-by: Ronny Baturov <[email protected]>
  • Loading branch information
rbaturov committed Apr 1, 2024
1 parent 8d02255 commit 43743a9
Show file tree
Hide file tree
Showing 13 changed files with 303 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
package __performance_config_test

import (
"context"
"flag"
"log"
"os"
Expand All @@ -14,6 +15,7 @@ import (
. "github.com/onsi/ginkgo/v2"
"github.com/onsi/ginkgo/v2/reporters"
. "github.com/onsi/gomega"
"k8s.io/apimachinery/pkg/api/errors"

ctrllog "sigs.k8s.io/controller-runtime/pkg/log"

Expand All @@ -22,7 +24,10 @@ import (

testutils "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils"
testclient "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/client"
"github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/daemonset"
"github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/images"
"github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/k8sreporter"
"github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/namespaces"
)

var (
Expand Down Expand Up @@ -59,6 +64,13 @@ func TestPerformanceConfig(t *testing.T) {

var _ = BeforeSuite(func() {
Expect(testclient.ClientsEnabled).To(BeTrue())
// create test namespace
if err := testclient.Client.Create(context.TODO(), namespaces.TestingDaemonsetNamespace); !errors.IsAlreadyExists(err) {
Expect(err).ToNot(HaveOccurred())
}

err := daemonset.CreateForTesting(testclient.Client, testutils.TestingDaemonsetNamespace, testutils.TestingDaemonsetName, images.Test())
Expect(err).ToNot(HaveOccurred())

})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ var _ = Describe("[performance]Hugepages", Ordered, func() {

func checkHugepagesStatus(ctx context.Context, path string, workerRTNode *corev1.Node) int {
command := []string{"cat", path}
out, err := nodes.ExecCommandOnMachineConfigDaemon(ctx, workerRTNode, command)
out, err := nodes.ExecCommandOnTestingDaemonPod(ctx, workerRTNode, command)
Expect(err).ToNot(HaveOccurred())
n, err := strconv.Atoi(strings.Trim(string(out), "\n\r"))
Expect(err).ToNot(HaveOccurred())
Expand Down
24 changes: 12 additions & 12 deletions test/e2e/performanceprofile/functests/1_performance/performance.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ var _ = Describe("[rfe_id:27368][performance]", Ordered, func() {

It("[test_id:31198] Should set CPU affinity kernel argument", func() {
for _, node := range workerRTNodes {
cmdline, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
cmdline, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
Expect(err).ToNot(HaveOccurred())
// since systemd.cpu_affinity is calculated on node level using tuned we can check only the key in this context.
Expect(string(cmdline)).To(ContainSubstring("systemd.cpu_affinity="))
Expand All @@ -151,7 +151,7 @@ var _ = Describe("[rfe_id:27368][performance]", Ordered, func() {

It("[test_id:32702] Should set CPU isolcpu's kernel argument managed_irq flag", func() {
for _, node := range workerRTNodes {
cmdline, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
cmdline, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
Expect(err).ToNot(HaveOccurred())
if profile.Spec.CPU.BalanceIsolated != nil && *profile.Spec.CPU.BalanceIsolated == false {
Expect(string(cmdline)).To(ContainSubstring("isolcpus=domain,managed_irq,"))
Expand All @@ -164,7 +164,7 @@ var _ = Describe("[rfe_id:27368][performance]", Ordered, func() {
It("[test_id:27081][crit:high][vendor:[email protected]][level:acceptance] Should set workqueue CPU mask", func() {
for _, node := range workerRTNodes {
By(fmt.Sprintf("Getting tuned.non_isolcpus kernel argument on %q", node.Name))
cmdline, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
cmdline, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
Expect(err).ToNot(HaveOccurred())
re := regexp.MustCompile(`tuned.non_isolcpus=\S+`)
nonIsolcpusFullArgument := re.FindString(string(cmdline))
Expand All @@ -185,13 +185,13 @@ var _ = Describe("[rfe_id:27368][performance]", Ordered, func() {
}

By(fmt.Sprintf("Getting the virtual workqueue mask (/sys/devices/virtual/workqueue/cpumask) on %q", node.Name))
workqueueMaskData, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"cat", "/sys/devices/virtual/workqueue/cpumask"})
workqueueMaskData, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"cat", "/sys/devices/virtual/workqueue/cpumask"})
Expect(err).ToNot(HaveOccurred())
workqueueMask := getTrimmedMaskFromData("virtual", workqueueMaskData)
expectMasksEqual(nonIsolcpusMaskNoDelimiters, workqueueMask)

By(fmt.Sprintf("Getting the writeback workqueue mask (/sys/bus/workqueue/devices/writeback/cpumask) on %q", node.Name))
workqueueWritebackMaskData, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"cat", "/sys/bus/workqueue/devices/writeback/cpumask"})
workqueueWritebackMaskData, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"cat", "/sys/bus/workqueue/devices/writeback/cpumask"})
Expect(err).ToNot(HaveOccurred())
workqueueWritebackMask := getTrimmedMaskFromData("workqueue", workqueueWritebackMaskData)
expectMasksEqual(nonIsolcpusMaskNoDelimiters, workqueueWritebackMask)
Expand All @@ -200,12 +200,12 @@ var _ = Describe("[rfe_id:27368][performance]", Ordered, func() {

It("[test_id:32375][crit:high][vendor:[email protected]][level:acceptance] initramfs should not have injected configuration", func() {
for _, node := range workerRTNodes {
rhcosId, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"awk", "-F", "/", "{printf $3}", "/rootfs/proc/cmdline"})
rhcosId, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"awk", "-F", "/", "{printf $3}", "/rootfs/proc/cmdline"})
Expect(err).ToNot(HaveOccurred())
initramfsImagesPath, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"find", filepath.Join("/rootfs/boot/ostree", string(rhcosId)), "-name", "*.img"})
initramfsImagesPath, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"find", filepath.Join("/rootfs/boot/ostree", string(rhcosId)), "-name", "*.img"})
Expect(err).ToNot(HaveOccurred())
modifiedImagePath := strings.TrimPrefix(strings.TrimSpace(string(initramfsImagesPath)), "/rootfs")
initrd, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"chroot", "/rootfs", "lsinitrd", modifiedImagePath})
initrd, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"chroot", "/rootfs", "lsinitrd", modifiedImagePath})
Expect(err).ToNot(HaveOccurred())
Expect(string(initrd)).ShouldNot(ContainSubstring("'/etc/systemd/system.conf /etc/systemd/system.conf.d/setAffinity.conf'"))
}
Expand Down Expand Up @@ -279,7 +279,7 @@ var _ = Describe("[rfe_id:27368][performance]", Ordered, func() {
It("[test_id:28611][crit:high][vendor:[email protected]][level:acceptance] Should set additional kernel arguments on the machine", func() {
if profile.Spec.AdditionalKernelArgs != nil {
for _, node := range workerRTNodes {
cmdline, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
cmdline, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
Expect(err).ToNot(HaveOccurred())
for _, arg := range profile.Spec.AdditionalKernelArgs {
Expect(string(cmdline)).To(ContainSubstring(arg))
Expand Down Expand Up @@ -1011,7 +1011,7 @@ var _ = Describe("[rfe_id:27368][performance]", Ordered, func() {

It("[test_id:54083] Should have kernel param rcutree.kthread", func() {
for _, node := range workerRTNodes {
cmdline, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
cmdline, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &node, []string{"cat", "/proc/cmdline"})
Expect(err).ToNot(HaveOccurred(), "Failed to read /proc/cmdline")
Expect(string(cmdline)).To(ContainSubstring("rcutree.kthread_prio=11"), "Boot Parameters should contain rctree.kthread_prio=11")
}
Expand Down Expand Up @@ -1301,7 +1301,7 @@ func execSysctlOnWorkers(ctx context.Context, workerNodes []corev1.Node, sysctlM
for _, node := range workerNodes {
for param, expected := range sysctlMap {
By(fmt.Sprintf("executing the command \"sysctl -n %s\"", param))
out, err = nodes.ExecCommandOnMachineConfigDaemon(ctx, &node, []string{"sysctl", "-n", param})
out, err = nodes.ExecCommandOnTestingDaemonPod(ctx, &node, []string{"sysctl", "-n", param})
Expect(err).ToNot(HaveOccurred())
Expect(strings.TrimSpace(string(out))).Should(Equal(expected), "parameter %s value is not %s.", param, expected)
}
Expand All @@ -1316,7 +1316,7 @@ func checkSchedKnobs(ctx context.Context, workerNodes []corev1.Node, schedKnobs
for param, expected := range schedKnobs {
By(fmt.Sprintf("Checking scheduler knob %s", param))
knob := fmt.Sprintf("/rootfs/sys/kernel/debug/sched/%s", param)
out, err = nodes.ExecCommandOnMachineConfigDaemon(ctx, &node, []string{"cat", knob})
out, err = nodes.ExecCommandOnTestingDaemonPod(ctx, &node, []string{"cat", knob})
Expect(err).ToNot(HaveOccurred())
Expect(strings.TrimSpace(string(out))).Should(Equal(expected), "parameter %s value is not %s.", param, expected)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ var _ = Describe("[rfe_id:49062][workloadHints] Telco friendly workload specific
mcps.WaitForCondition(performanceMCP, machineconfigv1.MachineConfigPoolUpdated, corev1.ConditionTrue)

By("Verifying node kernel arguments")
cmdline, err := nodes.ExecCommandOnMachineConfigDaemon(context.TODO(), &workerRTNodes[0], []string{"cat", "/proc/cmdline"})
cmdline, err := nodes.ExecCommandOnTestingDaemonPod(context.TODO(), &workerRTNodes[0], []string{"cat", "/proc/cmdline"})
Expect(err).ToNot(HaveOccurred())
Expect(cmdline).To(ContainSubstring("intel_pstate=passive"))
Expect(cmdline).ToNot(ContainSubstring("intel_pstate=disable"))
Expand Down
2 changes: 1 addition & 1 deletion test/e2e/performanceprofile/functests/9_reboot/devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ func waitForNodeReadyOrFail(tag, nodeName string, timeout, polling time.Duration

func runCommandOnNodeThroughMCD(ctx context.Context, node *corev1.Node, description, command string) (string, error) {
testlog.Infof("node %q: before %s", node.Name, description)
out, err := testnodes.ExecCommandOnMachineConfigDaemon(ctx, node, []string{"sh", "-c", command})
out, err := testnodes.ExecCommandOnTestingDaemonPod(ctx, node, []string{"sh", "-c", command})
testlog.Infof("node %q: output=[%s]", node.Name, string(out))
testlog.Infof("node %q: after %s", node.Name, description)
return string(out), err
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package clusterrole

import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// GetClusterRole returns a ClusterRole object with the specified parameters
func GetClusterRole(name string) *rbacv1.ClusterRole {
return &rbacv1.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
}
}

func WithRules(rules []rbacv1.PolicyRule) func(*rbacv1.ClusterRole) {
return func(cr *rbacv1.ClusterRole) {
cr.Rules = rules
}
}

func Make(name string, opts ...func(cr *rbacv1.ClusterRole)) *rbacv1.ClusterRole {
cr := GetClusterRole(name)
for _, opt := range opts {
opt(cr)
}
return cr
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package clusterrolebinding

import (
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// GetRoleBinding returns a RoleBinding object with the specified parameters
func GetRoleBinding(name, namespace, serviceAccountName, clusterRoleName string) *rbacv1.RoleBinding {
return &rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
Subjects: []rbacv1.Subject{
{
Kind: "ServiceAccount",
Name: serviceAccountName,
Namespace: namespace,
},
},
RoleRef: rbacv1.RoleRef{
Kind: "ClusterRole",
Name: clusterRoleName,
APIGroup: "rbac.authorization.k8s.io",
},
}
}
6 changes: 6 additions & 0 deletions test/e2e/performanceprofile/functests/utils/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ const (
// NamespaceTesting contains the name of the testing namespace
NamespaceTesting = "performance-addon-operators-testing"
)
const (
// TestingDaemonsetName contains the name of testing daemonset name
TestingDaemonsetName = "testing-daemonset"
// TestingDaemonsetNamespace contains the name of testing daemonset namespace
TestingDaemonsetNamespace = "testing-daemonset-ns"
)

const (
// FilePathKubeletConfig contains the kubelet.conf file path
Expand Down
Loading

0 comments on commit 43743a9

Please sign in to comment.