jiebi/CodeConvo huggingface dataset:
} } <del> type testingMode interface { Fatalf(format string, args ...interface{}) } func makeBasePod(t testingMode, nodeName, objName, cpu, mem, extended string, ports []v1.ContainerPort, volumes []v1.Volume) *v1.Pod { req := v1.ResourceList{} if cpu != "" { req = v1.ResourceList{ v1.ResourceCPU:    resource.MustParse(cpu), v1.ResourceMemory: resource.MustParse(mem), } if extended != "" { parts := strings.Split(extended, ":") if len(parts) != 2 { t.Fatalf("Invalid extended resource string: "%s"", extended) } req[v1.ResourceName(parts[0])] = resource.MustParse(parts[1]) } } return &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ UID:       types.UID(objName), Namespace: "node_info_cache_test", Name:      objName, }, Spec: v1.PodSpec{ Containers: []v1.Container{{ Resources: v1.ResourceRequirements{ Requests: req, }, Ports: ports, }}, NodeName: nodeName, Volumes:  volumes, }, } } </del> func TestNewNodeInfo(t *testing.T) { nodeName := "test-node" pods := []*v1.Pod{ <del> makeBasePod(t, nodeName, "test-1", "100m", "500", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 80, Protocol: "TCP"}}, nil), makeBasePod(t, nodeName, "test-2", "200m", "1Ki", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 8080, Protocol: "TCP"}}, nil), </del> <ins> st.MakePod().UID("test-1").Namespace("node_info_cache_test").Name("test-1").Node(nodeName). Containers([]v1.Container{st.MakeContainer().ResourceRequests(map[v1.ResourceName]string{ v1.ResourceCPU:    "100m", v1.ResourceMemory: "500", }).ContainerPort([]v1.ContainerPort{{ HostIP:   "127.0.0.1", HostPort: 80, Protocol: "TCP", }}).Obj()}). Obj(), st.MakePod().UID("test-2").Namespace("node_info_cache_test").Name("test-2").Node(nodeName). Containers([]v1.Container{st.MakeContainer().ResourceRequests(map[v1.ResourceName]string{ v1.ResourceCPU:    "200m", v1.ResourceMemory: "1Ki", }).ContainerPort([]v1.ContainerPort{{ HostIP:   "127.0.0.1", HostPort: 8080, Protocol: "TCP", }}).Obj()}). Obj(), </ins> } expected := &NodeInfo{
func TestNodeInfoRemovePod(t *testing.T) { nodeName := "test-node" pods := []*v1.Pod{ <del> makeBasePod(t, nodeName, "test-1", "100m", "500", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 80, Protocol: "TCP"}}, []v1.Volume{{VolumeSource: v1.VolumeSource{PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: "pvc-1"}}}}), makeBasePod(t, nodeName, "test-2", "200m", "1Ki", "", []v1.ContainerPort{{HostIP: "127.0.0.1", HostPort: 8080, Protocol: "TCP"}}, nil), </del> <ins> st.MakePod().UID("test-1").Namespace("node_info_cache_test").Name("test-1").Node(nodeName). Containers([]v1.Container{st.MakeContainer().ResourceRequests(map[v1.ResourceName]string{ v1.ResourceCPU:    "100m", v1.ResourceMemory: "500", }).ContainerPort([]v1.ContainerPort{{ HostIP:   "127.0.0.1", HostPort: 80, Protocol: "TCP", }}).Obj()}). Volumes([]v1.Volume{{VolumeSource: v1.VolumeSource{PersistentVolumeClaim: &v1.PersistentVolumeClaimVolumeSource{ClaimName: "pvc-1"}}}}). Obj(), st.MakePod().UID("test-2").Namespace("node_info_cache_test").Name("test-2").Node(nodeName). Containers([]v1.Container{st.MakeContainer().ResourceRequests(map[v1.ResourceName]string{ v1.ResourceCPU:    "200m", v1.ResourceMemory: "1Ki", }).ContainerPort([]v1.ContainerPort{{ HostIP:   "127.0.0.1", HostPort: 8080, Protocol: "TCP", }}).Obj()}). Obj(), </ins> } // add pod Overhead
expectedNodeInfo *NodeInfo }{ { <del> pod:         makeBasePod(t, nodeName, "non-exist", "0", "0", "", []v1.ContainerPort{{}}, []v1.Volume{}), </del> <ins> pod:         st.MakePod().UID("non-exist").Namespace("node_info_cache_test").Node(nodeName).Obj(), </ins> errExpected: true, expectedNodeInfo: &NodeInfo{ node: &v1.Node{
return p } <ins> // Volumes set the volumes and inject into the inner pod. func (p *PodWrapper) Volumes(volumes []v1.Volume) *PodWrapper { p.Spec.Volumes = volumes return p } </ins> // SchedulingGates sets `gates` as additional SchedulerGates of the inner pod. func (p *PodWrapper) SchedulingGates(gates []string) *PodWrapper { for _, gate := range gates {
// This will start reconciliation of node.status.volumesInUse. rc.updateLastSyncTime() } <del> if len(rc.volumesNeedReportedInUse) != 0 && rc.populatorHasAddedPods() { // Once DSW is populated, mark all reconstructed as reported in node.status, // so they can proceed with MountDevice / SetUp. rc.desiredStateOfWorld.MarkVolumesReportedInUse(rc.volumesNeedReportedInUse) rc.volumesNeedReportedInUse = nil } </del> }
// Add the volumes to ASW rc.updateStates(reconstructedVolumes) <del> // The reconstructed volumes are mounted, hence a previous kubelet must have already put it into node.status.volumesInUse. // Remember to update DSW with this information. rc.volumesNeedReportedInUse = reconstructedVolumeNames </del> // Remember to update devicePath from node.status.volumesAttached rc.volumesNeedUpdateFromNodeStatus = reconstructedVolumeNames }
filepath.Join("pod1", "volumes", "fake-plugin", "pvc-abcdef"), filepath.Join("pod2", "volumes", "fake-plugin", "pvc-abcdef"), }, <del> expectedVolumesNeedReportedInUse:    []string{"fake-plugin/pvc-abcdef", "fake-plugin/pvc-abcdef"}, </del> expectedVolumesNeedDevicePath:       []string{"fake-plugin/pvc-abcdef", "fake-plugin/pvc-abcdef"}, expectedVolumesFailedReconstruction: []string{}, verifyFunc: func(rcInstance *reconciler, fakePlugin *volumetesting.FakeVolumePlugin) error {
t.Errorf("Expected expectedVolumesNeedDevicePath:n%vn got:n%v", expectedVolumes, rcInstance.volumesNeedUpdateFromNodeStatus) } <del> expectedVolumes = make([]v1.UniqueVolumeName, len(tc.expectedVolumesNeedReportedInUse)) for i := range tc.expectedVolumesNeedReportedInUse { expectedVolumes[i] = v1.UniqueVolumeName(tc.expectedVolumesNeedReportedInUse[i]) } if !reflect.DeepEqual(expectedVolumes, rcInstance.volumesNeedReportedInUse) { t.Errorf("Expected volumesNeedReportedInUse:n%vn got:n%v", expectedVolumes, rcInstance.volumesNeedReportedInUse) } </del> volumesFailedReconstruction := sets.NewString() for _, vol := range rcInstance.volumesFailedReconstruction { volumesFailedReconstruction.Insert(vol.volumeSpecName)
resourcev1alpha2 "k8s.io/api/resource/v1alpha2" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" <ins> "k8s.io/apimachinery/pkg/labels" </ins> "k8s.io/client-go/kubernetes" "k8s.io/dynamic-resource-allocation/controller" "k8s.io/klog/v2" "k8s.io/kubernetes/test/e2e/dra/test-driver/app" "k8s.io/kubernetes/test/e2e/framework" <ins> e2enode "k8s.io/kubernetes/test/e2e/framework/node" </ins> e2epod "k8s.io/kubernetes/test/e2e/framework/pod" admissionapi "k8s.io/pod-security-admission/api" utilpointer "k8s.io/utils/pointer"
framework.ExpectNoError(err, "start pod") } }) <ins> // This test covers aspects of non graceful node shutdown by DRA controller // More details about this can be found in the KEP: // https://github.com/kubernetes/enhancements/tree/master/keps/sig-storage/2268-non-graceful-shutdown // NOTE: this test depends on kind. It will only work with kind cluster as it shuts down one of the // nodes by running `docker stop <node name>`, which is very kind-specific. ginkgo.It("[Serial] [Disruptive] [Slow] must deallocate on non graceful node shutdown", func(ctx context.Context) { ginkgo.By("create test pod") parameters := b.parameters() label := "app.kubernetes.io/instance" instance := f.UniqueName + "-test-app" pod := b.podExternal() pod.Labels[label] = instance claim := b.externalClaim(resourcev1alpha2.AllocationModeWaitForFirstConsumer) b.create(ctx, parameters, claim, pod) ginkgo.By("wait for test pod " + pod.Name + " to run") labelSelector := labels.SelectorFromSet(labels.Set(pod.Labels)) pods, err := e2epod.WaitForPodsWithLabelRunningReady(ctx, f.ClientSet, pod.Namespace, labelSelector, 1, framework.PodStartTimeout) framework.ExpectNoError(err, "start pod") runningPod := &pods.Items[0] nodeName := runningPod.Spec.NodeName // Prevent builder tearDown to fail waiting for unprepared resources delete(b.driver.Nodes, nodeName) ginkgo.By("stop node " + nodeName + " non gracefully") _, stderr, err := framework.RunCmd("docker", "stop", nodeName) gomega.Expect(stderr).To(gomega.BeEmpty()) framework.ExpectNoError(err) ginkgo.DeferCleanup(framework.RunCmd, "docker", "start", nodeName) if ok := e2enode.WaitForNodeToBeNotReady(ctx, f.ClientSet, nodeName, f.Timeouts.NodeNotReady); !ok { framework.Failf("Node %s failed to enter NotReady state", nodeName) } ginkgo.By("apply out-of-service taint on node " + nodeName) taint := v1.Taint{ Key:    v1.TaintNodeOutOfService, Effect: v1.TaintEffectNoExecute, } e2enode.AddOrUpdateTaintOnNode(ctx, f.ClientSet, nodeName, taint) e2enode.ExpectNodeHasTaint(ctx, f.ClientSet, nodeName, &taint) ginkgo.DeferCleanup(e2enode.RemoveTaintOffNode, f.ClientSet, nodeName, taint) ginkgo.By("waiting for claim to get deallocated") gomega.Eventually(ctx, framework.GetObject(b.f.ClientSet.ResourceV1alpha2().ResourceClaims(b.f.Namespace.Name).Get, claim.Name, metav1.GetOptions{})).WithTimeout(f.Timeouts.PodDelete).Should(gomega.HaveField("Status.Allocation", gomega.BeNil())) }) </ins> }) ginkgo.Context("with node-local resources", func() {
} // remove old KMS provider <ins> // verifyIfKMSTransformersSwapped sometimes passes even before the changes in the encryption config file are observed. // this causes the metrics tests to fail, which validate two config changes. // this may happen when an existing KMS provider is already running (e.g., new-kms-provider-for-secrets in this case). // to ensure that the changes are observed, we added one more provider (kms-provider-to-encrypt-all) and are validating it in verifyIfKMSTransformersSwapped. </ins> encryptionConfigWithoutOldProvider := ` kind: EncryptionConfiguration apiVersion: apiserver.config.k8s.io/v1
name: new-kms-provider-for-configmaps cachesize: 1000 endpoint: unix:///@new-kms-provider.sock <ins> - resources: - '*.*' providers: - kms: name: kms-provider-to-encrypt-all cachesize: 1000 endpoint: unix:///@new-encrypt-all-kms-provider.sock - identity: {} </ins> ` <ins> // start new KMS Plugin _ = mock.NewBase64Plugin(t, "@new-encrypt-all-kms-provider.sock") </ins> // update encryption config and wait for hot reload if err := os.WriteFile(filepath.Join(test.configDir, encryptionConfigFileName), []byte(encryptionConfigWithoutOldProvider), 0644); err != nil { t.Fatalf("failed to update encryption config, err: %v", err) } <ins> wantPrefixForEncryptAll := "k8s:enc:kms:v1:kms-provider-to-encrypt-all:" </ins> // wait for config to be observed <del> verifyIfKMSTransformersSwapped(t, wantPrefixForSecrets, test) </del> <ins> verifyIfKMSTransformersSwapped(t, wantPrefixForSecrets, wantPrefixForEncryptAll, test) </ins> // confirm that reading secrets still works _, err = test.restClient.CoreV1().Secrets(testNamespace).Get(
func verifyPrefixOfSecretResource(t *testing.T, wantPrefix string, test *transformTest) { // implementing this brute force approach instead of fancy channel notification to avoid test specific code in prod. // wait for config to be observed <del> verifyIfKMSTransformersSwapped(t, wantPrefix, test) </del> <ins> verifyIfKMSTransformersSwapped(t, wantPrefix, "", test) </ins> // run storage migration secretsList, err := test.restClient.CoreV1().Secrets("").List(
return false, nil } <ins> if wantPrefixForEncryptAll != "" { deploymentName := fmt.Sprintf("deployment-%d", idx) _, err := test.createDeployment(deploymentName, "default") if err != nil { t.Fatalf("Failed to create test secret, error: %v", err) } rawEnvelope, err := test.readRawRecordFromETCD(test.getETCDPathForResource(test.storageConfig.Prefix, "", "deployments", deploymentName, "default")) if err != nil { t.Fatalf("failed to read %s from etcd: %v", test.getETCDPathForResource(test.storageConfig.Prefix, "", "deployments", deploymentName, "default"), err) } // check prefix if !bytes.HasPrefix(rawEnvelope.Kvs[0].Value, []byte(wantPrefixForEncryptAll)) { idx++ swapErr = fmt.Errorf("expected deployment to be prefixed with %s, but got %s", wantPrefixForEncryptAll, rawEnvelope.Kvs[0].Value) // return nil error to continue polling till timeout return false, nil } } </ins> return true, nil }) if pollErr == wait.ErrWaitTimeout {
// start new KMS Plugin _ = mock.NewBase64Plugin(t, "@new-kms-provider.sock") // update encryption config <del> if err := os.WriteFile(filepath.Join(test.configDir, encryptionConfigFileName), []byte(encryptionConfigWithNewProvider), 0644); err != nil { t.Fatalf("failed to update encryption config, err: %v", err) } </del> <ins> updateFile(t, test.configDir, encryptionConfigFileName, []byte(encryptionConfigWithNewProvider)) </ins> wantPrefixForSecrets := "k8s:enc:kms:v1:new-kms-provider-for-secrets:" // implementing this brute force approach instead of fancy channel notification to avoid test specific code in prod. // wait for config to be observed <del> verifyIfKMSTransformersSwapped(t, wantPrefixForSecrets, "", test) </del> <ins> verifyIfKMSTransformersSwapped(t, wantPrefixForSecrets, test) </ins> // run storage migration // get secrets
} // remove old KMS provider <del> // verifyIfKMSTransformersSwapped sometimes passes even before the changes in the encryption config file are observed. // this causes the metrics tests to fail, which validate two config changes. // this may happen when an existing KMS provider is already running (e.g., new-kms-provider-for-secrets in this case). // to ensure that the changes are observed, we added one more provider (kms-provider-to-encrypt-all) and are validating it in verifyIfKMSTransformersSwapped. </del> encryptionConfigWithoutOldProvider := ` kind: EncryptionConfiguration apiVersion: apiserver.config.k8s.io/v1
name: new-kms-provider-for-configmaps cachesize: 1000 endpoint: unix:///@new-kms-provider.sock <del> - resources: - '*.*' providers: - kms: name: kms-provider-to-encrypt-all cachesize: 1000 endpoint: unix:///@new-encrypt-all-kms-provider.sock - identity: {} </del> ` <del> // start new KMS Plugin _ = mock.NewBase64Plugin(t, "@new-encrypt-all-kms-provider.sock") </del> // update encryption config and wait for hot reload <del> if err := os.WriteFile(filepath.Join(test.configDir, encryptionConfigFileName), []byte(encryptionConfigWithoutOldProvider), 0644); err != nil { t.Fatalf("failed to update encryption config, err: %v", err) } wantPrefixForEncryptAll := "k8s:enc:kms:v1:kms-provider-to-encrypt-all:" </del> <ins> updateFile(t, test.configDir, encryptionConfigFileName, []byte(encryptionConfigWithoutOldProvider)) </ins> // wait for config to be observed <del> verifyIfKMSTransformersSwapped(t, wantPrefixForSecrets, wantPrefixForEncryptAll, test) </del> <ins> verifyIfKMSTransformersSwapped(t, wantPrefixForSecrets, test) </ins> // confirm that reading secrets still works _, err = test.restClient.CoreV1().Secrets(testNamespace).Get(
func verifyPrefixOfSecretResource(t *testing.T, wantPrefix string, test *transformTest) { // implementing this brute force approach instead of fancy channel notification to avoid test specific code in prod. // wait for config to be observed <del> verifyIfKMSTransformersSwapped(t, wantPrefix, "", test) </del> <ins> verifyIfKMSTransformersSwapped(t, wantPrefix, test) </ins> // run storage migration secretsList, err := test.restClient.CoreV1().Secrets("").List(
return false, nil } <del> if wantPrefixForEncryptAll != "" { deploymentName := fmt.Sprintf("deployment-%d", idx) _, err := test.createDeployment(deploymentName, "default") if err != nil { t.Fatalf("Failed to create test secret, error: %v", err) } rawEnvelope, err := test.readRawRecordFromETCD(test.getETCDPathForResource(test.storageConfig.Prefix, "", "deployments", deploymentName, "default")) if err != nil { t.Fatalf("failed to read %s from etcd: %v", test.getETCDPathForResource(test.storageConfig.Prefix, "", "deployments", deploymentName, "default"), err) } // check prefix if !bytes.HasPrefix(rawEnvelope.Kvs[0].Value, []byte(wantPrefixForEncryptAll)) { idx++ swapErr = fmt.Errorf("expected deployment to be prefixed with %s, but got %s", wantPrefixForEncryptAll, rawEnvelope.Kvs[0].Value) // return nil error to continue polling till timeout return false, nil } } </del> return true, nil }) if pollErr == wait.ErrWaitTimeout {
} } <ins> func updateFile(t *testing.T, configDir, filename string, newContent []byte) { t.Helper() // Create a temporary file tempFile, err := os.CreateTemp(configDir, "tempfile") if err != nil { t.Fatal(err) } defer tempFile.Close() // Write the new content to the temporary file _, err = tempFile.Write(newContent) if err != nil { t.Fatal(err) } // Atomically replace the original file with the temporary file err = os.Rename(tempFile.Name(), filepath.Join(configDir, filename)) if err != nil { t.Fatal(err) } } </ins> func TestKMSHealthz(t *testing.T) { encryptionConfig := ` kind: EncryptionConfiguration
"k8s.io/apimachinery/pkg/util/uuid" netutils "k8s.io/utils/net" <ins> utilfeature "k8s.io/apiserver/pkg/util/feature" </ins> kubefeatures "k8s.io/kubernetes/pkg/features" kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config" "k8s.io/kubernetes/test/e2e/framework"
e2enode "k8s.io/kubernetes/test/e2e/framework/node" e2epod "k8s.io/kubernetes/test/e2e/framework/pod" e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output" <ins> e2eskipper "k8s.io/kubernetes/test/e2e/framework/skipper" </ins> "k8s.io/kubernetes/test/e2e/network/common" imageutils "k8s.io/kubernetes/test/utils/image" <ins> admissionapi "k8s.io/pod-security-admission/api" </ins> ) <del> var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() { </del> <ins> var _ = common.SIGDescribe("DualStack Host IP [Serial] [NodeFeature:PodHostIPs] [Feature:PodHostIPs]", func() { </ins> f := framework.NewDefaultFramework("dualstack") <ins> f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged </ins> ginkgo.Context("when creating a Pod, it has no PodHostIPs feature", func() { tempSetCurrentKubeletConfig(f, func(ctx context.Context, initialConfig *kubeletconfig.KubeletConfiguration) {
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil()) ginkgo.By("deleting the pod") <del> err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30)) </del> <ins> err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1)) </ins> framework.ExpectNoError(err, "failed to delete pod") })
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil()) ginkgo.By("deleting the pod") <del> err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30)) </del> <ins> err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1)) </ins> framework.ExpectNoError(err, "failed to delete pod") }) })
podName := "pod-dualstack-host-ips" <del> pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:   podName, Labels: map[string]string{"test": "dualstack-host-ips"}, }, Spec: v1.PodSpec{ Containers: []v1.Container{ { Name:  "dualstack-host-ips", Image: imageutils.GetE2EImage(imageutils.Agnhost), }, }, }, } </del> <ins> pod := genPodHostIPs(podName+string(uuid.NewUUID()), false) </ins> ginkgo.By("submitting the pod to kubernetes") podClient := e2epod.NewPodClient(f)
podName := "pod-dualstack-host-ips" <del> pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:   podName, Labels: map[string]string{"test": "dualstack-host-ips"}, }, Spec: v1.PodSpec{ Containers: []v1.Container{ { Name:  "dualstack-host-ips", Image: imageutils.GetE2EImage(imageutils.Agnhost), }, }, HostNetwork: true, }, } </del> <ins> pod := genPodHostIPs(podName+string(uuid.NewUUID()), true) </ins> ginkgo.By("submitting the pod to kubernetes") podClient := e2epod.NewPodClient(f)
} ginkgo.By("deleting the pod") <del> err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30)) </del> <ins> err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1)) </ins> framework.ExpectNoError(err, "failed to delete pod") }) ginkgo.It("should provide hostIPs as an env var", func(ctx context.Context) { <ins> if !utilfeature.DefaultFeatureGate.Enabled(kubefeatures.PodHostIPs) { e2eskipper.Skipf("PodHostIPs feature is not enabled") } </ins> podName := "downward-api-" + string(uuid.NewUUID()) env := []v1.EnvVar{ {
testDownwardAPI(ctx, f, podName, env, expectations) }) }) <ins> ginkgo.Context("when feature rollback", func() { tempSetCurrentKubeletConfig(f, func(ctx context.Context, initialConfig *kubeletconfig.KubeletConfiguration) { initialConfig.FeatureGates = map[string]bool{ string(kubefeatures.PodHostIPs): true, } }) ginkgo.It("should able upgrade and rollback", func(ctx context.Context) { podName := "pod-dualstack-host-ips" pod := genPodHostIPs(podName+string(uuid.NewUUID()), false) ginkgo.By("submitting the pod to kubernetes") podClient := e2epod.NewPodClient(f) p := podClient.CreateSync(ctx, pod) gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil()) ginkgo.By("Disable PodHostIPs feature") cfg, err := getCurrentKubeletConfig(ctx) framework.ExpectNoError(err) newCfg := cfg.DeepCopy() newCfg.FeatureGates = map[string]bool{ string(kubefeatures.PodHostIPs): false, } updateKubeletConfig(ctx, f, newCfg, true) gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil()) ginkgo.By("deleting the pod") err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1)) framework.ExpectNoError(err, "failed to delete pod") ginkgo.By("recreate pod") pod = genPodHostIPs(podName+string(uuid.NewUUID()), false) p = podClient.CreateSync(ctx, pod) // Feature PodHostIPs is disabled, HostIPs should be nil gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil()) newCfg.FeatureGates = map[string]bool{ string(kubefeatures.PodHostIPs): true, } updateKubeletConfig(ctx, f, newCfg, true) p, err = podClient.Get(ctx, pod.Name, metav1.GetOptions{}) framework.ExpectNoError(err) // Feature PodHostIPs is enabled, HostIPs should not be nil gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil()) ginkgo.By("deleting the pod") err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1)) framework.ExpectNoError(err, "failed to delete pod") }) }) </ins> }) <ins> func genPodHostIPs(podName string, hostNetwork bool) *v1.Pod { return &v1.Pod{ ObjectMeta: metav1.ObjectMeta{ Name:   podName, Labels: map[string]string{"test": "dualstack-host-ips"}, }, Spec: v1.PodSpec{ Containers: []v1.Container{ { Name:  "test-container", Image: imageutils.GetE2EImage(imageutils.Agnhost), }, }, RestartPolicy: v1.RestartPolicyNever, HostNetwork:   hostNetwork, }, } } </ins> func testDownwardAPI(ctx context.Context, f *framework.Framework, podName string, env []v1.EnvVar, expectations []string) { pod := &v1.Pod{ ObjectMeta: metav1.ObjectMeta{