diff --git a/test/e2e/framework/constant.go b/test/e2e/framework/constant.go index 170110cb0..39d61f43e 100644 --- a/test/e2e/framework/constant.go +++ b/test/e2e/framework/constant.go @@ -23,4 +23,6 @@ const ( pollInterval = 5 * time.Second // pollTimeout defines the time after which the poll operation times out. pollTimeout = 420 * time.Second + // metricsCreationDelay defines the maximum time metrics not yet available for pod. + metricsCreationDelay = 2 * time.Minute ) diff --git a/test/e2e/framework/pod.go b/test/e2e/framework/pod.go index 2880d4942..3fa653b9f 100644 --- a/test/e2e/framework/pod.go +++ b/test/e2e/framework/pod.go @@ -29,6 +29,11 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/klog/v2" + metricsclientset "k8s.io/metrics/pkg/client/clientset/versioned" + + clusterv1alpha1 "github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1" + karmada "github.com/karmada-io/karmada/pkg/generated/clientset/versioned" + "github.com/karmada-io/karmada/pkg/util" ) // CreatePod create Pod. @@ -62,6 +67,32 @@ func WaitPodPresentOnClusterFitWith(cluster, namespace, name string, fit func(po }, pollTimeout, pollInterval).Should(gomega.Equal(true)) } +// WaitPodMetricsReady wait podMetrics to be ready. +func WaitPodMetricsReady(kubeClient kubernetes.Interface, karmadaClient karmada.Interface, cluster, namespace, name string) { + clusterGetter := func(cluster string) (*clusterv1alpha1.Cluster, error) { + return karmadaClient.ClusterV1alpha1().Clusters().Get(context.Background(), cluster, metav1.GetOptions{}) + } + secretGetter := func(namespace string, name string) (*corev1.Secret, error) { + return kubeClient.CoreV1().Secrets(namespace).Get(context.Background(), name, metav1.GetOptions{}) + } + config, err := util.BuildClusterConfig(cluster, clusterGetter, secretGetter) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + metricsClient, err := metricsclientset.NewForConfig(config) + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + gomega.Eventually(func() bool { + _, err = metricsClient.MetricsV1beta1().PodMetricses(namespace).Get(context.TODO(), name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + klog.Infof("Metrics not yet available for pod %s/%s", namespace, name) + return false + } + klog.Errorf("Metrics not available for pod %s/%s", namespace, name) + return false + } + return true + }, metricsCreationDelay, pollInterval).Should(gomega.Equal(true)) +} + // WaitPodPresentOnClustersFitWith wait pod present on cluster sync with fit func. func WaitPodPresentOnClustersFitWith(clusters []string, namespace, name string, fit func(pod *corev1.Pod) bool) { ginkgo.By(fmt.Sprintf("Waiting for pod(%s/%s) synced on member clusters", namespace, name), func() { diff --git a/test/e2e/karmadactl_test.go b/test/e2e/karmadactl_test.go index 6a74bc367..f946ce17c 100644 --- a/test/e2e/karmadactl_test.go +++ b/test/e2e/karmadactl_test.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "os" + "strings" "time" "github.com/onsi/ginkgo/v2" @@ -538,3 +539,79 @@ var _ = ginkgo.Describe("Karmadactl exec testing", func() { } }) }) + +var _ = ginkgo.Describe("Karmadactl top testing", ginkgo.Labels{NeedCreateCluster}, func() { + ginkgo.Context("Karmadactl top pod which does not exist", func() { + ginkgo.It("Karmadactl top pod which does not exist", func() { + podName := podNamePrefix + rand.String(RandomStrLength) + for _, clusterName := range framework.ClusterNames() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, "", karmadactlTimeout, "top", "pod", podName, "-n", testNamespace, "-C", clusterName) + _, err := cmd.ExecOrDie() + gomega.Expect(strings.Contains(err.Error(), fmt.Sprintf("pods \"%s\" not found", podName))).To(gomega.BeTrue(), "should not found") + } + }) + }) + + ginkgo.Context("Karmadactl top pod", func() { + var policyName string + var pod *corev1.Pod + var policy *policyv1alpha1.PropagationPolicy + ginkgo.BeforeEach(func() { + // create a pod and a propagationPolicy + policyName = podNamePrefix + rand.String(RandomStrLength) + pod = helper.NewPod(testNamespace, podNamePrefix+rand.String(RandomStrLength)) + policy = testhelper.NewPropagationPolicy(testNamespace, policyName, []policyv1alpha1.ResourceSelector{ + { + APIVersion: pod.APIVersion, + Kind: pod.Kind, + Name: pod.Name, + }, + }, policyv1alpha1.Placement{ + ClusterAffinity: &policyv1alpha1.ClusterAffinity{ + ClusterNames: framework.ClusterNames(), + }, + }) + + framework.CreatePropagationPolicy(karmadaClient, policy) + framework.CreatePod(kubeClient, pod) + ginkgo.DeferCleanup(func() { + framework.RemovePropagationPolicy(karmadaClient, policy.Namespace, policyName) + framework.RemovePod(kubeClient, pod.Namespace, pod.Name) + }) + + // wait for pod and metrics ready + framework.WaitPodPresentOnClustersFitWith(framework.ClusterNames(), pod.Namespace, pod.Name, + func(pod *corev1.Pod) bool { + return pod.Status.Phase == corev1.PodRunning + }) + for _, cluster := range framework.ClusterNames() { + framework.WaitPodMetricsReady(kubeClient, karmadaClient, cluster, pod.Namespace, pod.Name) + } + }) + + ginkgo.It("Karmadactl top existing pod", func() { + for _, clusterName := range framework.ClusterNames() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", pod.Name, "-n", pod.Namespace, "-C", clusterName) + _, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + } + }) + + ginkgo.It("Karmadactl top existing pod without setting cluster flag", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", pod.Name, "-n", pod.Namespace) + _, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + }) + + ginkgo.It("Karmadactl top pod without specific podName", func() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", "-A") + _, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + for _, clusterName := range framework.ClusterNames() { + cmd := framework.NewKarmadactlCommand(kubeconfig, karmadaContext, karmadactlPath, pod.Namespace, karmadactlTimeout, "top", "pod", "-A", "-C", clusterName) + _, err := cmd.ExecOrDie() + gomega.Expect(err).ShouldNot(gomega.HaveOccurred()) + } + }) + }) +})