diff --git a/test/e2e/feature/feature.go b/test/e2e/feature/feature.go index 9448f6590a6..a3fb6edc20a 100644 --- a/test/e2e/feature/feature.go +++ b/test/e2e/feature/feature.go @@ -368,7 +368,9 @@ var ( // TODO: document the feature (owning SIG, when to use this feature for a test) StackdriverMonitoring = framework.WithFeature(framework.ValidFeatures.Add("StackdriverMonitoring")) - // TODO: document the feature (owning SIG, when to use this feature for a test) + // Tests marked with this feature require the kubelet to be running in standalone mode (--standalone-mode=true) like this: + // make test-e2e-node PARALLELISM=1 FOCUS="StandaloneMode" TEST_ARGS='--kubelet-flags="--fail-swap-on=false" --standalone-mode=true' + // Tests validating the behavior of kubelet when running without the API server. StandaloneMode = framework.WithFeature(framework.ValidFeatures.Add("StandaloneMode")) // TODO: document the feature (owning SIG, when to use this feature for a test) diff --git a/test/e2e_node/standalone_test.go b/test/e2e_node/standalone_test.go index 72eb293823f..51cf0b8f3c2 100644 --- a/test/e2e_node/standalone_test.go +++ b/test/e2e_node/standalone_test.go @@ -56,18 +56,18 @@ var _ = SIGDescribe(feature.StandaloneMode, func() { staticPodName = "static-pod-" + string(uuid.NewUUID()) podPath = kubeletCfg.StaticPodPath - err := createBasicStaticPod(podPath, staticPodName, ns) + err := scheduleStaticPod(podPath, staticPodName, ns, createBasicStaticPodSpec(staticPodName, ns)) framework.ExpectNoError(err) gomega.Eventually(ctx, func(ctx context.Context) error { pod, err := getPodFromStandaloneKubelet(ctx, ns, staticPodName) if err != nil { - return fmt.Errorf("error getting pod(%v/%v) from standalone kubelet: %v", ns, staticPodName, err) + return fmt.Errorf("error getting pod(%v/%v) from standalone kubelet: %w", ns, staticPodName, err) } isReady, err := testutils.PodRunningReady(pod) if err != nil { - return fmt.Errorf("error checking if pod (%v/%v) is running ready: %v", ns, staticPodName, err) + return fmt.Errorf("error checking if pod (%v/%v) is running ready: %w", ns, staticPodName, err) } if !isReady { return fmt.Errorf("pod (%v/%v) is not running", ns, staticPodName) @@ -76,6 +76,124 @@ var _ = SIGDescribe(feature.StandaloneMode, func() { }, f.Timeouts.PodStart, time.Second*5).Should(gomega.BeNil()) }) + ginkgo.It("the pod with the port on host network should be running and can be upgraded when the container name changes", func(ctx context.Context) { + ns = f.Namespace.Name + staticPodName = "static-pod-" + string(uuid.NewUUID()) + podPath = kubeletCfg.StaticPodPath + + podSpec := createBasicStaticPodSpec(staticPodName, ns) + podSpec.Spec.HostNetwork = true + podSpec.Spec.Containers[0].Ports = []v1.ContainerPort{ + { + Name: "tcp", + ContainerPort: 4534, + Protocol: v1.ProtocolTCP, + }, + } + err := scheduleStaticPod(podPath, staticPodName, ns, podSpec) + framework.ExpectNoError(err) + + gomega.Eventually(ctx, func(ctx context.Context) error { + pod, err := getPodFromStandaloneKubelet(ctx, ns, staticPodName) + if err != nil { + return fmt.Errorf("error getting pod(%v/%v) from standalone kubelet: %w", ns, staticPodName, err) + } + + isReady, err := testutils.PodRunningReady(pod) + if err != nil { + return fmt.Errorf("error checking if pod (%v/%v) is running ready: %w", ns, staticPodName, err) + } + if !isReady { + return fmt.Errorf("pod (%v/%v) is not running", ns, staticPodName) + } + return nil + }, f.Timeouts.PodStart, time.Second*5).Should(gomega.BeNil()) + + // Upgrade the pod + podSpec.Spec.Containers[0].Name = "upgraded" + err = scheduleStaticPod(podPath, staticPodName, ns, podSpec) + framework.ExpectNoError(err) + + gomega.Eventually(ctx, func(ctx context.Context) error { + pod, err := getPodFromStandaloneKubelet(ctx, ns, staticPodName) + if err != nil { + return fmt.Errorf("error getting pod(%v/%v) from standalone kubelet: %w", ns, staticPodName, err) + } + + if pod.Spec.Containers[0].Name != "upgraded" { + return fmt.Errorf("pod (%v/%v) is not upgraded", ns, staticPodName) + } + + isReady, err := testutils.PodRunningReady(pod) + if err != nil { + return fmt.Errorf("error checking if pod (%v/%v) is running ready: %w", ns, staticPodName, err) + } + if !isReady { + return fmt.Errorf("pod (%v/%v) is not running", ns, staticPodName) + } + return nil + }, f.Timeouts.PodStart, time.Second*5).Should(gomega.BeNil()) + }) + + // the test below is not working - pod update fails with the "Predicate NodePorts failed: node(s) didn't have free ports for the requested pod ports" + // ginkgo.It("the pod with the port on host network should be running and can be upgraded when namespace of a Pod changes", func(ctx context.Context) { + // ns = f.Namespace.Name + // staticPodName = "static-pod-" + string(uuid.NewUUID()) + // podPath = kubeletCfg.StaticPodPath + + // podSpec := createBasicStaticPodSpec(staticPodName, ns) + // podSpec.Spec.HostNetwork = true + // podSpec.Spec.Containers[0].Ports = []v1.ContainerPort{ + // { + // Name: "tcp", + // ContainerPort: 4534, + // Protocol: v1.ProtocolTCP, + // }, + // } + // err := scheduleStaticPod(podPath, staticPodName, ns, podSpec) + // framework.ExpectNoError(err) + + // gomega.Eventually(ctx, func(ctx context.Context) error { + // pod, err := getPodFromStandaloneKubelet(ctx, ns, staticPodName) + // if err != nil { + // return fmt.Errorf("error getting pod(%v/%v) from standalone kubelet: %w", ns, staticPodName, err) + // } + + // isReady, err := testutils.PodRunningReady(pod) + // if err != nil { + // return fmt.Errorf("error checking if pod (%v/%v) is running ready: %w", ns, staticPodName, err) + // } + // if !isReady { + // return fmt.Errorf("pod (%v/%v) is not running", ns, staticPodName) + // } + // return nil + // }, f.Timeouts.PodStart, time.Second*5).Should(gomega.BeNil()) + + // // Upgrade the pod + // upgradedNs := ns + "-upgraded" + // podSpec.Namespace = upgradedNs + + // // use old namespace as it uses ns in a file name + // err = scheduleStaticPod(podPath, staticPodName, ns, podSpec) + // framework.ExpectNoError(err) + + // gomega.Eventually(ctx, func(ctx context.Context) error { + // pod, err := getPodFromStandaloneKubelet(ctx, upgradedNs, staticPodName) + // if err != nil { + // return fmt.Errorf("error getting pod(%v/%v) from standalone kubelet: %w", upgradedNs, staticPodName, err) + // } + + // isReady, err := testutils.PodRunningReady(pod) + // if err != nil { + // return fmt.Errorf("error checking if pod (%v/%v) is running ready: %w", upgradedNs, staticPodName, err) + // } + // if !isReady { + // return fmt.Errorf("pod (%v/%v) is not running", upgradedNs, staticPodName) + // } + // return nil + // }, f.Timeouts.PodStart, time.Second*5).Should(gomega.BeNil()) + // }) + ginkgo.AfterEach(func(ctx context.Context) { ginkgo.By(fmt.Sprintf("delete the static pod (%v/%v)", ns, staticPodName)) err := deleteStaticPod(podPath, staticPodName, ns) @@ -94,7 +212,7 @@ var _ = SIGDescribe(feature.StandaloneMode, func() { }) }) -func createBasicStaticPod(dir, name, namespace string) error { +func createBasicStaticPodSpec(name, namespace string) *v1.Pod { podSpec := &v1.Pod{ TypeMeta: metav1.TypeMeta{ Kind: "Pod", @@ -135,6 +253,10 @@ func createBasicStaticPod(dir, name, namespace string) error { }, } + return podSpec +} + +func scheduleStaticPod(dir, name, namespace string, podSpec *v1.Pod) error { file := staticPodPath(dir, name, namespace) f, err := os.OpenFile(file, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0666) if err != nil {