-
Notifications
You must be signed in to change notification settings - Fork 105
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added node inspector for inspecting nodes configuration
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 introduces a node inspector implemented as a daemonset. Upon execution of test suites, a pod with elevated privileges and host filesystem mounted will be deployed on every node. Also I have added Z-deconfig suite ('Z' prefix, will guarantee that it will be the last suite run) that will be used for cleanup. This API will be used for both hypershift and non-hypershift systems. Signed-off-by: Ronny Baturov <[email protected]>
- Loading branch information
Showing
7 changed files
with
269 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
13 changes: 13 additions & 0 deletions
13
test/e2e/performanceprofile/functests/Z_deconfig/Z_deconfig_suite_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
package Z_deconfig_test | ||
|
||
import ( | ||
"testing" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
) | ||
|
||
func TestZDeconfig(t *testing.T) { | ||
RegisterFailHandler(Fail) | ||
RunSpecs(t, "ZDeconfig Suite") | ||
} |
27 changes: 27 additions & 0 deletions
27
test/e2e/performanceprofile/functests/Z_deconfig/deconfig.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package Z_deconfig | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
. "github.com/onsi/ginkgo/v2" | ||
. "github.com/onsi/gomega" | ||
|
||
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" | ||
nodeInspector "github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/node_inspector" | ||
"github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/namespaces" | ||
) | ||
|
||
// This test suite is designed to perform cleanup actions that should occur after all test suites have been executed. | ||
|
||
var _ = Describe("Deconfig", func() { | ||
It("Should delete the node inspector and its namespace", func() { | ||
err := nodeInspector.Delete(testclient.Client, testutils.NodeInspectorNamespace, testutils.NodeInspectorName) | ||
Expect(err).ToNot(HaveOccurred()) | ||
err = testclient.DataPlaneClient.Delete(context.TODO(), namespaces.NodeInspectorNamespace) | ||
Expect(err).ToNot(HaveOccurred()) | ||
err = namespaces.WaitForDeletion(testutils.NodeInspectorNamespace, 5*time.Minute) | ||
Expect(err).ToNot(HaveOccurred()) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
199 changes: 199 additions & 0 deletions
199
test/e2e/performanceprofile/functests/utils/node_inspector/inspector.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,199 @@ | ||
package node_inspector | ||
|
||
import ( | ||
"context" | ||
|
||
appsv1 "k8s.io/api/apps/v1" | ||
corev1 "k8s.io/api/core/v1" | ||
rbacv1 "k8s.io/api/rbac/v1" | ||
"k8s.io/apimachinery/pkg/api/errors" | ||
"k8s.io/apimachinery/pkg/api/resource" | ||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
"k8s.io/utils/pointer" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
|
||
"github.com/openshift/cluster-node-tuning-operator/test/e2e/performanceprofile/functests/utils/daemonset" | ||
) | ||
|
||
const serviceAccountSuffix = "sa" | ||
const clusterRoleSuffix = "cr" | ||
const clusterRoleBindingSuffix = "crb" | ||
|
||
func Create(cli client.Client, namespace, name, image string) error { | ||
serviceAccountName := name + serviceAccountSuffix | ||
sa := createServiceAccount(serviceAccountName, namespace) | ||
if err := cli.Create(context.Background(), sa); err != nil && !errors.IsAlreadyExists(err) { | ||
return err | ||
} | ||
clusterRoleName := name + clusterRoleSuffix | ||
cr := createClusterRole(clusterRoleName) | ||
if err := cli.Create(context.Background(), cr); err != nil && !errors.IsAlreadyExists(err) { | ||
return err | ||
} | ||
clusterRoleBindingName := name + clusterRoleBindingSuffix | ||
rb := createClusterRoleBinding(clusterRoleBindingName, namespace, serviceAccountName, clusterRoleName) | ||
if err := cli.Create(context.Background(), rb); err != nil && !errors.IsAlreadyExists(err) { | ||
return err | ||
} | ||
ds := createDaemonSet(name, namespace, serviceAccountName, image) | ||
if err := cli.Create(context.Background(), ds); err != nil && !errors.IsAlreadyExists(err) { | ||
return err | ||
} | ||
if err := daemonset.WaitToBeRunning(cli, namespace, name); err != nil { | ||
return err | ||
} | ||
|
||
return nil | ||
} | ||
|
||
func Delete(cli client.Client, namespace, name string) error { | ||
ds := &appsv1.DaemonSet{ObjectMeta: metav1.ObjectMeta{Name: name, Namespace: namespace}} | ||
if err := cli.Delete(context.Background(), ds); err != nil && !errors.IsNotFound(err) { | ||
return err | ||
} | ||
sa := &corev1.ServiceAccount{ObjectMeta: metav1.ObjectMeta{Name: name + serviceAccountSuffix, Namespace: namespace}} | ||
if err := cli.Delete(context.Background(), sa); err != nil && !errors.IsNotFound(err) { | ||
return err | ||
} | ||
crb := &rbacv1.ClusterRoleBinding{ObjectMeta: metav1.ObjectMeta{Name: name + clusterRoleBindingSuffix, Namespace: namespace}} | ||
if err := cli.Delete(context.Background(), crb); err != nil && !errors.IsNotFound(err) { | ||
return err | ||
} | ||
cr := &rbacv1.ClusterRole{ObjectMeta: metav1.ObjectMeta{Name: name + clusterRoleSuffix}} | ||
if err := cli.Delete(context.Background(), cr); err != nil && !errors.IsNotFound(err) { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func IsRunning(cli client.Client, namespace, name string) (bool,error){ | ||
return daemonset.IsRunning(cli, namespace, name) | ||
} | ||
|
||
func createDaemonSet(name, namespace, serviceAccountName, image string) *appsv1.DaemonSet { | ||
MountPropagationHostToContainer := corev1.MountPropagationHostToContainer | ||
return &appsv1.DaemonSet{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: name, | ||
Namespace: namespace, | ||
Labels: map[string]string{ | ||
"name": name, | ||
}, | ||
}, | ||
Spec: appsv1.DaemonSetSpec{ | ||
Selector: &metav1.LabelSelector{ | ||
MatchLabels: map[string]string{ | ||
"name": name, | ||
}, | ||
}, | ||
Template: corev1.PodTemplateSpec{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Annotations: map[string]string{ | ||
"target.workload.openshift.io/management": `{"effect": "PreferredDuringScheduling"}`, | ||
}, | ||
Labels: map[string]string{ | ||
"name": name, | ||
}, | ||
}, | ||
Spec: corev1.PodSpec{ | ||
HostPID: true, | ||
HostNetwork: true, | ||
ServiceAccountName: serviceAccountName, | ||
TerminationGracePeriodSeconds: pointer.Int64(0), | ||
NodeSelector: map[string]string{"kubernetes.io/os": "linux"}, | ||
Containers: []corev1.Container{ | ||
{ | ||
Name: "node-daemon", | ||
Image: image, | ||
Command: []string{"/bin/bash", "-c", "sleep INF"}, | ||
ImagePullPolicy: corev1.PullAlways, | ||
Resources: corev1.ResourceRequirements{ | ||
Requests: corev1.ResourceList{ | ||
"cpu": resource.MustParse("20m"), | ||
"memory": resource.MustParse("50Mi"), | ||
}, | ||
}, | ||
SecurityContext: &corev1.SecurityContext{ | ||
Privileged: pointer.Bool(true), | ||
ReadOnlyRootFilesystem: pointer.Bool(true), | ||
}, | ||
VolumeMounts: []corev1.VolumeMount{ | ||
{ | ||
MountPath: "/rootfs", | ||
Name: "rootfs", | ||
MountPropagation: &MountPropagationHostToContainer, | ||
}, | ||
}, | ||
}, | ||
}, | ||
Volumes: []corev1.Volume{ | ||
{ | ||
Name: "rootfs", | ||
VolumeSource: corev1.VolumeSource{ | ||
HostPath: &corev1.HostPathVolumeSource{ | ||
Path: "/", | ||
}, | ||
}, | ||
}, | ||
}, | ||
Tolerations: []corev1.Toleration{ | ||
{ | ||
Operator: corev1.TolerationOpExists, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func createServiceAccount(name, namespace string) *corev1.ServiceAccount { | ||
return &corev1.ServiceAccount{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: name, | ||
Namespace: namespace, | ||
}, | ||
} | ||
} | ||
|
||
func createClusterRole(name string) *rbacv1.ClusterRole { | ||
return &rbacv1.ClusterRole{ | ||
ObjectMeta: metav1.ObjectMeta{ | ||
Name: name, | ||
}, | ||
Rules: []rbacv1.PolicyRule{ | ||
{ | ||
APIGroups: []string{""}, | ||
Resources: []string{"nodes"}, | ||
Verbs: []string{"get", "list", "watch"}, | ||
}, | ||
{ | ||
APIGroups: []string{"security.openshift.io"}, | ||
ResourceNames: []string{"privileged"}, | ||
Resources: []string{"securitycontextconstraints"}, | ||
Verbs: []string{"use"}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func createClusterRoleBinding(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", | ||
}, | ||
} | ||
} |