diff --git a/tests-extension/test/qe/specs/olmv0_opm.go b/tests-extension/test/qe/specs/olmv0_opm.go index 202f6022a3..c845460596 100644 --- a/tests-extension/test/qe/specs/olmv0_opm.go +++ b/tests-extension/test/qe/specs/olmv0_opm.go @@ -70,6 +70,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:43171-[OTP][Skipped:Disconnected] opm render blob from bundle db based index dc based index db file and directory", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:43171-[Skipped:Disconnected] opm render blob from bundle db based index dc based index db file and directory"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("render db-based index image") output, err := opmCLI.Run("render").Args("quay.io/olmqe/olm-index:OLM-2199").Output() o.Expect(err).NotTo(o.HaveOccurred()) @@ -236,6 +239,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:45402-[OTP][Skipped:Disconnected] opm render should automatically pulling in the images used in the deployments", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:45402-[Skipped:Disconnected] opm render should automatically pulling in the images used in the deployments"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("render bundle image") output, err := opmCLI.Run("render").Args("quay.io/olmqe/mta-operator:v0.0.4-45402", "quay.io/olmqe/eclipse-che:7.32.2-45402", "-oyaml").Output() o.Expect(err).NotTo(o.HaveOccurred()) @@ -261,6 +267,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:48438-[OTP][Skipped:Disconnected] opm render should support olm.constraint which is defined in dependencies", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:48438-[Skipped:Disconnected] opm render should support olm.constraint which is defined in dependencies"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("render bundle image") output, err := opmCLI.Run("render").Args("quay.io/olmqe/etcd-bundle:v0.9.2-48438", "-oyaml").Output() o.Expect(err).NotTo(o.HaveOccurred()) @@ -272,6 +281,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:70013-[OTP][Skipped:Disconnected] opm support deprecated channel", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:70013-[Skipped:Disconnected] opm support deprecated channel"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + opmBaseDir := exutil.FixturePath("testdata", "opm", "70013") opmCLI.ExecCommandPath = opmBaseDir @@ -302,6 +314,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:54168-[OTP][Skipped:Disconnected] opm support '--use-http' global flag", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:54168-[Skipped:Disconnected] opm support '--use-http' global flag"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + if os.Getenv("HTTP_PROXY") != "" || os.Getenv("http_proxy") != "" { g.Skip("HTTP_PROXY is not empty - skipping test ...") } @@ -345,6 +360,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:43409-[OTP][Skipped:Disconnected] opm can list catalog contents", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:43409-[Skipped:Disconnected] opm can list catalog contents"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + dcimagetag := "quay.io/olmqe/nginxolm-operator-index:v1" g.By("1, testing with dc format index image") g.By("1.1 list packages") @@ -415,6 +433,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:53869-[OTP][Skipped:Disconnected] opm supports creating a catalog using basic veneer", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:53869-[Skipped:Disconnected] opm supports creating a catalog using basic veneer"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + if os.Getenv("HTTP_PROXY") != "" || os.Getenv("http_proxy") != "" { g.Skip("HTTP_PROXY is not empty - skipping test ...") } @@ -423,7 +444,7 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype g.By("step: create dir catalog") catsrcPathYaml := filepath.Join(opmBaseDir, "catalog-yaml") - err := os.MkdirAll(catsrcPathYaml, 0755) + err = os.MkdirAll(catsrcPathYaml, 0755) o.Expect(err).NotTo(o.HaveOccurred()) g.By("step: create a catalog using basic veneer with yaml format") @@ -646,6 +667,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:53917-[OTP][Skipped:Disconnected] opm can visualize the update graph for a given Operator from an arbitrary version", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:53917-[Skipped:Disconnected] opm can visualize the update graph for a given Operator from an arbitrary version"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + if os.Getenv("HTTP_PROXY") != "" || os.Getenv("http_proxy") != "" { g.Skip("HTTP_PROXY is not empty - skipping test ...") } @@ -702,6 +726,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:60573-[OTP][Skipped:Disconnected] opm exclude bundles with olm.deprecated property when rendering", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:60573-[Skipped:Disconnected] opm exclude bundles with olm.deprecated property when rendering"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + g.By("opm render the sqlite index image message") msg, err := opmCLI.Run("render").Args("quay.io/olmqe/catalogtest-index:v4.12depre", "-oyaml").Output() o.Expect(err).NotTo(o.HaveOccurred()) @@ -720,6 +747,9 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 opm should", g.Label("NonHype }) g.It("PolarionID:73218-[OTP][Skipped:Disconnected] opm alpha render-graph indicate deprecated graph content", g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 opm should PolarionID:73218-[Skipped:Disconnected] opm alpha render-graph indicate deprecated graph content"), func() { + err := opmcli.EnsureContainerPolicy() + o.Expect(err).NotTo(o.HaveOccurred()) + if os.Getenv("HTTP_PROXY") != "" || os.Getenv("http_proxy") != "" { g.Skip("HTTP_PROXY is not empty - skipping test ...") } diff --git a/tests-extension/test/qe/util/opmcli/opm_client.go b/tests-extension/test/qe/util/opmcli/opm_client.go index 82c4fc4960..466ee5d613 100644 --- a/tests-extension/test/qe/util/opmcli/opm_client.go +++ b/tests-extension/test/qe/util/opmcli/opm_client.go @@ -12,6 +12,7 @@ import ( "path/filepath" "runtime/debug" "strings" + "sync" g "github.com/onsi/ginkgo/v2" e2e "k8s.io/kubernetes/test/e2e/framework" @@ -232,3 +233,62 @@ func DeleteDir(filePathStr string, filePre string) bool { return true } } + +var ( + // policyMutex ensures thread-safe access to container policy file creation + policyMutex sync.Mutex + // policyCreated tracks whether policy.json has been created to avoid redundant operations + policyCreated bool +) + +// EnsureContainerPolicy ensures that the containers policy.json file exists. +// Creates ${HOME}/.config/containers/policy.json with insecureAcceptAnything policy if it doesn't exist. +// This is required for OPM commands that interact with container images. +// This function is thread-safe and can be called concurrently from parallel test cases. +// Returns error if HOME is not set or if file creation fails. +func EnsureContainerPolicy() error { + // Use mutex to ensure only one goroutine creates the file at a time + policyMutex.Lock() + defer policyMutex.Unlock() + + // If already created in a previous call, just verify it exists + if policyCreated { + return nil + } + + homeDir := os.Getenv("HOME") + if homeDir == "" { + return fmt.Errorf("HOME environment variable is not set") + } + policyDir := filepath.Join(homeDir, ".config", "containers") + policyFile := filepath.Join(policyDir, "policy.json") + + // Check if policy.json exists + if _, err := os.Stat(policyFile); os.IsNotExist(err) { + // Create directory if it doesn't exist + if err := os.MkdirAll(policyDir, 0755); err != nil { + return fmt.Errorf("failed to create directory %s: %w", policyDir, err) + } + + // Create policy.json with insecure accept anything policy + policyContent := `{ + "default": [ + { + "type": "insecureAcceptAnything" + } + ] +} +` + if err := os.WriteFile(policyFile, []byte(policyContent), 0644); err != nil { + return fmt.Errorf("failed to create policy.json at %s: %w", policyFile, err) + } + e2e.Logf("Created containers policy.json at: %s", policyFile) + policyCreated = true + } else if err != nil { + return fmt.Errorf("failed to check policy.json at %s: %w", policyFile, err) + } else { + e2e.Logf("Containers policy.json already exists at: %s", policyFile) + policyCreated = true + } + return nil +}