...

Source file src/k8s.io/kubernetes/test/e2e/windows/hyperv.go

Documentation: k8s.io/kubernetes/test/e2e/windows

     1  /*
     2  Copyright 2023 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package windows
    18  
    19  import (
    20  	"context"
    21  	"time"
    22  
    23  	"github.com/onsi/ginkgo/v2"
    24  	"github.com/onsi/gomega"
    25  	v1 "k8s.io/api/core/v1"
    26  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    27  	"k8s.io/kubernetes/test/e2e/feature"
    28  	"k8s.io/kubernetes/test/e2e/framework"
    29  	e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
    30  	e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper"
    31  	imageutils "k8s.io/kubernetes/test/utils/image"
    32  	admissionapi "k8s.io/pod-security-admission/api"
    33  )
    34  
    35  var (
    36  	WindowsHyperVContainerRuntimeClass = "runhcs-wcow-hypervisor"
    37  )
    38  
    39  var _ = sigDescribe(feature.WindowsHyperVContainers, "HyperV containers", skipUnlessWindows(func() {
    40  	ginkgo.BeforeEach(func() {
    41  		e2eskipper.SkipUnlessNodeOSDistroIs("windows")
    42  	})
    43  
    44  	f := framework.NewDefaultFramework("windows-hyperv-test")
    45  	f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
    46  
    47  	ginkgo.It("should start a hyperv isolated container", func(ctx context.Context) {
    48  
    49  		// HyperV isolated containers are only supported on containerd 1.7+
    50  		skipUnlessContainerdOneSevenOrGreater(ctx, f)
    51  
    52  		// check if hyperv runtime class is on node and skip otherwise
    53  		// Note: the runtime class is expected to be added to a cluster before running this test.
    54  		// see https://github.com/kubernetes-sigs/windows-testing/tree/master/helpers/hyper-v-mutating-webhook/hyperv-runtimeclass.yaml
    55  		// for an example.
    56  		_, err := f.ClientSet.NodeV1().RuntimeClasses().Get(ctx, WindowsHyperVContainerRuntimeClass, metav1.GetOptions{})
    57  		if err != nil {
    58  			framework.Logf("error getting runtime class: %v", err)
    59  			e2eskipper.Skipf("skipping test because runhcs-wcow-hypervisor runtime class is not present")
    60  		}
    61  
    62  		ginkgo.By("selecting a Windows node")
    63  		targetNode, err := findWindowsNode(ctx, f)
    64  		framework.ExpectNoError(err, "error finding Windows node")
    65  		framework.Logf("Using node: %v", targetNode.Name)
    66  
    67  		ginkgo.By("schedule a pod to that node")
    68  		image := imageutils.GetE2EImage(imageutils.BusyBox)
    69  		hypervPodName := "hyperv-test-pod"
    70  		hypervPod := &v1.Pod{
    71  			ObjectMeta: metav1.ObjectMeta{
    72  				Name: hypervPodName,
    73  			},
    74  			Spec: v1.PodSpec{
    75  				Containers: []v1.Container{
    76  					{
    77  						Image:   image,
    78  						Name:    "busybox-1",
    79  						Command: []string{"powershell.exe", "-Command", "Write-Host 'Hello'; sleep -Seconds 600"},
    80  					},
    81  					{
    82  						Image:   image,
    83  						Name:    "busybox-2",
    84  						Command: []string{"powershell.exe", "-Command", "Write-Host 'Hello'; sleep -Seconds 600"},
    85  					},
    86  				},
    87  				RestartPolicy:    v1.RestartPolicyNever,
    88  				RuntimeClassName: &WindowsHyperVContainerRuntimeClass,
    89  				NodeName:         targetNode.Name,
    90  			},
    91  		}
    92  
    93  		pc := e2epod.NewPodClient(f)
    94  
    95  		pc.Create(ctx, hypervPod)
    96  		ginkgo.By("waiting for the pod to be running")
    97  		timeout := 3 * time.Minute
    98  		e2epod.WaitForPodsRunningReady(ctx, f.ClientSet, f.Namespace.Name, 1, 0, timeout)
    99  
   100  		ginkgo.By("creating a host process container in another pod to verify the pod is running hyperv isolated containers")
   101  
   102  		// Note: each pod runs in a separate UVM so even though we are scheduling 2 containers in the test pod
   103  		// we should only expect a single UVM to be running on the host.
   104  		podName := "validation-pod"
   105  		pod := &v1.Pod{
   106  			ObjectMeta: metav1.ObjectMeta{
   107  				Name: podName,
   108  			},
   109  			Spec: v1.PodSpec{
   110  				SecurityContext: &v1.PodSecurityContext{
   111  					WindowsOptions: &v1.WindowsSecurityContextOptions{
   112  						HostProcess:   &trueVar,
   113  						RunAsUserName: &User_NTAuthoritySystem,
   114  					},
   115  				},
   116  				HostNetwork: true,
   117  				Containers: []v1.Container{
   118  					{
   119  						Image:   image,
   120  						Name:    "container",
   121  						Command: []string{"powershell.exe", "-Command", "$vms = Get-ComputeProcess | Where-Object { ($_.Type -EQ 'VirtualMachine') -and ($_.Owner -EQ 'containerd-shim-runhcs-v1.exe') } ; if ($vms.Length -le 0) { throw 'error' }"},
   122  					},
   123  				},
   124  				RestartPolicy: v1.RestartPolicyNever,
   125  				NodeName:      targetNode.Name,
   126  			},
   127  		}
   128  
   129  		pc.Create(ctx, pod)
   130  		ginkgo.By("waiting for the pod to be run")
   131  		pc.WaitForFinish(ctx, podName, timeout)
   132  
   133  		ginkgo.By("then ensuring pod finished running successfully")
   134  		p, err := f.ClientSet.CoreV1().Pods(f.Namespace.Name).Get(ctx, podName, metav1.GetOptions{})
   135  		framework.ExpectNoError(err, "error getting pod")
   136  
   137  		if p.Status.Phase != v1.PodSucceeded {
   138  			logs, err := e2epod.GetPodLogs(ctx, f.ClientSet, f.Namespace.Name, podName, "container")
   139  			if err != nil {
   140  				framework.Logf("Error pulling logs: %v", err)
   141  			}
   142  			framework.Logf("Pod phase: %v\nlogs:\n%s", p.Status.Phase, logs)
   143  		}
   144  
   145  		gomega.Expect(p.Status.Phase).To(gomega.Equal(v1.PodSucceeded), "pod should have succeeded")
   146  	})
   147  }))
   148  

View as plain text