diff --git a/tests/e2e/controlplane/control_plane_suite_test.go b/tests/e2e/controlplane/control_plane_suite_test.go index b8e073099..a494a16d8 100644 --- a/tests/e2e/controlplane/control_plane_suite_test.go +++ b/tests/e2e/controlplane/control_plane_suite_test.go @@ -43,7 +43,7 @@ var ( bookinfoNamespace = env.Get("BOOKINFO_NAMESPACE", "bookinfo") multicluster = env.GetBool("MULTICLUSTER", false) - k *kubectl.KubectlBuilder + k kubectl.Kubectl ) func TestInstall(t *testing.T) { @@ -62,5 +62,5 @@ func setup() { cl, err = k8sclient.InitK8sClient("") Expect(err).NotTo(HaveOccurred()) - k = kubectl.NewKubectlBuilder() + k = kubectl.New() } diff --git a/tests/e2e/controlplane/control_plane_test.go b/tests/e2e/controlplane/control_plane_test.go index c6db61e89..eafcc9a01 100644 --- a/tests/e2e/controlplane/control_plane_test.go +++ b/tests/e2e/controlplane/control_plane_test.go @@ -173,9 +173,8 @@ spec: }) It("doesn't continuously reconcile the IstioCNI CR", func() { - Eventually(k.SetNamespace(namespace).Logs).WithArguments("deploy/"+deploymentName, ptr.Of(30*time.Second)). + Eventually(k.WithNamespace(namespace).Logs).WithArguments("deploy/"+deploymentName, ptr.Of(30*time.Second)). ShouldNot(ContainSubstring("Reconciliation done"), "IstioCNI is continuously reconciling") - k.ResetNamespace() Success("IstioCNI stopped reconciling") }) }) @@ -222,9 +221,8 @@ spec: }) It("doesn't continuously reconcile the Istio CR", func() { - Eventually(k.SetNamespace(namespace).Logs).WithArguments("deploy/"+deploymentName, ptr.Of(30*time.Second)). + Eventually(k.WithNamespace(namespace).Logs).WithArguments("deploy/"+deploymentName, ptr.Of(30*time.Second)). ShouldNot(ContainSubstring("Reconciliation done"), "Istio CR is continuously reconciling") - k.ResetNamespace() Success("Istio CR stopped reconciling") }) }) @@ -269,7 +267,7 @@ spec: When("the Istio CR is deleted", func() { BeforeEach(func() { - Expect(k.SetNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") + Expect(k.WithNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") Success("Istio CR deleted") }) @@ -283,7 +281,7 @@ spec: When("the IstioCNI CR is deleted", func() { BeforeEach(func() { - Expect(k.SetNamespace(istioCniNamespace).Delete("istiocni", istioCniName)).To(Succeed(), "IstioCNI CR failed to be deleted") + Expect(k.WithNamespace(istioCniNamespace).Delete("istiocni", istioCniName)).To(Succeed(), "IstioCNI CR failed to be deleted") Success("IstioCNI deleted") }) @@ -389,7 +387,7 @@ func getBookinfoURL(version supportedversion.VersionInfo) string { func deployBookinfo(version supportedversion.VersionInfo) error { bookinfoURL := getBookinfoURL(version) - err := k.SetNamespace(bookinfoNamespace).Apply(bookinfoURL) + err := k.WithNamespace(bookinfoNamespace).Apply(bookinfoURL) if err != nil { return fmt.Errorf("error deploying bookinfo: %w", err) } @@ -398,7 +396,7 @@ func deployBookinfo(version supportedversion.VersionInfo) error { } func getProxyVersion(podName, namespace string) (*semver.Version, error) { - output, err := k.SetNamespace(namespace).Exec( + output, err := k.WithNamespace(namespace).Exec( podName, "istio-proxy", `curl -s http://localhost:15000/server_info | grep "ISTIO_VERSION" | awk -F '"' '{print $4}'`) diff --git a/tests/e2e/dualstack/dualstack_suite_test.go b/tests/e2e/dualstack/dualstack_suite_test.go index d2fc4211f..99f82bab0 100644 --- a/tests/e2e/dualstack/dualstack_suite_test.go +++ b/tests/e2e/dualstack/dualstack_suite_test.go @@ -43,7 +43,7 @@ var ( multicluster = env.GetBool("MULTICLUSTER", false) ipFamily = env.Get("IP_FAMILY", "ipv4") - k *kubectl.KubectlBuilder + k kubectl.Kubectl ) func TestDualStack(t *testing.T) { @@ -63,5 +63,5 @@ func setup() { cl, err = k8sclient.InitK8sClient("") Expect(err).NotTo(HaveOccurred()) - k = kubectl.NewKubectlBuilder() + k = kubectl.New() } diff --git a/tests/e2e/dualstack/dualstack_test.go b/tests/e2e/dualstack/dualstack_test.go index 3a4aae4fe..b4108509b 100644 --- a/tests/e2e/dualstack/dualstack_test.go +++ b/tests/e2e/dualstack/dualstack_test.go @@ -81,7 +81,7 @@ var _ = Describe("DualStack configuration ", Ordered, func() { continue } - Context("Istio version is: "+version.Version.String(), func() { + Context(fmt.Sprintf("Istio version %s", version.Version), func() { BeforeAll(func() { Expect(k.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Istio namespace failed to be created") Expect(k.CreateNamespace(istioCniNamespace)).To(Succeed(), "IstioCNI namespace failed to be created") @@ -205,10 +205,10 @@ spec: Expect(k.Patch("namespace", SleepNamespace, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). To(Succeed(), "Error patching sleep namespace") - Expect(k.SetNamespace(DualStackNamespace).Apply(getYAMLPodURL(version, DualStackNamespace))).To(Succeed(), "error deploying tcpDualStack pod") - Expect(k.SetNamespace(IPv4Namespace).Apply(getYAMLPodURL(version, IPv4Namespace))).To(Succeed(), "error deploying ipv4 pod") - Expect(k.SetNamespace(IPv6Namespace).Apply(getYAMLPodURL(version, IPv6Namespace))).To(Succeed(), "error deploying ipv6 pod") - Expect(k.SetNamespace(SleepNamespace).Apply(getYAMLPodURL(version, SleepNamespace))).To(Succeed(), "error deploying sleep pod") + Expect(k.WithNamespace(DualStackNamespace).Apply(getYAMLPodURL(version, DualStackNamespace))).To(Succeed(), "error deploying tcpDualStack pod") + Expect(k.WithNamespace(IPv4Namespace).Apply(getYAMLPodURL(version, IPv4Namespace))).To(Succeed(), "error deploying ipv4 pod") + Expect(k.WithNamespace(IPv6Namespace).Apply(getYAMLPodURL(version, IPv6Namespace))).To(Succeed(), "error deploying ipv6 pod") + Expect(k.WithNamespace(SleepNamespace).Apply(getYAMLPodURL(version, SleepNamespace))).To(Succeed(), "error deploying sleep pod") Success("dualStack validation pods deployed") }) @@ -254,7 +254,7 @@ spec: When("the Istio CR is deleted", func() { BeforeEach(func() { - Expect(k.SetNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") + Expect(k.WithNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") Success("Istio CR deleted") }) @@ -268,7 +268,7 @@ spec: When("the IstioCNI CR is deleted", func() { BeforeEach(func() { - Expect(k.SetNamespace(istioCniNamespace).Delete("istiocni", istioCniName)).To(Succeed(), "IstioCNI CR failed to be deleted") + Expect(k.WithNamespace(istioCniNamespace).Delete("istiocni", istioCniName)).To(Succeed(), "IstioCNI CR failed to be deleted") Success("IstioCNI deleted") }) @@ -356,7 +356,7 @@ func getYAMLPodURL(version supportedversion.VersionInfo, namespace string) strin func checkPodConnectivity(podName, namespace, echoStr string) { command := fmt.Sprintf(`sh -c 'echo %s | nc tcp-echo.%s 9000'`, echoStr, echoStr) - response, err := k.SetNamespace(namespace).Exec(podName, "sleep", command) + response, err := k.WithNamespace(namespace).Exec(podName, "sleep", command) Expect(err).NotTo(HaveOccurred(), fmt.Sprintf("error connecting to the %q pod", podName)) Expect(response).To(ContainSubstring(fmt.Sprintf("hello %s", echoStr)), fmt.Sprintf("Unexpected response from %s pod", podName)) } diff --git a/tests/e2e/multicluster/multicluster_multiprimary_test.go b/tests/e2e/multicluster/multicluster_multiprimary_test.go index 6f5397e2a..8cee0948e 100644 --- a/tests/e2e/multicluster/multicluster_multiprimary_test.go +++ b/tests/e2e/multicluster/multicluster_multiprimary_test.go @@ -49,8 +49,8 @@ var _ = Describe("Multicluster deployment models", Ordered, func() { BeforeAll(func(ctx SpecContext) { if !skipDeploy { // Deploy the Sail Operator on both clusters - Expect(kubectlClient1.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created on Cluster #1") - Expect(kubectlClient2.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created on Cluster #2") + Expect(k1.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created on Cluster #1") + Expect(k2.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created on Cluster #2") Expect(helm.Install("sail-operator", filepath.Join(project.RootDir, "chart"), "--namespace "+namespace, "--set=image="+image, "--kubeconfig "+kubeconfig)). To(Succeed(), "Operator failed to be deployed in Cluster #1") @@ -73,15 +73,15 @@ var _ = Describe("Multicluster deployment models", Ordered, func() { Describe("Multi-Primary Multi-Network configuration", func() { // Test the Multi-Primary Multi-Network configuration for each supported Istio version for _, version := range supportedversion.List { - Context("Istio version is: "+version.Version.String(), func() { - When("Istio resources are created in both clusters with multicluster configuration", func() { + Context(fmt.Sprintf("Istio version %s", version.Version), func() { + When("Istio resources are created in both clusters", func() { BeforeAll(func(ctx SpecContext) { - Expect(kubectlClient1.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") - Expect(kubectlClient2.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") + Expect(k1.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") + Expect(k2.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") // Push the intermediate CA to both clusters - Expect(certs.PushIntermediateCA(controlPlaneNamespace, kubeconfig, "east", "network1", artifacts, clPrimary)).To(Succeed()) - Expect(certs.PushIntermediateCA(controlPlaneNamespace, kubeconfig2, "west", "network2", artifacts, clRemote)).To(Succeed()) + Expect(certs.PushIntermediateCA(k1, controlPlaneNamespace, "east", "network1", artifacts, clPrimary)).To(Succeed()) + Expect(certs.PushIntermediateCA(k2, controlPlaneNamespace, "west", "network2", artifacts, clRemote)).To(Succeed()) // Wait for the secret to be created in both clusters Eventually(func() error { @@ -110,11 +110,11 @@ spec: network: %s` multiclusterCluster1YAML := fmt.Sprintf(multiclusterYAML, version.Name, controlPlaneNamespace, "mesh1", "cluster1", "network1") Log("Istio CR Cluster #1: ", multiclusterCluster1YAML) - Expect(kubectlClient1.CreateFromString(multiclusterCluster1YAML)).To(Succeed(), "Istio Resource creation failed on Cluster #1") + Expect(k1.CreateFromString(multiclusterCluster1YAML)).To(Succeed(), "Istio Resource creation failed on Cluster #1") multiclusterCluster2YAML := fmt.Sprintf(multiclusterYAML, version.Name, controlPlaneNamespace, "mesh1", "cluster2", "network2") Log("Istio CR Cluster #2: ", multiclusterCluster2YAML) - Expect(kubectlClient2.CreateFromString(multiclusterCluster2YAML)).To(Succeed(), "Istio Resource creation failed on Cluster #2") + Expect(k2.CreateFromString(multiclusterCluster2YAML)).To(Succeed(), "Istio Resource creation failed on Cluster #2") }) It("updates both Istio CR status to Ready", func(ctx SpecContext) { @@ -140,19 +140,18 @@ spec: WithArguments(ctx, clRemote, kube.Key("istiod", controlPlaneNamespace), &appsv1.Deployment{}). Should(HaveCondition(appsv1.DeploymentAvailable, metav1.ConditionTrue), "Istiod is not Available on Cluster #2; unexpected Condition") Expect(common.GetVersionFromIstiod()).To(Equal(version.Version), "Unexpected istiod version") - Success("Istiod is deployed in the namespace and Running on Cluster #2") + Success("Istiod is deployed in the namespace and Running on Cluster #2") }) }) When("Gateway is created in both clusters", func() { BeforeAll(func(ctx SpecContext) { - Expect(kubectlClient1.SetNamespace(controlPlaneNamespace).Apply(eastGatewayYAML)).To(Succeed(), "Gateway creation failed on Cluster #1") - - Expect(kubectlClient2.SetNamespace(controlPlaneNamespace).Apply(westGatewayYAML)).To(Succeed(), "Gateway creation failed on Cluster #2") + Expect(k1.WithNamespace(controlPlaneNamespace).Apply(eastGatewayYAML)).To(Succeed(), "Gateway creation failed on Cluster #1") + Expect(k2.WithNamespace(controlPlaneNamespace).Apply(westGatewayYAML)).To(Succeed(), "Gateway creation failed on Cluster #2") // Expose the Gateway service in both clusters - Expect(kubectlClient1.SetNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Cluster #1") - Expect(kubectlClient2.SetNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Cluster #2") + Expect(k1.WithNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Cluster #1") + Expect(k2.WithNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Cluster #2") }) It("updates both Gateway status to Available", func(ctx SpecContext) { @@ -170,23 +169,23 @@ spec: When("are installed remote secrets on each cluster", func() { BeforeAll(func(ctx SpecContext) { // Get the internal IP of the control plane node in both clusters - internalIPCluster1, err := kubectlClient1.GetInternalIP("node-role.kubernetes.io/control-plane") + internalIPCluster1, err := k1.GetInternalIP("node-role.kubernetes.io/control-plane") Expect(err).NotTo(HaveOccurred()) Expect(internalIPCluster1).NotTo(BeEmpty(), "Internal IP is empty for Cluster #1") - internalIPCluster2, err := kubectlClient2.GetInternalIP("node-role.kubernetes.io/control-plane") + internalIPCluster2, err := k2.GetInternalIP("node-role.kubernetes.io/control-plane") Expect(internalIPCluster2).NotTo(BeEmpty(), "Internal IP is empty for Cluster #2") Expect(err).NotTo(HaveOccurred()) // Install a remote secret in Cluster #1 that provides access to the Cluster #2 API server. secret, err := istioctl.CreateRemoteSecret(kubeconfig2, "cluster2", internalIPCluster2) Expect(err).NotTo(HaveOccurred()) - Expect(kubectlClient1.ApplyString(secret)).To(Succeed(), "Remote secret creation failed on Cluster #1") + Expect(k1.ApplyString(secret)).To(Succeed(), "Remote secret creation failed on Cluster #1") // Install a remote secret in Cluster #2 that provides access to the Cluster #1 API server. secret, err = istioctl.CreateRemoteSecret(kubeconfig, "cluster1", internalIPCluster1) Expect(err).NotTo(HaveOccurred()) - Expect(kubectlClient2.ApplyString(secret)).To(Succeed(), "Remote secret creation failed on Cluster #1") + Expect(k2.ApplyString(secret)).To(Succeed(), "Remote secret creation failed on Cluster #1") }) It("remote secrets are created", func(ctx SpecContext) { @@ -196,7 +195,7 @@ spec: secret, err = common.GetObject(ctx, clRemote, kube.Key("istio-remote-secret-cluster1", controlPlaneNamespace), &corev1.Secret{}) Expect(err).NotTo(HaveOccurred()) - Expect(secret).NotTo(BeNil(), "Secret is not created on Cluster #2") + Expect(secret).NotTo(BeNil(), "Secret is not created on Cluster #2") Success("Remote secrets are created in both clusters") }) }) @@ -238,16 +237,16 @@ spec: Expect(err).NotTo(HaveOccurred(), "Error getting sleep pod name on Cluster #1") sleepPodNameCluster2, err := common.GetPodNameByLabel(ctx, clRemote, "sample", "app", "sleep") - Expect(sleepPodNameCluster2).NotTo(BeEmpty(), "Sleep pod not found on Cluster #2") - Expect(err).NotTo(HaveOccurred(), "Error getting sleep pod name on Cluster #2") + Expect(sleepPodNameCluster2).NotTo(BeEmpty(), "Sleep pod not found on Cluster #2") + Expect(err).NotTo(HaveOccurred(), "Error getting sleep pod name on Cluster #2") // Run the curl command from the sleep pod in the Cluster #2 and get response list to validate that we get responses from both clusters - Cluster2Responses := strings.Join(getListCurlResponses(kubectlClient2, sleepPodNameCluster2), "\n") + Cluster2Responses := strings.Join(getListCurlResponses(k2, sleepPodNameCluster2), "\n") Expect(Cluster2Responses).To(ContainSubstring("Hello version: v1"), "Responses from Cluster #2 are not the expected") Expect(Cluster2Responses).To(ContainSubstring("Hello version: v2"), "Responses from Cluster #2 are not the expected") // Run the curl command from the sleep pod in the Cluster #1 and get response list to validate that we get responses from both clusters - Cluster1Responses := strings.Join(getListCurlResponses(kubectlClient1, sleepPodNameCluster1), "\n") + Cluster1Responses := strings.Join(getListCurlResponses(k1, sleepPodNameCluster1), "\n") Expect(Cluster1Responses).To(ContainSubstring("Hello version: v1"), "Responses from Cluster #1 are not the expected") Expect(Cluster1Responses).To(ContainSubstring("Hello version: v2"), "Responses from Cluster #1 are not the expected") Success("Sample app is accessible from both clusters") @@ -257,8 +256,8 @@ spec: When("istio CR is deleted in both clusters", func() { BeforeEach(func() { // Delete the Istio CR in both clusters - Expect(kubectlClient1.SetNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") - Expect(kubectlClient2.SetNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") + Expect(k1.WithNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") + Expect(k2.WithNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") Success("Istio CR is deleted in both clusters") }) @@ -273,16 +272,16 @@ spec: AfterAll(func(ctx SpecContext) { // Delete namespace to ensure clean up for new tests iteration - Expect(kubectlClient1.DeleteNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be deleted on Cluster #1") - Expect(kubectlClient2.DeleteNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be deleted on Cluster #2") + Expect(k1.DeleteNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be deleted on Cluster #1") + Expect(k2.DeleteNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be deleted on Cluster #2") common.CheckNamespaceEmpty(ctx, clPrimary, controlPlaneNamespace) common.CheckNamespaceEmpty(ctx, clRemote, controlPlaneNamespace) Success("ControlPlane Namespaces are empty") // Delete the entire sample namespace in both clusters - Expect(kubectlClient1.DeleteNamespace("sample")).To(Succeed(), "Namespace failed to be deleted on Cluster #1") - Expect(kubectlClient2.DeleteNamespace("sample")).To(Succeed(), "Namespace failed to be deleted on Cluster #2") + Expect(k1.DeleteNamespace("sample")).To(Succeed(), "Namespace failed to be deleted on Cluster #1") + Expect(k2.DeleteNamespace("sample")).To(Succeed(), "Namespace failed to be deleted on Cluster #2") common.CheckNamespaceEmpty(ctx, clPrimary, "sample") common.CheckNamespaceEmpty(ctx, clRemote, "sample") @@ -294,8 +293,8 @@ spec: AfterAll(func(ctx SpecContext) { // Delete the Sail Operator from both clusters - Expect(kubectlClient1.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted on Cluster #1") - Expect(kubectlClient2.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted on Cluster #2") + Expect(k1.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted on Cluster #1") + Expect(k2.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted on Cluster #2") // Delete the intermediate CA from both clusters common.CheckNamespaceEmpty(ctx, clPrimary, namespace) @@ -306,13 +305,13 @@ spec: // deploySampleApp deploys the sample app in the given cluster func deploySampleApp(ns string, istioVersion supportedversion.VersionInfo) { // Create the namespace - Expect(kubectlClient1.CreateNamespace(ns)).To(Succeed(), "Namespace failed to be created") - Expect(kubectlClient2.CreateNamespace(ns)).To(Succeed(), "Namespace failed to be created") + Expect(k1.CreateNamespace(ns)).To(Succeed(), "Namespace failed to be created") + Expect(k2.CreateNamespace(ns)).To(Succeed(), "Namespace failed to be created") // Label the namespace - Expect(kubectlClient1.Patch("namespace", ns, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). + Expect(k1.Patch("namespace", ns, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). To(Succeed(), "Error patching sample namespace") - Expect(kubectlClient2.Patch("namespace", ns, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). + Expect(k2.Patch("namespace", ns, "merge", `{"metadata":{"labels":{"istio-injection":"enabled"}}}`)). To(Succeed(), "Error patching sample namespace") version := istioVersion.Version.String() @@ -321,22 +320,22 @@ func deploySampleApp(ns string, istioVersion supportedversion.VersionInfo) { version = "master" } helloWorldURL := fmt.Sprintf("https://raw.githubusercontent.com/istio/istio/%s/samples/helloworld/helloworld.yaml", version) - Expect(kubectlClient1.SetNamespace(ns).ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Sample service deploy failed on Cluster #1") - Expect(kubectlClient2.SetNamespace(ns).ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Sample service deploy failed on Cluster #2") + Expect(k1.WithNamespace(ns).ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Sample service deploy failed on Cluster #1") + Expect(k2.WithNamespace(ns).ApplyWithLabels(helloWorldURL, "service=helloworld")).To(Succeed(), "Sample service deploy failed on Cluster #2") - Expect(kubectlClient1.SetNamespace(ns).ApplyWithLabels(helloWorldURL, "version=v1")).To(Succeed(), "Sample service deploy failed on Cluster #1") - Expect(kubectlClient2.SetNamespace(ns).ApplyWithLabels(helloWorldURL, "version=v2")).To(Succeed(), "Sample service deploy failed on Cluster #2") + Expect(k1.WithNamespace(ns).ApplyWithLabels(helloWorldURL, "version=v1")).To(Succeed(), "Sample service deploy failed on Cluster #1") + Expect(k2.WithNamespace(ns).ApplyWithLabels(helloWorldURL, "version=v2")).To(Succeed(), "Sample service deploy failed on Cluster #2") sleepURL := fmt.Sprintf("https://raw.githubusercontent.com/istio/istio/%s/samples/sleep/sleep.yaml", version) - Expect(kubectlClient1.SetNamespace(ns).Apply(sleepURL)).To(Succeed(), "Sample sleep deploy failed on Cluster #1") - Expect(kubectlClient2.SetNamespace(ns).Apply(sleepURL)).To(Succeed(), "Sample sleep deploy failed on Cluster #2") + Expect(k1.WithNamespace(ns).Apply(sleepURL)).To(Succeed(), "Sample sleep deploy failed on Cluster #1") + Expect(k2.WithNamespace(ns).Apply(sleepURL)).To(Succeed(), "Sample sleep deploy failed on Cluster #2") } // getListCurlResponses runs the curl command 10 times from the sleep pod in the given cluster and get response list -func getListCurlResponses(k *kubectl.KubectlBuilder, podName string) []string { +func getListCurlResponses(k kubectl.Kubectl, podName string) []string { var responses []string for i := 0; i < 10; i++ { - response, err := k.SetNamespace("sample").Exec(podName, "sleep", "curl -sS helloworld.sample:5000/hello") + response, err := k.WithNamespace("sample").Exec(podName, "sleep", "curl -sS helloworld.sample:5000/hello") Expect(err).NotTo(HaveOccurred()) responses = append(responses, response) } diff --git a/tests/e2e/multicluster/multicluster_primaryremote_test.go b/tests/e2e/multicluster/multicluster_primaryremote_test.go index e6e45e2fd..35c6fb240 100644 --- a/tests/e2e/multicluster/multicluster_primaryremote_test.go +++ b/tests/e2e/multicluster/multicluster_primaryremote_test.go @@ -48,8 +48,8 @@ var _ = Describe("Multicluster deployment models", Ordered, func() { BeforeAll(func(ctx SpecContext) { if !skipDeploy { // Deploy the Sail Operator on both clusters - Expect(kubectlClient1.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created on Primary Cluster") - Expect(kubectlClient2.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created on Remote Cluster") + Expect(k1.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created on Primary Cluster") + Expect(k2.CreateNamespace(namespace)).To(Succeed(), "Namespace failed to be created on Remote Cluster") Expect(helm.Install("sail-operator", filepath.Join(project.RootDir, "chart"), "--namespace "+namespace, "--set=image="+image, "--kubeconfig "+kubeconfig)). To(Succeed(), "Operator failed to be deployed in Primary Cluster") @@ -78,16 +78,16 @@ var _ = Describe("Multicluster deployment models", Ordered, func() { continue } - Context("Istio version is: "+version.Version.String(), func() { + Context(fmt.Sprintf("Istio version %s", version.Version), func() { When("Istio resources are created in both clusters", func() { BeforeAll(func(ctx SpecContext) { - Expect(kubectlClient1.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") - Expect(kubectlClient2.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") + Expect(k1.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") + Expect(k2.CreateNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be created") // Push the intermediate CA to both clusters - Expect(certs.PushIntermediateCA(controlPlaneNamespace, kubeconfig, "east", "network1", artifacts, clPrimary)). + Expect(certs.PushIntermediateCA(k1, controlPlaneNamespace, "east", "network1", artifacts, clPrimary)). To(Succeed(), "Error pushing intermediate CA to Primary Cluster") - Expect(certs.PushIntermediateCA(controlPlaneNamespace, kubeconfig2, "west", "network2", artifacts, clRemote)). + Expect(certs.PushIntermediateCA(k2, controlPlaneNamespace, "west", "network2", artifacts, clRemote)). To(Succeed(), "Error pushing intermediate CA to Remote Cluster") // Wait for the secret to be created in both clusters @@ -120,7 +120,7 @@ spec: network: %s` multiclusterPrimaryYAML := fmt.Sprintf(PrimaryYAML, version.Name, controlPlaneNamespace, "mesh1", "cluster1", "network1") Log("Istio CR Primary: ", multiclusterPrimaryYAML) - Expect(kubectlClient1.CreateFromString(multiclusterPrimaryYAML)).To(Succeed(), "Istio Resource creation failed on Primary Cluster") + Expect(k1.CreateFromString(multiclusterPrimaryYAML)).To(Succeed(), "Istio Resource creation failed on Primary Cluster") }) It("updates Istio CR on Primary cluster status to Ready", func(ctx SpecContext) { @@ -141,13 +141,13 @@ spec: When("Gateway is created on Primary cluster ", func() { BeforeAll(func(ctx SpecContext) { - Expect(kubectlClient1.SetNamespace(controlPlaneNamespace).Apply(eastGatewayYAML)).To(Succeed(), "Gateway creation failed on Primary Cluster") + Expect(k1.WithNamespace(controlPlaneNamespace).Apply(eastGatewayYAML)).To(Succeed(), "Gateway creation failed on Primary Cluster") // Expose istiod service in Primary cluster - Expect(kubectlClient1.SetNamespace(controlPlaneNamespace).Apply(exposeIstiodYAML)).To(Succeed(), "Expose Istiod creation failed on Primary Cluster") + Expect(k1.WithNamespace(controlPlaneNamespace).Apply(exposeIstiodYAML)).To(Succeed(), "Expose Istiod creation failed on Primary Cluster") // Expose the Gateway service in both clusters - Expect(kubectlClient1.SetNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Primary Cluster") + Expect(k1.WithNamespace(controlPlaneNamespace).Apply(exposeServiceYAML)).To(Succeed(), "Expose Service creation failed on Primary Cluster") }) It("updates Gateway status to Available", func(ctx SpecContext) { @@ -179,19 +179,19 @@ spec: remoteIstioYAML := fmt.Sprintf(RemoteYAML, version.Name, remotePilotAddress) Log("RemoteIstio CR: ", remoteIstioYAML) By("Creating RemoteIstio CR on Remote Cluster") - Expect(kubectlClient2.CreateFromString(remoteIstioYAML)).To(Succeed(), "RemoteIstio Resource creation failed on Remote Cluster") + Expect(k2.CreateFromString(remoteIstioYAML)).To(Succeed(), "RemoteIstio Resource creation failed on Remote Cluster") // Set the controlplane cluster and network for Remote namespace By("Patching the istio-system namespace on Remote Cluster") Expect( - kubectlClient2.Patch( + k2.Patch( "namespace", controlPlaneNamespace, "merge", `{"metadata":{"annotations":{"topology.istio.io/controlPlaneClusters":"cluster1"}}}`)). To(Succeed(), "Error patching istio-system namespace") Expect( - kubectlClient2.Patch( + k2.Patch( "namespace", controlPlaneNamespace, "merge", @@ -201,7 +201,7 @@ spec: // To be able to access the remote cluster from the primary cluster, we need to create a secret in the primary cluster // RemoteIstio resource will not be Ready until the secret is created // Get the internal IP of the control plane node in Remote cluster - internalIPRemote, err := kubectlClient2.GetInternalIP("node-role.kubernetes.io/control-plane") + internalIPRemote, err := k2.GetInternalIP("node-role.kubernetes.io/control-plane") Expect(internalIPRemote).NotTo(BeEmpty(), "Internal IP is empty for Remote Cluster") Expect(err).NotTo(HaveOccurred()) @@ -212,7 +212,7 @@ spec: By("Creating Remote Secret on Primary Cluster") secret, err := istioctl.CreateRemoteSecret(kubeconfig2, "remote", internalIPRemote) Expect(err).NotTo(HaveOccurred()) - Expect(kubectlClient1.ApplyString(secret)).To(Succeed(), "Remote secret creation failed on Primary Cluster") + Expect(k1.WithNamespace(controlPlaneNamespace).ApplyString(secret)).To(Succeed(), "Remote secret creation failed on Primary Cluster") }) It("secret is created", func(ctx SpecContext) { @@ -232,7 +232,7 @@ spec: When("gateway is created in Remote cluster", func() { BeforeAll(func(ctx SpecContext) { - Expect(kubectlClient2.SetNamespace(controlPlaneNamespace).Apply(westGatewayYAML)).To(Succeed(), "Gateway creation failed on Remote Cluster") + Expect(k2.WithNamespace(controlPlaneNamespace).Apply(westGatewayYAML)).To(Succeed(), "Gateway creation failed on Remote Cluster") Success("Gateway is created in Remote cluster") }) @@ -285,12 +285,12 @@ spec: Expect(err).NotTo(HaveOccurred(), "Error getting sleep pod name on Remote Cluster") // Run the curl command from the sleep pod in the Remote Cluster and get response list to validate that we get responses from both clusters - remoteResponses := strings.Join(getListCurlResponses(kubectlClient2, sleepPodNameRemote), "\n") + remoteResponses := strings.Join(getListCurlResponses(k2, sleepPodNameRemote), "\n") Expect(remoteResponses).To(ContainSubstring("Hello version: v1"), "Responses from Remote Cluster are not the expected") Expect(remoteResponses).To(ContainSubstring("Hello version: v2"), "Responses from Remote Cluster are not the expected") // Run the curl command from the sleep pod in the Primary Cluster and get response list to validate that we get responses from both clusters - primaryResponses := strings.Join(getListCurlResponses(kubectlClient1, sleepPodNamePrimary), "\n") + primaryResponses := strings.Join(getListCurlResponses(k1, sleepPodNamePrimary), "\n") Expect(primaryResponses).To(ContainSubstring("Hello version: v1"), "Responses from Primary Cluster are not the expected") Expect(primaryResponses).To(ContainSubstring("Hello version: v2"), "Responses from Primary Cluster are not the expected") Success("Sample app is accessible from both clusters") @@ -299,8 +299,8 @@ spec: When("Istio CR and RemoteIstio CR are deleted in both clusters", func() { BeforeEach(func() { - Expect(kubectlClient1.SetNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") - Expect(kubectlClient2.SetNamespace(controlPlaneNamespace).Delete("remoteistio", istioName)).To(Succeed(), "RemoteIstio CR failed to be deleted") + Expect(k1.WithNamespace(controlPlaneNamespace).Delete("istio", istioName)).To(Succeed(), "Istio CR failed to be deleted") + Expect(k2.WithNamespace(controlPlaneNamespace).Delete("remoteistio", istioName)).To(Succeed(), "RemoteIstio CR failed to be deleted") Success("Istio and RemoteIstio are deleted") }) @@ -313,16 +313,16 @@ spec: AfterAll(func(ctx SpecContext) { // Delete namespace to ensure clean up for new tests iteration - Expect(kubectlClient1.DeleteNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be deleted on Primary Cluster") - Expect(kubectlClient2.DeleteNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be deleted on Remote Cluster") + Expect(k1.DeleteNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be deleted on Primary Cluster") + Expect(k2.DeleteNamespace(controlPlaneNamespace)).To(Succeed(), "Namespace failed to be deleted on Remote Cluster") common.CheckNamespaceEmpty(ctx, clPrimary, controlPlaneNamespace) common.CheckNamespaceEmpty(ctx, clRemote, controlPlaneNamespace) Success("ControlPlane Namespaces are empty") // Delete the entire sample namespace in both clusters - Expect(kubectlClient1.DeleteNamespace("sample")).To(Succeed(), "Namespace failed to be deleted on Primary Cluster") - Expect(kubectlClient2.DeleteNamespace("sample")).To(Succeed(), "Namespace failed to be deleted on Remote Cluster") + Expect(k1.DeleteNamespace("sample")).To(Succeed(), "Namespace failed to be deleted on Primary Cluster") + Expect(k2.DeleteNamespace("sample")).To(Succeed(), "Namespace failed to be deleted on Remote Cluster") common.CheckNamespaceEmpty(ctx, clPrimary, "sample") common.CheckNamespaceEmpty(ctx, clRemote, "sample") @@ -334,8 +334,8 @@ spec: AfterAll(func(ctx SpecContext) { // Delete the Sail Operator from both clusters - Expect(kubectlClient1.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted on Primary Cluster") - Expect(kubectlClient2.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted on Remote Cluster") + Expect(k1.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted on Primary Cluster") + Expect(k2.DeleteNamespace(namespace)).To(Succeed(), "Namespace failed to be deleted on Remote Cluster") // Check that the namespace is empty common.CheckNamespaceEmpty(ctx, clPrimary, namespace) diff --git a/tests/e2e/multicluster/multicluster_suite_test.go b/tests/e2e/multicluster/multicluster_suite_test.go index a31105df8..09ca73fde 100644 --- a/tests/e2e/multicluster/multicluster_suite_test.go +++ b/tests/e2e/multicluster/multicluster_suite_test.go @@ -52,8 +52,8 @@ var ( exposeServiceYAML string exposeIstiodYAML string - kubectlClient1 *kubectl.KubectlBuilder - kubectlClient2 *kubectl.KubectlBuilder + k1 kubectl.Kubectl + k2 kubectl.Kubectl ) func TestInstall(t *testing.T) { @@ -99,6 +99,6 @@ func setup(t *testing.T) { exposeIstiodYAML = fmt.Sprintf("%s/docs/multicluster/expose-istiod.yaml", baseRepoDir) // Initialize kubectl utilities, one for each cluster - kubectlClient1 = kubectl.NewKubectlBuilder().SetKubeconfig(kubeconfig) - kubectlClient2 = kubectl.NewKubectlBuilder().SetKubeconfig(kubeconfig2) + k1 = kubectl.New().WithKubeconfig(kubeconfig) + k2 = kubectl.New().WithKubeconfig(kubeconfig2) } diff --git a/tests/e2e/operator/operator_suite_test.go b/tests/e2e/operator/operator_suite_test.go index 560855caa..952d7cd8e 100644 --- a/tests/e2e/operator/operator_suite_test.go +++ b/tests/e2e/operator/operator_suite_test.go @@ -36,7 +36,7 @@ var ( deploymentName = env.Get("DEPLOYMENT_NAME", "sail-operator") multicluster = env.GetBool("MULTICLUSTER", false) - k *kubectl.KubectlBuilder + k kubectl.Kubectl ) func TestInstall(t *testing.T) { @@ -62,5 +62,5 @@ func setup() { GinkgoWriter.Println("Running on Kubernetes") } - k = kubectl.NewKubectlBuilder() + k = kubectl.New() } diff --git a/tests/e2e/util/certs/certs.go b/tests/e2e/util/certs/certs.go index c2fd599c6..505eebe6f 100644 --- a/tests/e2e/util/certs/certs.go +++ b/tests/e2e/util/certs/certs.go @@ -219,7 +219,7 @@ func writeFile(confPath string, confContent string) error { } // PushIntermediateCA pushes the intermediate CA to the cluster -func PushIntermediateCA(ns, kubeconfig, zone, network, basePath string, cl client.Client) error { +func PushIntermediateCA(k kubectl.Kubectl, ns, zone, network, basePath string, cl client.Client) error { // Set cert dir certDir := filepath.Join(basePath, "certs") @@ -227,8 +227,6 @@ func PushIntermediateCA(ns, kubeconfig, zone, network, basePath string, cl clien _, err := common.GetObject(context.Background(), cl, kube.Key("cacerts", ns), &corev1.Secret{}) if err != nil { // Label the namespace with the network - k := kubectl.NewKubectlBuilder() - k.SetKubeconfig(kubeconfig) err = k.Patch("namespace", ns, "merge", `{"metadata":{"labels":{"topology.istio.io/network":"`+network+`"}}}`) if err != nil { return fmt.Errorf("failed to label namespace: %w", err) diff --git a/tests/e2e/util/common/e2e_utils.go b/tests/e2e/util/common/e2e_utils.go index 5fec5f6d0..4ccbe570a 100644 --- a/tests/e2e/util/common/e2e_utils.go +++ b/tests/e2e/util/common/e2e_utils.go @@ -52,7 +52,7 @@ var ( // - 1.24-alpha.feabc1234 istiodVersionRegex = regexp.MustCompile(`Version:"([^"]*)"`) - k = kubectl.NewKubectlBuilder() + k = kubectl.New() ) // GetObject returns the object with the given key @@ -141,21 +141,20 @@ func LogDebugInfo() { } func logOperatorDebugInfo() { - operator, err := k.SetNamespace(namespace).GetYAML("deployment", deploymentName) + operator, err := k.WithNamespace(namespace).GetYAML("deployment", deploymentName) logDebugElement("Operator Deployment YAML", operator, err) - logs, err := k.SetNamespace(namespace).Logs("deploy/"+deploymentName, ptr.Of(120*time.Second)) - k.ResetNamespace() + logs, err := k.WithNamespace(namespace).Logs("deploy/"+deploymentName, ptr.Of(120*time.Second)) logDebugElement("Operator logs", logs, err) - events, err := k.SetNamespace(namespace).GetEvents() + events, err := k.WithNamespace(namespace).GetEvents() logDebugElement("Events in "+namespace, events, err) // Temporary information to gather more details about failure - pods, err := k.SetNamespace(namespace).GetPods("", "-o wide") + pods, err := k.WithNamespace(namespace).GetPods("", "-o wide") logDebugElement("Pods in "+namespace, pods, err) - describe, err := k.SetNamespace(namespace).Describe("deployment", deploymentName) + describe, err := k.WithNamespace(namespace).Describe("deployment", deploymentName) logDebugElement("Operator Deployment describe", describe, err) } @@ -163,14 +162,13 @@ func logIstioDebugInfo() { resource, err := k.GetYAML("istio", istioName) logDebugElement("Istio YAML", resource, err) - output, err := k.SetNamespace(controlPlaneNamespace).GetPods("", "-o wide") + output, err := k.WithNamespace(controlPlaneNamespace).GetPods("", "-o wide") logDebugElement("Pods in "+controlPlaneNamespace, output, err) - logs, err := k.SetNamespace(controlPlaneNamespace).Logs("deploy/istiod", ptr.Of(120*time.Second)) - k.ResetNamespace() + logs, err := k.WithNamespace(controlPlaneNamespace).Logs("deploy/istiod", ptr.Of(120*time.Second)) logDebugElement("Istiod logs", logs, err) - events, err := k.SetNamespace(controlPlaneNamespace).GetEvents() + events, err := k.WithNamespace(controlPlaneNamespace).GetEvents() logDebugElement("Events in "+controlPlaneNamespace, events, err) } @@ -178,20 +176,20 @@ func logCNIDebugInfo() { resource, err := k.GetYAML("istiocni", istioCniName) logDebugElement("IstioCNI YAML", resource, err) - ds, err := k.SetNamespace(istioCniNamespace).GetYAML("daemonset", "istio-cni-node") + ds, err := k.WithNamespace(istioCniNamespace).GetYAML("daemonset", "istio-cni-node") logDebugElement("Istio CNI DaemonSet YAML", ds, err) - events, err := k.SetNamespace(istioCniNamespace).GetEvents() + events, err := k.WithNamespace(istioCniNamespace).GetEvents() logDebugElement("Events in "+istioCniNamespace, events, err) // Temporary information to gather more details about failure - pods, err := k.SetNamespace(istioCniNamespace).GetPods("", "-o wide") + pods, err := k.WithNamespace(istioCniNamespace).GetPods("", "-o wide") logDebugElement("Pods in "+istioCniNamespace, pods, err) - describe, err := k.SetNamespace(istioCniNamespace).Describe("daemonset", "istio-cni-node") + describe, err := k.WithNamespace(istioCniNamespace).Describe("daemonset", "istio-cni-node") logDebugElement("Istio CNI DaemonSet describe", describe, err) - logs, err := k.SetNamespace(istioCniNamespace).Logs("daemonset/istio-cni-node", ptr.Of(120*time.Second)) + logs, err := k.WithNamespace(istioCniNamespace).Logs("daemonset/istio-cni-node", ptr.Of(120*time.Second)) logDebugElement("Istio CNI logs", logs, err) } @@ -206,8 +204,8 @@ func logDebugElement(caption string, info string, err error) { } func GetVersionFromIstiod() (*semver.Version, error) { - k := kubectl.NewKubectlBuilder() - output, err := k.SetNamespace(controlPlaneNamespace).Exec("deploy/istiod", "", "pilot-discovery version") + k := kubectl.New() + output, err := k.WithNamespace(controlPlaneNamespace).Exec("deploy/istiod", "", "pilot-discovery version") if err != nil { return nil, fmt.Errorf("error getting version from istiod: %w", err) } diff --git a/tests/e2e/util/kubectl/kubectl.go b/tests/e2e/util/kubectl/kubectl.go index f07035513..f1b69576f 100644 --- a/tests/e2e/util/kubectl/kubectl.go +++ b/tests/e2e/util/kubectl/kubectl.go @@ -23,28 +23,18 @@ import ( "github.com/istio-ecosystem/sail-operator/tests/e2e/util/shell" ) -type KubectlBuilder struct { +type Kubectl struct { binary string namespace string kubeconfig string } -const DefaultBinary = "kubectl" - -func newKubectlBuilder() *KubectlBuilder { - return &KubectlBuilder{} -} - -func (k *KubectlBuilder) setBinary() { - binary := DefaultBinary - if cmd := os.Getenv("COMMAND"); cmd != "" { - binary = cmd - } - - k.binary = binary +// New creates a new kubectl.Kubectl +func New() Kubectl { + return Kubectl{}.WithBinary(os.Getenv("COMMAND")) } -func (k *KubectlBuilder) build(cmd string) string { +func (k Kubectl) build(cmd string) string { args := []string{k.binary} // Only append namespace if it's set @@ -63,15 +53,18 @@ func (k *KubectlBuilder) build(cmd string) string { return strings.Join(args, " ") } -// NewKubectlBuilder creates a new KubectlBuilder -func NewKubectlBuilder() *KubectlBuilder { - k := newKubectlBuilder() - k.setBinary() +// WithBinary returns a new Kubectl with the binary set to the given value; if the value is "", the binary is set to "kubectl" +func (k Kubectl) WithBinary(binary string) Kubectl { + if binary == "" { + k.binary = "kubectl" + } else { + k.binary = binary + } return k } -// SetNamespace sets the namespace -func (k *KubectlBuilder) SetNamespace(ns string) *KubectlBuilder { +// WithNamespace returns a new Kubectl with the namespace set to the given value +func (k Kubectl) WithNamespace(ns string) Kubectl { if ns == "" { k.namespace = "--all-namespaces" } else { @@ -80,9 +73,11 @@ func (k *KubectlBuilder) SetNamespace(ns string) *KubectlBuilder { return k } -// SetKubeconfig sets the kubeconfig -func (k *KubectlBuilder) SetKubeconfig(kubeconfig string) *KubectlBuilder { - if kubeconfig != "" { +// WithKubeconfig returns a new Kubectl with kubeconfig set to the given value +func (k Kubectl) WithKubeconfig(kubeconfig string) Kubectl { + if kubeconfig == "" { + k.kubeconfig = "" + } else { k.kubeconfig = fmt.Sprintf("--kubeconfig %s", kubeconfig) } return k @@ -90,7 +85,7 @@ func (k *KubectlBuilder) SetKubeconfig(kubeconfig string) *KubectlBuilder { // CreateNamespace creates a namespace // If the namespace already exists, it will return nil -func (k *KubectlBuilder) CreateNamespace(ns string) error { +func (k Kubectl) CreateNamespace(ns string) error { cmd := k.build(" create namespace " + ns) output, err := k.executeCommand(cmd) if err != nil { @@ -105,10 +100,9 @@ func (k *KubectlBuilder) CreateNamespace(ns string) error { } // CreateFromString creates a resource from the given yaml string -func (k *KubectlBuilder) CreateFromString(yamlString string) error { +func (k Kubectl) CreateFromString(yamlString string) error { cmd := k.build(" create -f -") _, err := shell.ExecuteCommandWithInput(cmd, yamlString) - k.ResetNamespace() if err != nil { return fmt.Errorf("error creating resource from yaml: %w", err) } @@ -116,22 +110,20 @@ func (k *KubectlBuilder) CreateFromString(yamlString string) error { } // DeleteCRDs deletes the CRDs by given list of crds names -func (k *KubectlBuilder) DeleteCRDs(crds []string) error { +func (k Kubectl) DeleteCRDs(crds []string) error { for _, crd := range crds { cmd := k.build(" delete crd " + crd) _, err := shell.ExecuteCommand(cmd) if err != nil { - k.ResetNamespace() return fmt.Errorf("error deleting crd %s: %w", crd, err) } } - k.ResetNamespace() return nil } // DeleteNamespace deletes a namespace -func (k *KubectlBuilder) DeleteNamespace(ns string) error { +func (k Kubectl) DeleteNamespace(ns string) error { cmd := k.build(" delete namespace " + ns) _, err := k.executeCommand(cmd) if err != nil { @@ -142,10 +134,9 @@ func (k *KubectlBuilder) DeleteNamespace(ns string) error { } // ApplyString applies the given yaml string to the cluster -func (k *KubectlBuilder) ApplyString(yamlString string) error { +func (k Kubectl) ApplyString(yamlString string) error { cmd := k.build(" apply --server-side -f -") _, err := shell.ExecuteCommandWithInput(cmd, yamlString) - k.ResetNamespace() if err != nil { return fmt.Errorf("error applying yaml: %w", err) } @@ -154,13 +145,13 @@ func (k *KubectlBuilder) ApplyString(yamlString string) error { } // Apply applies the given yaml file to the cluster -func (k *KubectlBuilder) Apply(yamlFile string) error { +func (k Kubectl) Apply(yamlFile string) error { err := k.ApplyWithLabels(yamlFile, "") return err } // ApplyWithLabels applies the given yaml file to the cluster with the given labels -func (k *KubectlBuilder) ApplyWithLabels(yamlFile, label string) error { +func (k Kubectl) ApplyWithLabels(yamlFile, label string) error { cmd := k.build(" apply " + labelFlag(label) + " -f " + yamlFile) _, err := k.executeCommand(cmd) if err != nil { @@ -171,7 +162,7 @@ func (k *KubectlBuilder) ApplyWithLabels(yamlFile, label string) error { } // DeleteFromFile deletes a resource from the given yaml file -func (k *KubectlBuilder) DeleteFromFile(yamlFile string) error { +func (k Kubectl) DeleteFromFile(yamlFile string) error { cmd := k.build(" delete -f " + yamlFile) _, err := k.executeCommand(cmd) if err != nil { @@ -182,7 +173,7 @@ func (k *KubectlBuilder) DeleteFromFile(yamlFile string) error { } // Delete deletes a resource based on the namespace, kind and the name -func (k *KubectlBuilder) Delete(kind, name string) error { +func (k Kubectl) Delete(kind, name string) error { cmd := k.build(" delete " + kind + " " + name) _, err := k.executeCommand(cmd) if err != nil { @@ -193,7 +184,7 @@ func (k *KubectlBuilder) Delete(kind, name string) error { } // Patch patches a resource -func (k *KubectlBuilder) Patch(kind, name, patchType, patch string) error { +func (k Kubectl) Patch(kind, name, patchType, patch string) error { cmd := k.build(fmt.Sprintf(" patch %s %s --type=%s -p=%q", kind, name, patchType, patch)) _, err := k.executeCommand(cmd) if err != nil { @@ -203,7 +194,7 @@ func (k *KubectlBuilder) Patch(kind, name, patchType, patch string) error { } // ForceDelete deletes a resource by removing its finalizers -func (k *KubectlBuilder) ForceDelete(kind, name string) error { +func (k Kubectl) ForceDelete(kind, name string) error { // Not all resources have finalizers, trying to remove them returns an error here. // We explicitly ignore the error and attempt to delete the resource anyway. _ = k.Patch(kind, name, "json", `[{"op": "remove", "path": "/metadata/finalizers"}]`) @@ -211,7 +202,7 @@ func (k *KubectlBuilder) ForceDelete(kind, name string) error { } // GetYAML returns the yaml of a resource -func (k *KubectlBuilder) GetYAML(kind, name string) (string, error) { +func (k Kubectl) GetYAML(kind, name string) (string, error) { cmd := k.build(fmt.Sprintf(" get %s %s -o yaml", kind, name)) output, err := k.executeCommand(cmd) if err != nil { @@ -222,7 +213,7 @@ func (k *KubectlBuilder) GetYAML(kind, name string) (string, error) { } // GetPods returns the pods of a namespace -func (k *KubectlBuilder) GetPods(args ...string) (string, error) { +func (k Kubectl) GetPods(args ...string) (string, error) { cmd := k.build(fmt.Sprintf(" get pods %s", strings.Join(args, " "))) output, err := k.executeCommand(cmd) if err != nil { @@ -233,7 +224,7 @@ func (k *KubectlBuilder) GetPods(args ...string) (string, error) { } // GetInternalIP returns the internal IP of a node -func (k *KubectlBuilder) GetInternalIP(label string) (string, error) { +func (k Kubectl) GetInternalIP(label string) (string, error) { cmd := k.build(fmt.Sprintf(" get nodes -l %s -o jsonpath='{.items[0].status.addresses[?(@.type==\"InternalIP\")].address}'", label)) output, err := k.executeCommand(cmd) if err != nil { @@ -244,8 +235,8 @@ func (k *KubectlBuilder) GetInternalIP(label string) (string, error) { } // Exec executes a command in the pod or specific container -func (k *KubectlBuilder) Exec(pod, container, command string) (string, error) { - cmd := k.build(fmt.Sprintf(" exec %s %s -- %s", pod, containerflag(container), command)) +func (k Kubectl) Exec(pod, container, command string) (string, error) { + cmd := k.build(fmt.Sprintf(" exec %s %s -- %s", pod, containerFlag(container), command)) output, err := k.executeCommand(cmd) if err != nil { return "", err @@ -254,7 +245,7 @@ func (k *KubectlBuilder) Exec(pod, container, command string) (string, error) { } // GetEvents returns the events of a namespace -func (k *KubectlBuilder) GetEvents() (string, error) { +func (k Kubectl) GetEvents() (string, error) { cmd := k.build(" get events") output, err := k.executeCommand(cmd) if err != nil { @@ -265,7 +256,7 @@ func (k *KubectlBuilder) GetEvents() (string, error) { } // Describe returns the description of a resource -func (k *KubectlBuilder) Describe(kind, name string) (string, error) { +func (k Kubectl) Describe(kind, name string) (string, error) { cmd := k.build(fmt.Sprintf(" describe %s %s", kind, name)) output, err := k.executeCommand(cmd) if err != nil { @@ -276,7 +267,7 @@ func (k *KubectlBuilder) Describe(kind, name string) (string, error) { } // Logs returns the logs of a deployment -func (k *KubectlBuilder) Logs(pod string, since *time.Duration) (string, error) { +func (k Kubectl) Logs(pod string, since *time.Duration) (string, error) { cmd := k.build(fmt.Sprintf(" logs %s %s", pod, sinceFlag(since))) output, err := shell.ExecuteCommand(cmd) if err != nil { @@ -286,15 +277,8 @@ func (k *KubectlBuilder) Logs(pod string, since *time.Duration) (string, error) } // executeCommand handles running the command and then resets the namespace automatically -func (k *KubectlBuilder) executeCommand(cmd string) (string, error) { - result, err := shell.ExecuteCommand(cmd) - k.ResetNamespace() - return result, err -} - -// ResetNamespace resets the namespace -func (k *KubectlBuilder) ResetNamespace() { - k.namespace = "" +func (k Kubectl) executeCommand(cmd string) (string, error) { + return shell.ExecuteCommand(cmd) } func sinceFlag(since *time.Duration) string { @@ -311,7 +295,7 @@ func labelFlag(label string) string { return "-l " + label } -func containerflag(container string) string { +func containerFlag(container string) string { if container == "" { return "" }