Skip to content

Commit

Permalink
virt-operator: Adding node restrictions e2e tests
Browse files Browse the repository at this point in the history
The tests will only run if validatingadmissionpolicies resource is
available on the cluster.

Signed-off-by: Ram Lavi <[email protected]>
  • Loading branch information
RamLavi committed Jun 5, 2024
1 parent a8dcb76 commit d8672f2
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
1 change: 1 addition & 0 deletions tests/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ go_test(
"//tests/testsuite:go_default_library",
"//tests/usb:go_default_library",
"//tests/util:go_default_library",
"//tests/validatingaddmisionpolicy:go_default_library",
"//tests/virtctl:go_default_library",
"//tests/virtiofs:go_default_library",
"//tests/watcher:go_default_library",
Expand Down
1 change: 1 addition & 0 deletions tests/tests_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import (
_ "kubevirt.io/kubevirt/tests/scale"
_ "kubevirt.io/kubevirt/tests/storage"
_ "kubevirt.io/kubevirt/tests/usb"
_ "kubevirt.io/kubevirt/tests/validatingaddmisionpolicy"
_ "kubevirt.io/kubevirt/tests/virtctl"
_ "kubevirt.io/kubevirt/tests/virtiofs"
)
Expand Down
18 changes: 18 additions & 0 deletions tests/validatingaddmisionpolicy/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")

go_library(
name = "go_default_library",
srcs = ["noderestrictions.go"],
importpath = "kubevirt.io/kubevirt/tests/validatingaddmisionpolicy",
visibility = ["//visibility:public"],
deps = [
"//pkg/virt-operator/resource/generate/components:go_default_library",
"//pkg/virt-operator/util:go_default_library",
"//tests/exec:go_default_library",
"//tests/framework/kubevirt:go_default_library",
"//tests/libnode:go_default_library",
"//vendor/github.com/onsi/ginkgo/v2:go_default_library",
"//vendor/github.com/onsi/gomega:go_default_library",
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
],
)
129 changes: 129 additions & 0 deletions tests/validatingaddmisionpolicy/noderestrictions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* This file is part of the KubeVirt project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* Copyright The KubeVirt Authors.
*
*/

package validatingaddmisionpolicy

import (
"context"
"fmt"
"strings"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

k8smetav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

"kubevirt.io/kubevirt/pkg/virt-operator/resource/generate/components"
"kubevirt.io/kubevirt/pkg/virt-operator/util"
"kubevirt.io/kubevirt/tests/exec"
"kubevirt.io/kubevirt/tests/framework/kubevirt"
"kubevirt.io/kubevirt/tests/libnode"
)

var _ = Describe("[sig-compute] virt-handler validationAdmissionPolicy", func() {
BeforeEach(func() {
virtClient := kubevirt.Client()
isValidatingAdmissionPolicyEnabled, err := util.IsValidatingAdmissionPolicyEnabled(virtClient)
Expect(err).ToNot(HaveOccurred())

if !isValidatingAdmissionPolicyEnabled {
Skip("test is verifying ValidatingAdmissionPolicy deployment")
}
})

BeforeEach(func() {
virtClient := kubevirt.Client()
nodesList, err := virtClient.CoreV1().Nodes().List(context.TODO(), k8smetav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())

for _, node := range nodesList.Items {
node.Labels["other.io/notAllowedLabel"] = "value"
node.Annotations["other.io/notAllowedAnnotation"] = "value"
virtClient.CoreV1().Nodes().Update(context.Background(), &node, k8smetav1.UpdateOptions{})
}
})
AfterEach(func() {
virtClient := kubevirt.Client()
nodesList, err := virtClient.CoreV1().Nodes().List(context.TODO(), k8smetav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())

for _, node := range nodesList.Items {
delete(node.Labels, "other.io/notAllowedLabel")
delete(node.Annotations, "other.io/notAllowedAnnotation")
virtClient.CoreV1().Nodes().Update(context.Background(), &node, k8smetav1.UpdateOptions{})
}
})

DescribeTable("reject not allowed patches to node", func(nodePatch, expectedErrMessage string) {
virtClient := kubevirt.Client()
nodesList, err := virtClient.CoreV1().Nodes().List(context.TODO(), k8smetav1.ListOptions{})
Expect(err).ToNot(HaveOccurred())

for _, node := range nodesList.Items {
tokenCommand := "cat /var/run/secrets/kubernetes.io/serviceaccount/token"
stdout, err := executeCommandInVirtHandlerPod(node.Name, strings.Fields(tokenCommand))
Expect(err).ToNot(HaveOccurred())
virtHandlerToken := stdout

serverAddressCommand := "printenv KUBERNETES_SERVICE_HOST KUBERNETES_SERVICE_PORT"
stdout, err = executeCommandInVirtHandlerPod(node.Name, strings.Fields(serverAddressCommand))
Expect(err).ToNot(HaveOccurred())
serverAddress := strings.ReplaceAll(strings.TrimSpace(stdout), "\n", ":")

By("directly sending an API node patch using virt-handler credentials")
nodeAPIEndpoint := fmt.Sprintf("/api/v1/nodes/%s", node.Name)
patchCommand := []string{
"curl",
"-k",
"-XPATCH",
fmt.Sprintf("https://%s%s", serverAddress, nodeAPIEndpoint),
"-H", fmt.Sprintf("Authorization: Bearer %s", virtHandlerToken),
"-H", "Content-Type: application/json-patch+json",
"-d", nodePatch,
}
stdout, err = executeCommandInVirtHandlerPod(node.Name, patchCommand)
Expect(err).ToNot(HaveOccurred())
Expect(stdout).To(ContainSubstring(expectedErrMessage), "node patch should failed on node specific node restriction")
}
},
Entry("should reject spec patch", `[{"op":"add", "path": "/spec/unschedulable","value":true}]`, components.NodeRestrictionErrModifySpec),
Entry("should reject not allowed metadata patch", `[{"op":"add", "path": "/metadata/finalizers","value":["kubernetes.io/evil-finalizer"]}]`, components.NodeRestrictionErrChangeMetadataFields),
Entry("should reject not allowed label addition", `[{"op":"add","path":"/metadata/labels/other.io~1newNotAllowedLabel","value":"value"}]`, components.NodeRestrictionErrAddDeleteLabels),
Entry("should reject not allowed label update", `[{"op":"replace","path":"/metadata/labels/other.io~1notAllowedLabel","value":"other-value"}]`, components.NodeRestrictionErrUpdateLabels),
Entry("should reject not allowed label removal", `[{"op":"remove","path":"/metadata/labels/other.io~1notAllowedLabel"}]`, components.NodeRestrictionErrAddDeleteLabels),
Entry("should reject not allowed annotation addition", `[{"op":"add","path":"/metadata/annotations/other.io~1newNotAllowedAnnotation","value":"value"}]`, components.NodeRestrictionErrAddDeleteAnnotations),
Entry("should reject not allowed annotation update", `[{"op":"replace","path":"/metadata/annotations/other.io~1notAllowedAnnotation","value":"value"}]`, components.NodeRestrictionErrUpdateAnnotations),
Entry("should reject not allowed annotation removal", `[{"op":"remove","path":"/metadata/annotations/other.io~1notAllowedAnnotation","value":"value"}]`, components.NodeRestrictionErrAddDeleteAnnotations),
)
})

func executeCommandInVirtHandlerPod(nodeName string, args []string) (stdout string, err error) {
virtClient := kubevirt.Client()

pod, err := libnode.GetVirtHandlerPod(virtClient, nodeName)
if err != nil {
return stdout, err
}

stdout, stderr, err := exec.ExecuteCommandOnPodWithResults(pod, "virt-handler", args)
if err != nil {
return stdout, fmt.Errorf("Failed excuting command=%v, error=%v, stdout=%s, stderr=%s", args, err, stdout, stderr)
}
return stdout, nil
}

0 comments on commit d8672f2

Please sign in to comment.