From ad35224268449383690984a025800313abeff7da Mon Sep 17 00:00:00 2001 From: Huy Mai Date: Thu, 17 Oct 2024 10:07:10 +0000 Subject: [PATCH] Fetch Ironic node list after each e2e test Signed-off-by: Huy Mai --- hack/ci-e2e.sh | 4 ++ test/e2e/basic_ops_test.go | 2 +- test/e2e/common.go | 60 +++++++++++++++++++- test/e2e/config/fixture.yaml | 1 + test/e2e/config/ironic.yaml | 5 ++ test/e2e/e2e_config.go | 12 ++++ test/e2e/e2e_suite_test.go | 6 +- test/e2e/external_inspection_test.go | 2 +- test/e2e/inspection_test.go | 2 +- test/e2e/live_iso_test.go | 2 +- test/e2e/provisioning_and_annotation_test.go | 3 +- test/e2e/re_inspection_test.go | 2 +- test/e2e/upgrade_test.go | 2 +- 13 files changed, 91 insertions(+), 12 deletions(-) diff --git a/hack/ci-e2e.sh b/hack/ci-e2e.sh index 9ae823a9e5..1895c77463 100755 --- a/hack/ci-e2e.sh +++ b/hack/ci-e2e.sh @@ -84,6 +84,10 @@ rm /tmp/bmo-e2e.tar # This IP is defined by the network we created above. IP_ADDRESS="192.168.222.1" +# This IP is also defined by the network above, and is used consistently in all of +# our e2e overlays +export IRONIC_PROVISIONING_IP="192.168.222.199" + pushd "${REPO_ROOT}/test/createVM" || exit 1 go run main.go --yaml-source-file "${E2E_BMCS_CONF_FILE}" popd diff --git a/test/e2e/basic_ops_test.go b/test/e2e/basic_ops_test.go index 8e8c4c55df..c2e3aeff66 100644 --- a/test/e2e/basic_ops_test.go +++ b/test/e2e/basic_ops_test.go @@ -108,7 +108,7 @@ var _ = Describe("basic", Label("required", "basic"), func() { }) AfterEach(func() { - DumpResources(ctx, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) + DumpResources(ctx, e2eConfig, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) if !skipCleanup { cleanup(ctx, clusterProxy, namespace, cancelWatches, e2eConfig.GetIntervals("default", "wait-namespace-deleted")...) } diff --git a/test/e2e/common.go b/test/e2e/common.go index e23a5a08f2..693374ee40 100644 --- a/test/e2e/common.go +++ b/test/e2e/common.go @@ -3,7 +3,13 @@ package e2e import ( "bytes" "context" + "crypto/tls" + "encoding/base64" + "encoding/json" "fmt" + "io" + "net" + "net/http" "os" "path" "path/filepath" @@ -499,7 +505,7 @@ func dumpCRDS(ctx context.Context, cli client.Client, artifactFolder string) { } // DumpResources dumps resources related to BMO e2e tests as YAML. -func DumpResources(ctx context.Context, clusterProxy framework.ClusterProxy, namespace string, artifactFolder string) { +func DumpResources(ctx context.Context, e2eConfig *Config, clusterProxy framework.ClusterProxy, namespace string, artifactFolder string) { // CAPI resources. framework.DumpAllResources(ctx, framework.DumpAllResourcesInput{ Lister: clusterProxy.GetClient(), @@ -507,4 +513,56 @@ func DumpResources(ctx context.Context, clusterProxy framework.ClusterProxy, nam LogPath: filepath.Join(artifactFolder, "clusters", clusterProxy.GetName(), "resources"), }) dumpCRDS(ctx, clusterProxy.GetClient(), filepath.Join(artifactFolder, "crd")) + if e2eConfig.GetBoolVariable("FETCH_IRONIC_NODES") { + dumpIronicNodes(ctx, e2eConfig, artifactFolder) + } +} + +// dumpIronicNodes dumps the nodes in ironic's view into json file inside the provided artifactFolder. +func dumpIronicNodes(ctx context.Context, e2eConfig *Config, artifactFolder string) { + ironicProvisioningIP := e2eConfig.GetVariable("IRONIC_PROVISIONING_IP") + ironicProvisioningPort := e2eConfig.GetVariable("IRONIC_PROVISIONING_PORT") + ironicURL := fmt.Sprintf("https://%s/v1/nodes", net.JoinHostPort(ironicProvisioningIP, ironicProvisioningPort)) + username := e2eConfig.GetVariable("IRONIC_USERNAME") + password := e2eConfig.GetVariable("IRONIC_PASSWORD") + + // Create HTTP client with TLS settings + tlsConfig := &tls.Config{ + InsecureSkipVerify: true, // #nosec G402 Skip verification as we are using self-signed certificates + } + client := &http.Client{ + Transport: &http.Transport{TLSClientConfig: tlsConfig}, + } + + // Create the request + req, err := http.NewRequestWithContext(ctx, http.MethodGet, ironicURL, http.NoBody) + Expect(err).ToNot(HaveOccurred(), "Failed to create request") + + // Set basic auth header + auth := base64.StdEncoding.EncodeToString([]byte(username + ":" + password)) + req.Header.Add("Authorization", "Basic "+auth) + + // Make the request + resp, err := client.Do(req) + Expect(err).ToNot(HaveOccurred(), "Failed to send request") + Expect(resp.StatusCode).To(Equal(http.StatusOK), fmt.Sprintf("Unexpected Status Code: %d", resp.StatusCode)) + + defer resp.Body.Close() + // Read and output the response + body, err := io.ReadAll(resp.Body) + Expect(err).ToNot(HaveOccurred(), "Failed to read response body") + + var logOutput bytes.Buffer + + // Format the JSON with indentation + err = json.Indent(&logOutput, body, "", " ") + Expect(err).ToNot(HaveOccurred(), "Error formatting JSON") + + file, err := os.Create(path.Join(artifactFolder, "ironic-nodes.json")) + Expect(err).ToNot(HaveOccurred(), "Error creating file") + defer file.Close() + + // Write indented JSON to file + _, err = file.Write(logOutput.Bytes()) + Expect(err).ToNot(HaveOccurred(), "Error writing JSON to file") } diff --git a/test/e2e/config/fixture.yaml b/test/e2e/config/fixture.yaml index a7098e019a..c46532bc7b 100644 --- a/test/e2e/config/fixture.yaml +++ b/test/e2e/config/fixture.yaml @@ -27,6 +27,7 @@ variables: IMAGE_CHECKSUM: "c8fc807773e5354afe61636071771906" CERT_MANAGER_VERSION: "v1.13.1" SSH_CHECK_PROVISIONED: "false" + FETCH_IRONIC_NODES: "false" intervals: inspection/wait-unmanaged: ["1m", "10ms"] diff --git a/test/e2e/config/ironic.yaml b/test/e2e/config/ironic.yaml index 3c39551946..c3681d6e40 100644 --- a/test/e2e/config/ironic.yaml +++ b/test/e2e/config/ironic.yaml @@ -32,6 +32,11 @@ variables: SSH_USERNAME: "root" SSH_PRIV_KEY: "./images/ssh_testkey" SSH_PUB_KEY: "./images/ssh_testkey.pub" + FETCH_IRONIC_NODES: "true" + IRONIC_USERNAME: "changeme" + IRONIC_PASSWORD: "changeme" + IRONIC_PROVISIONING_IP: "localhost" + IRONIC_PROVISIONING_PORT: "6385" intervals: inspection/wait-unmanaged: ["1m", "5s"] diff --git a/test/e2e/e2e_config.go b/test/e2e/e2e_config.go index a4b150807d..3aabe068a0 100644 --- a/test/e2e/e2e_config.go +++ b/test/e2e/e2e_config.go @@ -153,3 +153,15 @@ func (c *Config) GetVariable(varName string) string { Expect(ok).To(BeTrue(), fmt.Sprintf("Configuration variable '%s' not found", varName)) return value } + +// GetBoolVariable returns a variable from environment variables or from the e2e config file as boolean. +func (c *Config) GetBoolVariable(varName string) bool { + value := c.GetVariable(varName) + falseValues := []string{"", "false", "no"} + for _, falseVal := range falseValues { + if strings.EqualFold(value, falseVal) { + return false + } + } + return true +} diff --git a/test/e2e/e2e_suite_test.go b/test/e2e/e2e_suite_test.go index a4edf7a73a..86ed4d5f6f 100644 --- a/test/e2e/e2e_suite_test.go +++ b/test/e2e/e2e_suite_test.go @@ -102,7 +102,7 @@ var _ = SynchronizedBeforeSuite(func() []byte { os.Setenv("KUBECONFIG", clusterProxy.GetKubeconfigPath()) - if e2eConfig.GetVariable("DEPLOY_CERT_MANAGER") != "false" { + if e2eConfig.GetBoolVariable("DEPLOY_CERT_MANAGER") { // Install cert-manager By("Installing cert-manager") err := checkCertManagerAPI(clusterProxy) @@ -122,7 +122,7 @@ var _ = SynchronizedBeforeSuite(func() []byte { bmoIronicNamespace := "baremetal-operator-system" - if e2eConfig.GetVariable("DEPLOY_IRONIC") != "false" { + if e2eConfig.GetBoolVariable("DEPLOY_IRONIC") { // Install Ironic By("Installing Ironic") err := FlakeAttempt(2, func() error { @@ -140,7 +140,7 @@ var _ = SynchronizedBeforeSuite(func() []byte { Expect(err).NotTo(HaveOccurred()) } - if e2eConfig.GetVariable("DEPLOY_BMO") != "false" { + if e2eConfig.GetBoolVariable("DEPLOY_BMO") { // Install BMO By("Installing BMO") err := FlakeAttempt(2, func() error { diff --git a/test/e2e/external_inspection_test.go b/test/e2e/external_inspection_test.go index 264a1e63f8..d7d3117c97 100644 --- a/test/e2e/external_inspection_test.go +++ b/test/e2e/external_inspection_test.go @@ -236,7 +236,7 @@ var _ = Describe("External Inspection", Label("required", "external-inspection") }) AfterEach(func() { - DumpResources(ctx, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) + DumpResources(ctx, e2eConfig, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) if !skipCleanup { cleanup(ctx, clusterProxy, namespace, cancelWatches, e2eConfig.GetIntervals("default", "wait-namespace-deleted")...) } diff --git a/test/e2e/inspection_test.go b/test/e2e/inspection_test.go index 56f04796f3..23c1de63f6 100644 --- a/test/e2e/inspection_test.go +++ b/test/e2e/inspection_test.go @@ -125,7 +125,7 @@ var _ = Describe("Inspection", Label("required", "inspection"), func() { }) AfterEach(func() { - DumpResources(ctx, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) + DumpResources(ctx, e2eConfig, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) if !skipCleanup { cleanup(ctx, clusterProxy, namespace, cancelWatches, e2eConfig.GetIntervals("default", "wait-namespace-deleted")...) } diff --git a/test/e2e/live_iso_test.go b/test/e2e/live_iso_test.go index 04e3f2b646..0b6dc5f8e3 100644 --- a/test/e2e/live_iso_test.go +++ b/test/e2e/live_iso_test.go @@ -135,7 +135,7 @@ var _ = Describe("Live-ISO", Label("required", "live-iso"), func() { }) AfterEach(func() { - DumpResources(ctx, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) + DumpResources(ctx, e2eConfig, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) if !skipCleanup { cleanup(ctx, clusterProxy, namespace, cancelWatches, e2eConfig.GetIntervals("default", "wait-namespace-deleted")...) } diff --git a/test/e2e/provisioning_and_annotation_test.go b/test/e2e/provisioning_and_annotation_test.go index a9637036bd..ccb06da0a3 100644 --- a/test/e2e/provisioning_and_annotation_test.go +++ b/test/e2e/provisioning_and_annotation_test.go @@ -251,11 +251,10 @@ var _ = Describe("Provision, detach, recreate from status and deprovision", Labe Bmh: bmh, State: metal3api.StateAvailable, }, e2eConfig.GetIntervals(specName, "wait-available")...) - }) AfterEach(func() { - DumpResources(ctx, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) + DumpResources(ctx, e2eConfig, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) if !skipCleanup { cleanup(ctx, clusterProxy, namespace, cancelWatches, e2eConfig.GetIntervals("default", "wait-namespace-deleted")...) } diff --git a/test/e2e/re_inspection_test.go b/test/e2e/re_inspection_test.go index 8c81cab95f..ee78d590e2 100644 --- a/test/e2e/re_inspection_test.go +++ b/test/e2e/re_inspection_test.go @@ -106,7 +106,7 @@ var _ = Describe("Re-Inspection", Label("required", "re-inspection"), func() { }) AfterEach(func() { - DumpResources(ctx, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) + DumpResources(ctx, e2eConfig, clusterProxy, namespace.Name, path.Join(artifactFolder, specName)) if !skipCleanup { cleanup(ctx, clusterProxy, namespace, cancelWatches, e2eConfig.GetIntervals("default", "wait-namespace-deleted")...) } diff --git a/test/e2e/upgrade_test.go b/test/e2e/upgrade_test.go index 7c420290d8..f5f37fca98 100644 --- a/test/e2e/upgrade_test.go +++ b/test/e2e/upgrade_test.go @@ -382,7 +382,7 @@ var _ = Describe("Upgrade", Label("optional", "upgrade"), func() { upgradeClusterProxy.Dispose(ctx) }) - if e2eConfig.GetVariable("UPGRADE_DEPLOY_CERT_MANAGER") != "false" { + if e2eConfig.GetBoolVariable("UPGRADE_DEPLOY_CERT_MANAGER") { By("Installing cert-manager on the upgrade cluster") cmVersion := e2eConfig.GetVariable("CERT_MANAGER_VERSION") err := installCertManager(ctx, upgradeClusterProxy, cmVersion)