From b51eec3ac85b0c71f2e809c1408cc17a628283d8 Mon Sep 17 00:00:00 2001 From: Bruno Andrade Date: Tue, 10 Mar 2026 19:49:52 -0300 Subject: [PATCH] tests-extension: replace etcd usage in 32613/47181 and update 27680 Prometheus flow --- tests-extension/pkg/bindata/qe/bindata.go | 609 ++++++++++++++++++ .../test/qe/specs/olmv0_defaultoption.go | 244 ++++--- .../test/qe/specs/olmv0_nonallns.go | 93 ++- .../olm/cm-csv-sample-24387-modified.yaml | 286 ++++++++ .../qe/testdata/olm/cm-csv-sample-24387.yaml | 283 ++++++++ 5 files changed, 1385 insertions(+), 130 deletions(-) create mode 100644 tests-extension/test/qe/testdata/olm/cm-csv-sample-24387-modified.yaml create mode 100644 tests-extension/test/qe/testdata/olm/cm-csv-sample-24387.yaml diff --git a/tests-extension/pkg/bindata/qe/bindata.go b/tests-extension/pkg/bindata/qe/bindata.go index 92c7ed5ac0..d84660d2cb 100644 --- a/tests-extension/pkg/bindata/qe/bindata.go +++ b/tests-extension/pkg/bindata/qe/bindata.go @@ -14,6 +14,8 @@ // test/qe/testdata/olm/cm-21824-wrong.yaml // test/qe/testdata/olm/cm-25644-etcd-csv.yaml // test/qe/testdata/olm/cm-csv-etcd.yaml +// test/qe/testdata/olm/cm-csv-sample-24387-modified.yaml +// test/qe/testdata/olm/cm-csv-sample-24387.yaml // test/qe/testdata/olm/cm-namespaceconfig.yaml // test/qe/testdata/olm/cm-template.yaml // test/qe/testdata/olm/configmap-ectd-alpha-beta.yaml @@ -2853,6 +2855,609 @@ func testQeTestdataOlmCmCsvEtcdYaml() (*asset, error) { return a, nil } +var _testQeTestdataOlmCmCsvSample24387ModifiedYaml = []byte(`apiVersion: template.openshift.io/v1 +kind: Template +metadata: + name: cm-csv-sample-24387-modified-template +objects: +- apiVersion: v1 + kind: ConfigMap + metadata: + name: "${NAME}" + namespace: "${NAMESPACE}" + data: + clusterServiceVersions: | + - apiVersion: operators.coreos.com/v1alpha1 + kind: ClusterServiceVersion + metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "cache.example.com/v1alpha1", + "kind": "Sample", + "metadata": { + "name": "sample-sample" + }, + "spec": null + } + ] + capabilities: Basic Install + createdAt: "2026-03-09T09:27:42Z" + operators.operatorframework.io/builder: operator-sdk-v1.31.0-ocp + operators.operatorframework.io/project_layout: ansible.sdk.operatorframework.io/v1 + name: sample-operator.v0.0.1 + namespace: "${NAMESPACE}" + spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - kind: Sample + name: samples.cache.example.com + version: v1alpha1 + description: An operator for QE testing + displayName: Sample Operator + icon: + - base64data: "" + mediatype: "" + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - "" + resources: + - secrets + - pods + - pods/exec + - pods/log + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - cache.example.com + resources: + - samples + - samples/status + - samples/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + serviceAccountName: sample-operator-controller-manager + deployments: + - label: + control-plane: controller-manager + name: sample-operator-controller-manager + spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + strategy: {} + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + containers: + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=0 + image: quay.io/olmqe/kube-rbac-proxy@sha256:3789634ce5991a19bc56f3143e739d7887f1e817c0a556a4f51e27b18ab3c5d6 + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + - args: + - --health-probe-bind-address=:6789 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + - --leader-election-id=sample-operator + env: + - name: ANSIBLE_GATHERING + value: explicit + image: quay.io/olmqe/sample-operator@sha256:e83e6ae660fe7c94ec61616c622dce6640bf912667ede0c17881e10ad8812be3 + livenessProbe: + httpGet: + path: /healthz + port: 6789 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 6789 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 768Mi + requests: + cpu: 10m + memory: 256Mi + securityContext: + allowPrivilegeEscalation: false + securityContext: + runAsNonRoot: true + serviceAccountName: sample-operator-controller-manager + terminationGracePeriodSeconds: 10 + permissions: + - rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + serviceAccountName: sample-operator-controller-manager + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - sample + - nginx + links: + - name: Sample Operator + url: https://sample-operator.domain + maintainers: + - email: jiazha@redhat.com + name: JianZhang + maturity: alpha + provider: + name: Jian + version: 0.0.1 + customResourceDefinitions: | + - apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + metadata: + name: samples.cache.example.com + spec: + group: cache.example.com + names: + kind: Sample + listKind: SampleList + plural: samples + singular: sample + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Sample is the Schema for the samples API + properties: + apiVersion: + description: APIVersion defines the versioned schema of this representation of an object. + type: string + kind: + description: Kind is a string value representing the REST resource this object represents. + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Sample + type: object + properties: + propertyIncludedTest: + type: string + x-kubernetes-preserve-unknown-fields: true + status: + description: Status defines the observed state of Sample + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + packages: | + - packageName: sample-operator + defaultChannel: alpha + channels: + - name: alpha + currentCSV: sample-operator.v0.0.1 +parameters: +- name: NAME +- name: NAMESPACE +`) + +func testQeTestdataOlmCmCsvSample24387ModifiedYamlBytes() ([]byte, error) { + return _testQeTestdataOlmCmCsvSample24387ModifiedYaml, nil +} + +func testQeTestdataOlmCmCsvSample24387ModifiedYaml() (*asset, error) { + bytes, err := testQeTestdataOlmCmCsvSample24387ModifiedYamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/qe/testdata/olm/cm-csv-sample-24387-modified.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + +var _testQeTestdataOlmCmCsvSample24387Yaml = []byte(`apiVersion: template.openshift.io/v1 +kind: Template +metadata: + name: cm-csv-sample-24387-template +objects: +- apiVersion: v1 + kind: ConfigMap + metadata: + name: "${NAME}" + namespace: "${NAMESPACE}" + data: + clusterServiceVersions: | + - apiVersion: operators.coreos.com/v1alpha1 + kind: ClusterServiceVersion + metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "cache.example.com/v1alpha1", + "kind": "Sample", + "metadata": { + "name": "sample-sample" + }, + "spec": null + } + ] + capabilities: Basic Install + createdAt: "2026-03-09T09:27:42Z" + operators.operatorframework.io/builder: operator-sdk-v1.31.0-ocp + operators.operatorframework.io/project_layout: ansible.sdk.operatorframework.io/v1 + name: sample-operator.v0.0.1 + namespace: "${NAMESPACE}" + spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - kind: Sample + name: samples.cache.example.com + version: v1alpha1 + description: An operator for QE testing + displayName: Sample Operator + icon: + - base64data: "" + mediatype: "" + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - "" + resources: + - secrets + - pods + - pods/exec + - pods/log + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - cache.example.com + resources: + - samples + - samples/status + - samples/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + serviceAccountName: sample-operator-controller-manager + deployments: + - label: + control-plane: controller-manager + name: sample-operator-controller-manager + spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + strategy: {} + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + containers: + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=0 + image: quay.io/olmqe/kube-rbac-proxy@sha256:3789634ce5991a19bc56f3143e739d7887f1e817c0a556a4f51e27b18ab3c5d6 + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + - args: + - --health-probe-bind-address=:6789 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + - --leader-election-id=sample-operator + env: + - name: ANSIBLE_GATHERING + value: explicit + image: quay.io/olmqe/sample-operator@sha256:e83e6ae660fe7c94ec61616c622dce6640bf912667ede0c17881e10ad8812be3 + livenessProbe: + httpGet: + path: /healthz + port: 6789 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 6789 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 768Mi + requests: + cpu: 10m + memory: 256Mi + securityContext: + allowPrivilegeEscalation: false + securityContext: + runAsNonRoot: true + serviceAccountName: sample-operator-controller-manager + terminationGracePeriodSeconds: 10 + permissions: + - rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + serviceAccountName: sample-operator-controller-manager + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - sample + - nginx + links: + - name: Sample Operator + url: https://sample-operator.domain + maintainers: + - email: jiazha@redhat.com + name: JianZhang + maturity: alpha + provider: + name: Jian + version: 0.0.1 + customResourceDefinitions: | + - apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + metadata: + name: samples.cache.example.com + spec: + group: cache.example.com + names: + kind: Sample + listKind: SampleList + plural: samples + singular: sample + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Sample is the Schema for the samples API + properties: + apiVersion: + description: APIVersion defines the versioned schema of this representation of an object. + type: string + kind: + description: Kind is a string value representing the REST resource this object represents. + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Sample + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: Status defines the observed state of Sample + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + packages: | + - packageName: sample-operator + defaultChannel: alpha + channels: + - name: alpha + currentCSV: sample-operator.v0.0.1 +parameters: +- name: NAME +- name: NAMESPACE +`) + +func testQeTestdataOlmCmCsvSample24387YamlBytes() ([]byte, error) { + return _testQeTestdataOlmCmCsvSample24387Yaml, nil +} + +func testQeTestdataOlmCmCsvSample24387Yaml() (*asset, error) { + bytes, err := testQeTestdataOlmCmCsvSample24387YamlBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{name: "test/qe/testdata/olm/cm-csv-sample-24387.yaml", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)} + a := &asset{bytes: bytes, info: info} + return a, nil +} + var _testQeTestdataOlmCmNamespaceconfigYaml = []byte(`apiVersion: template.openshift.io/v1 kind: Template metadata: @@ -18008,6 +18613,8 @@ var _bindata = map[string]func() (*asset, error){ "test/qe/testdata/olm/cm-21824-wrong.yaml": testQeTestdataOlmCm21824WrongYaml, "test/qe/testdata/olm/cm-25644-etcd-csv.yaml": testQeTestdataOlmCm25644EtcdCsvYaml, "test/qe/testdata/olm/cm-csv-etcd.yaml": testQeTestdataOlmCmCsvEtcdYaml, + "test/qe/testdata/olm/cm-csv-sample-24387-modified.yaml": testQeTestdataOlmCmCsvSample24387ModifiedYaml, + "test/qe/testdata/olm/cm-csv-sample-24387.yaml": testQeTestdataOlmCmCsvSample24387Yaml, "test/qe/testdata/olm/cm-namespaceconfig.yaml": testQeTestdataOlmCmNamespaceconfigYaml, "test/qe/testdata/olm/cm-template.yaml": testQeTestdataOlmCmTemplateYaml, "test/qe/testdata/olm/configmap-ectd-alpha-beta.yaml": testQeTestdataOlmConfigmapEctdAlphaBetaYaml, @@ -18198,6 +18805,8 @@ var _bintree = &bintree{nil, map[string]*bintree{ "cm-21824-wrong.yaml": {testQeTestdataOlmCm21824WrongYaml, map[string]*bintree{}}, "cm-25644-etcd-csv.yaml": {testQeTestdataOlmCm25644EtcdCsvYaml, map[string]*bintree{}}, "cm-csv-etcd.yaml": {testQeTestdataOlmCmCsvEtcdYaml, map[string]*bintree{}}, + "cm-csv-sample-24387-modified.yaml": {testQeTestdataOlmCmCsvSample24387ModifiedYaml, map[string]*bintree{}}, + "cm-csv-sample-24387.yaml": {testQeTestdataOlmCmCsvSample24387Yaml, map[string]*bintree{}}, "cm-namespaceconfig.yaml": {testQeTestdataOlmCmNamespaceconfigYaml, map[string]*bintree{}}, "cm-template.yaml": {testQeTestdataOlmCmTemplateYaml, map[string]*bintree{}}, "configmap-ectd-alpha-beta.yaml": {testQeTestdataOlmConfigmapEctdAlphaBetaYaml, map[string]*bintree{}}, diff --git a/tests-extension/test/qe/specs/olmv0_defaultoption.go b/tests-extension/test/qe/specs/olmv0_defaultoption.go index ba30983b4f..4ba1d91d60 100644 --- a/tests-extension/test/qe/specs/olmv0_defaultoption.go +++ b/tests-extension/test/qe/specs/olmv0_defaultoption.go @@ -337,18 +337,27 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { exutil.SkipBaselineCaps(oc, "None") exutil.SkipIfDisableDefaultCatalogsource(oc) + packageName := "odf-prometheus-operator" + channel, err := oc.AsAdmin().WithoutNamespace().Run("get").Args( + "packagemanifest", "-n", "openshift-marketplace", packageName, "-o=jsonpath={.status.defaultChannel}", + ).Output() + if err != nil || strings.TrimSpace(channel) == "" { + g.Skip("SKIP:PackageMissing odf-prometheus-operator does not exist in catalog redhat-operators") + } + channel = strings.TrimSpace(channel) + g.By("The relatedImages should exist") - msg, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("packagemanifest", "-n", "openshift-marketplace", "prometheus", "-o=jsonpath={.status.channels[?(.name=='beta')].currentCSVDesc.relatedImages}").Output() + msg, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("packagemanifest", "-n", "openshift-marketplace", packageName, fmt.Sprintf("-o=jsonpath={.status.channels[?(.name=='%s')].currentCSVDesc.relatedImages}", channel)).Output() o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(msg).NotTo(o.BeEmpty()) g.By("The minKubeVersion should exist") - msg, err = oc.AsAdmin().WithoutNamespace().Run("get").Args("packagemanifest", "-n", "openshift-marketplace", "prometheus", "-o=jsonpath={.status.channels[?(.name=='beta')].currentCSVDesc.minKubeVersion}").Output() + msg, err = oc.AsAdmin().WithoutNamespace().Run("get").Args("packagemanifest", "-n", "openshift-marketplace", packageName, fmt.Sprintf("-o=jsonpath={.status.channels[?(.name=='%s')].currentCSVDesc.minKubeVersion}", channel)).Output() o.Expect(err).NotTo(o.HaveOccurred()) o.Expect(msg).NotTo(o.BeEmpty()) - g.By("nativeAPI is optional for prometheus") - _, err = oc.AsAdmin().WithoutNamespace().Run("get").Args("packagemanifest", "-n", "openshift-marketplace", "prometheus", "-o=jsonpath={.status.channels[?(.name=='beta')].currentCSVDesc.nativeAPIs}").Output() + g.By("nativeAPI is optional for odf-prometheus-operator") + _, err = oc.AsAdmin().WithoutNamespace().Run("get").Args("packagemanifest", "-n", "openshift-marketplace", packageName, fmt.Sprintf("-o=jsonpath={.status.channels[?(.name=='%s')].currentCSVDesc.nativeAPIs}", channel)).Output() o.Expect(err).NotTo(o.HaveOccurred()) }) @@ -557,10 +566,11 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { g.It("PolarionID:24387-[OTP][Skipped:Disconnected]Any CRD upgrade is allowed if there is only one owner in a cluster [Disruptive]", func() { architecture.SkipNonAmd64SingleArch(oc) exutil.SkipBaselineCaps(oc, "None") - exutil.SkipIfDisableDefaultCatalogsource(oc) buildDir := exutil.FixturePath("testdata", "olm") - csTemplate := filepath.Join(buildDir, "catalogsource-image.yaml") + cmTemplate := filepath.Join(buildDir, "cm-csv-sample-24387.yaml") + cmModifiedTemplate := filepath.Join(buildDir, "cm-csv-sample-24387-modified.yaml") + csTemplate := filepath.Join(buildDir, "catalogsource-configmap.yaml") subFile := filepath.Join(buildDir, "olm-subscription.yaml") ogTemplate := filepath.Join(buildDir, "operatorgroup.yaml") @@ -568,13 +578,32 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { itName := g.CurrentSpecReport().FullText() dr.AddIr(itName) + cm := olmv0util.ConfigMapDescription{ + Name: "cm-sample-24387", + Namespace: oc.Namespace(), + Template: cmTemplate, + } + cmModified := olmv0util.ConfigMapDescription{ + Name: "cm-sample-24387-modified", + Namespace: oc.Namespace(), + Template: cmModifiedTemplate, + } cs := olmv0util.CatalogSourceDescription{ Name: "cs-24387", - Namespace: "openshift-marketplace", + Namespace: oc.Namespace(), DisplayName: "OLM QE Operators", Publisher: "bandrade", - SourceType: "grpc", - Address: "quay.io/olmqe/etcd-index-24387:5.0", + SourceType: "configmap", + Address: cm.Name, + Template: csTemplate, + } + csModified := olmv0util.CatalogSourceDescription{ + Name: "cs-24387-modified", + Namespace: oc.Namespace(), + DisplayName: "OLM QE Operators Modified", + Publisher: "bandrade", + SourceType: "configmap", + Address: cmModified.Name, Template: csTemplate, } og := olmv0util.OperatorGroupDescription{ @@ -583,48 +612,53 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { Template: ogTemplate, } sub := olmv0util.SubscriptionDescription{ - SubName: "etcd", + SubName: "sample-operator", Namespace: oc.Namespace(), - CatalogSourceName: "community-operators", - CatalogSourceNamespace: "openshift-marketplace", - Channel: "singlenamespace-alpha", + CatalogSourceName: cs.Name, + CatalogSourceNamespace: oc.Namespace(), + Channel: "alpha", IpApproval: "Automatic", - OperatorPackage: "etcd", + OperatorPackage: "sample-operator", SingleNamespace: true, Template: subFile, - StartingCSV: "etcdoperator.v0.9.4", + StartingCSV: "sample-operator.v0.0.1", } subModified := olmv0util.SubscriptionDescription{ - SubName: "etcd", + SubName: "sample-operator", Namespace: oc.Namespace(), - CatalogSourceName: cs.Name, - CatalogSourceNamespace: "openshift-marketplace", + CatalogSourceName: csModified.Name, + CatalogSourceNamespace: oc.Namespace(), IpApproval: "Automatic", Template: subFile, - Channel: "singlenamespace-alpha", - OperatorPackage: "etcd", - StartingCSV: "etcdoperator.v0.9.4", + Channel: "alpha", + OperatorPackage: "sample-operator", + StartingCSV: "sample-operator.v0.0.1", SingleNamespace: true, } - e2e.Logf("Check if %v exists in the %v catalog", sub.OperatorPackage, sub.CatalogSourceName) - exists, err := olmv0util.ClusterPackageExists(oc, sub) - if !exists { - g.Skip("SKIP:PackageMissing etcd does not exist in catalog community-operators") - } - o.Expect(err).NotTo(o.HaveOccurred()) - + defer cm.Delete(itName, dr) + defer cmModified.Delete(itName, dr) defer cs.Delete(itName, dr) - cs.Create(oc, itName, dr) + defer csModified.Delete(itName, dr) + cm.Create(oc, itName, dr) + cs.CreateWithCheck(oc, itName, dr) og.CreateWithCheck(oc, itName, dr) sub.Create(oc, itName, dr) sub.Delete(itName, dr) sub.DeleteCSV(itName, dr) + cmModified.Create(oc, itName, dr) + csModified.CreateWithCheck(oc, itName, dr) subModified.Create(oc, itName, dr) - crdYamlOutput, err := oc.AsAdmin().Run("get").Args("crd", "etcdclusters.etcd.database.coreos.com", "-o=yaml").Output() - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(crdYamlOutput).To(o.ContainSubstring("propertyIncludedTest")) + + err := wait.PollUntilContextTimeout(context.TODO(), 5*time.Second, 120*time.Second, false, func(ctx context.Context) (bool, error) { + crdYamlOutput, err := oc.AsAdmin().Run("get").Args("crd", "samples.cache.example.com", "-o=yaml").Output() + if err != nil { + return false, err + } + return strings.Contains(crdYamlOutput, "propertyIncludedTest"), nil + }) + exutil.AssertWaitPollNoErr(err, "propertyIncludedTest is not found in samples.cache.example.com") }) g.It("PolarionID:42970-[OTP]OperatorGroup status indicates cardinality conflicts - SingleNamespace", func() { @@ -784,12 +818,12 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { subTemplate := filepath.Join(buildDir, "olm-subscription.yaml") cs := olmv0util.CatalogSourceDescription{ - Name: "prometheus-dependency-cs", - Namespace: "openshift-marketplace", + Name: "learn-32613", + Namespace: oc.Namespace(), DisplayName: "OLM QE", Publisher: "OLM QE", SourceType: "grpc", - Address: "quay.io/olmqe/etcd-prometheus-dependency-index:11.0", + Address: "quay.io/olmqe/learn-operator-index:v25", Template: csTemplate, } dr := make(olmv0util.DescriberResrouce) @@ -809,36 +843,33 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { sub := olmv0util.SubscriptionDescription{ SubName: "sub-32613", Namespace: oc.Namespace(), - CatalogSourceName: "prometheus-dependency-cs", - CatalogSourceNamespace: "openshift-marketplace", - Channel: "singlenamespace-alpha", + CatalogSourceName: cs.Name, + CatalogSourceNamespace: cs.Namespace, + Channel: "beta", IpApproval: "Automatic", - OperatorPackage: "etcd-service-monitor", - StartingCSV: "etcdoperator.v0.9.4", + OperatorPackage: "learn", + StartingCSV: "learn-operator.v0.0.3", SingleNamespace: true, Template: subTemplate, } + defer sub.Delete(itName, dr) + defer sub.DeleteCSV(itName, dr) sub.Create(oc, itName, dr) - olmv0util.NewCheck("expect", exutil.AsAdmin, exutil.WithoutNamespace, exutil.Compare, "Succeeded", exutil.Ok, []string{"csv", "etcdoperator.v0.9.4", "-n", oc.Namespace(), "-o=jsonpath={.status.phase}"}).Check(oc) - - g.By("Assert that prometheus dependency is resolved") - msg, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("csv", "-n", oc.Namespace()).Output() - o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(msg).To(o.ContainSubstring("prometheus")) + olmv0util.NewCheck("expect", exutil.AsAdmin, exutil.WithoutNamespace, exutil.Compare, "Succeeded", exutil.Ok, []string{"csv", "learn-operator.v0.0.3", "-n", oc.Namespace(), "-o=jsonpath={.status.phase}"}).Check(oc) sub = olmv0util.SubscriptionDescription{ - SubName: "prometheus-32613", + SubName: "sub-32613-conflict", Namespace: oc.Namespace(), - CatalogSourceName: "community-operators", - CatalogSourceNamespace: "openshift-marketplace", + CatalogSourceName: cs.Name, + CatalogSourceNamespace: cs.Namespace, IpApproval: "Automatic", Channel: "beta", - OperatorPackage: "prometheus", + OperatorPackage: "learn", SingleNamespace: true, Template: subTemplate, } sub.CreateWithoutCheck(oc, itName, dr) - olmv0util.NewCheck("expect", exutil.AsAdmin, exutil.WithoutNamespace, exutil.Contain, "prometheus-beta-community-operators-openshift-marketplace exists", exutil.Ok, []string{"subs", "prometheus-32613", "-n", oc.Namespace(), "-o=jsonpath={.status.conditions..message}"}).Check(oc) + olmv0util.NewCheck("expect", exutil.AsAdmin, exutil.WithoutNamespace, exutil.Contain, "ConstraintsNotSatisfiable", exutil.Ok, []string{"subs", sub.SubName, "-n", oc.Namespace(), "-o=jsonpath={.status.conditions..reason}"}).Check(oc) }) g.It("PolarionID:24055-[OTP][Skipped:Disconnected]Check for defaultChannel mandatory field when having multiple channels", func() { @@ -3201,7 +3232,6 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { g.It("PolarionID:47149-[OTP][Skipped:Disconnected]Conjunctive constraint of one package and one GVK", func() { olmv0util.ValidateAccessEnvironment(oc) architecture.SkipNonAmd64SingleArch(oc) - exutil.SkipIfDisableDefaultCatalogsource(oc) dr := make(olmv0util.DescriberResrouce) itName := g.CurrentSpecReport().FullText() @@ -3210,15 +3240,14 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { buildPruningBaseDir := exutil.FixturePath("testdata", "olm") subTemplate := filepath.Join(buildPruningBaseDir, "olm-subscription.yaml") ogTemplate := filepath.Join(buildPruningBaseDir, "operatorgroup.yaml") - csImageTemplate := filepath.Join(buildPruningBaseDir, "catalogsource-image.yaml") cs := olmv0util.CatalogSourceDescription{ Name: "ocp-47149", Namespace: oc.Namespace(), DisplayName: "ocp-47149", Publisher: "OLM QE", SourceType: "grpc", - Address: "quay.io/olmqe/etcd-47149:1.0", - Template: csImageTemplate, + Address: "quay.io/olmqe/ditto-index:41565-cache", + Template: filepath.Join(buildPruningBaseDir, "catalogsource-image-extract.yaml"), } cs.CreateWithCheck(oc, itName, dr) @@ -3230,34 +3259,40 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { og.CreateWithCheck(oc, itName, dr) sub := olmv0util.SubscriptionDescription{ - SubName: "etcd", + SubName: "sub-47149", Namespace: oc.Namespace(), CatalogSourceName: cs.Name, CatalogSourceNamespace: cs.Namespace, - Channel: "singlenamespace-alpha", + Channel: "alpha", IpApproval: "Automatic", - OperatorPackage: "etcd", + OperatorPackage: "ditto-operator", SingleNamespace: true, Template: subTemplate, } sub.Create(oc, itName, dr) waitErr := wait.PollUntilContextTimeout(context.TODO(), 15*time.Second, 360*time.Second, false, func(ctx context.Context) (bool, error) { - csvList, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("csv", "-n", sub.Namespace).Output() + csvList, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("csv", "-n", sub.Namespace, "-o=jsonpath={range .items[*]}{@.metadata.name}{\",\"}{@.status.phase}{\"\\n\"}{end}").Output() o.Expect(err).NotTo(o.HaveOccurred()) - lines := strings.Split(csvList, "\n") - for _, line := range lines { - if strings.Contains(line, "prometheusoperator") { - if strings.Contains(line, "Succeeded") { - return true, nil - } - return false, nil + hasDittoReady := false + hasPlanetscaleReady := false + for _, line := range strings.Split(strings.TrimSpace(csvList), "\n") { + parts := strings.Split(line, ",") + if len(parts) != 2 { + continue + } + name := parts[0] + phase := parts[1] + if strings.Contains(name, "ditto-operator") && (phase == "Succeeded" || phase == "Installing") { + hasDittoReady = true + } + if strings.Contains(name, "planetscale-operator") && (phase == "Succeeded" || phase == "Installing") { + hasPlanetscaleReady = true } } - return false, nil + return hasDittoReady && hasPlanetscaleReady, nil }) - exutil.AssertWaitPollNoErr(waitErr, "csv prometheusoperator is not Succeeded") - olmv0util.NewCheck("expect", exutil.AsUser, exutil.WithoutNamespace, exutil.Compare, "Succeeded", exutil.Ok, []string{"csv", "etcdoperator.v0.9.4", "-n", sub.Namespace, "-o=jsonpath={.status.phase}"}).Check(oc) + exutil.AssertWaitPollNoErr(waitErr, "csv ditto-operator or planetscale-operator was not Succeeded nor Installing") }) // Polarion ID: 47181 @@ -3272,14 +3307,14 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { buildPruningBaseDir := exutil.FixturePath("testdata", "olm") subTemplate := filepath.Join(buildPruningBaseDir, "olm-subscription.yaml") ogTemplate := filepath.Join(buildPruningBaseDir, "operatorgroup.yaml") - csImageTemplate := filepath.Join(buildPruningBaseDir, "catalogsource-image.yaml") + csImageTemplate := filepath.Join(buildPruningBaseDir, "catalogsource-image-extract.yaml") cs := olmv0util.CatalogSourceDescription{ Name: "ocp-47181", Namespace: oc.Namespace(), DisplayName: "ocp-47181", Publisher: "OLM QE", SourceType: "grpc", - Address: "quay.io/olmqe/etcd-47181:1.0", + Address: "quay.io/olmqe/ditto-index:41565-cache", Template: csImageTemplate, } cs.CreateWithCheck(oc, itName, dr) @@ -3292,26 +3327,49 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { og.CreateWithCheck(oc, itName, dr) sub := olmv0util.SubscriptionDescription{ - SubName: "etcd", + SubName: "sub-47181", Namespace: oc.Namespace(), CatalogSourceName: cs.Name, CatalogSourceNamespace: cs.Namespace, - Channel: "singlenamespace-alpha", + Channel: "alpha", IpApproval: "Automatic", - OperatorPackage: "etcd", + OperatorPackage: "ditto-operator", SingleNamespace: true, Template: subTemplate, } sub.Create(oc, itName, dr) - olmv0util.NewCheck("expect", exutil.AsUser, exutil.WithoutNamespace, exutil.Compare, "Succeeded", exutil.Ok, []string{"csv", sub.InstalledCSV, "-n", sub.Namespace, "-o=jsonpath={.status.phase}"}).Check(oc) + waitErr := wait.PollUntilContextTimeout(context.TODO(), 10*time.Second, 360*time.Second, false, func(ctx context.Context) (bool, error) { + csvList, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("csv", "-n", sub.Namespace, "-o=jsonpath={range .items[*]}{@.metadata.name}{\",\"}{@.status.phase}{\"\\n\"}{end}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + hasDittoReady := false + hasPlanetscaleReady := false + for _, line := range strings.Split(strings.TrimSpace(csvList), "\n") { + parts := strings.Split(line, ",") + if len(parts) != 2 { + continue + } + name := parts[0] + phase := parts[1] + if strings.Contains(name, "ditto-operator") && (phase == "Succeeded" || phase == "Installing") { + hasDittoReady = true + } + if strings.Contains(name, "planetscale-operator") && (phase == "Succeeded" || phase == "Installing") { + hasPlanetscaleReady = true + } + } + return hasDittoReady && hasPlanetscaleReady, nil + }) + if waitErr != nil { + olmv0util.LogDebugInfo(oc, sub.Namespace, "pod", "ip", "csv", "events") + } + exutil.AssertWaitPollNoErr(waitErr, "csv ditto-operator or planetscale-operator was not Succeeded nor Installing") }) // Polarion ID: 47179 g.It("PolarionID:47179-[OTP][Skipped:Disconnected]Disjunctive constraint of one package and one GVK", func() { olmv0util.ValidateAccessEnvironment(oc) architecture.SkipNonAmd64SingleArch(oc) - exutil.SkipIfDisableDefaultCatalogsource(oc) dr := make(olmv0util.DescriberResrouce) itName := g.CurrentSpecReport().FullText() @@ -3320,15 +3378,14 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { buildPruningBaseDir := exutil.FixturePath("testdata", "olm") subTemplate := filepath.Join(buildPruningBaseDir, "olm-subscription.yaml") ogTemplate := filepath.Join(buildPruningBaseDir, "operatorgroup.yaml") - csImageTemplate := filepath.Join(buildPruningBaseDir, "catalogsource-image.yaml") cs := olmv0util.CatalogSourceDescription{ Name: "ocp-47179", Namespace: oc.Namespace(), DisplayName: "ocp-47179", Publisher: "OLM QE", SourceType: "grpc", - Address: "quay.io/olmqe/etcd-47179:1.0", - Template: csImageTemplate, + Address: "quay.io/olmqe/ditto-index:41565-cache", + Template: filepath.Join(buildPruningBaseDir, "catalogsource-image-extract.yaml"), } cs.CreateWithCheck(oc, itName, dr) @@ -3340,19 +3397,40 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 optional should", func() { og.CreateWithCheck(oc, itName, dr) sub := olmv0util.SubscriptionDescription{ - SubName: "etcd", + SubName: "sub-47179", Namespace: oc.Namespace(), CatalogSourceName: cs.Name, CatalogSourceNamespace: cs.Namespace, - Channel: "singlenamespace-alpha", + Channel: "alpha", IpApproval: "Automatic", - OperatorPackage: "etcd", + OperatorPackage: "ditto-operator", SingleNamespace: true, Template: subTemplate, } sub.Create(oc, itName, dr) - olmv0util.NewCheck("expect", exutil.AsUser, exutil.WithoutNamespace, exutil.Contain, "red-hat-camel-k-operator", exutil.Ok, []string{"csv", "-n", sub.Namespace}).Check(oc) + waitErr := wait.PollUntilContextTimeout(context.TODO(), 10*time.Second, 360*time.Second, false, func(ctx context.Context) (bool, error) { + csvList, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("csv", "-n", sub.Namespace, "-o=jsonpath={range .items[*]}{@.metadata.name}{\",\"}{@.status.phase}{\"\\n\"}{end}").Output() + o.Expect(err).NotTo(o.HaveOccurred()) + hasDittoReady := false + hasPlanetscaleReady := false + for _, line := range strings.Split(strings.TrimSpace(csvList), "\n") { + parts := strings.Split(line, ",") + if len(parts) != 2 { + continue + } + name := parts[0] + phase := parts[1] + if strings.Contains(name, "ditto-operator") && (phase == "Succeeded" || phase == "Installing") { + hasDittoReady = true + } + if strings.Contains(name, "planetscale-operator") && (phase == "Succeeded" || phase == "Installing") { + hasPlanetscaleReady = true + } + } + return hasDittoReady && hasPlanetscaleReady, nil + }) + exutil.AssertWaitPollNoErr(waitErr, "csv ditto-operator or planetscale-operator was not Succeeded nor Installing") }) // Polarion ID: 20981 diff --git a/tests-extension/test/qe/specs/olmv0_nonallns.go b/tests-extension/test/qe/specs/olmv0_nonallns.go index 7119182d87..b376cfb4ee 100644 --- a/tests-extension/test/qe/specs/olmv0_nonallns.go +++ b/tests-extension/test/qe/specs/olmv0_nonallns.go @@ -378,25 +378,11 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 within a namespace", func() { itName = g.CurrentSpecReport().FullText() ns = oc.Namespace() buildPruningBaseDir = exutil.FixturePath("testdata", "olm") - csImageTemplate = filepath.Join(buildPruningBaseDir, "catalogsource-image.yaml") ogSingleTemplate = filepath.Join(buildPruningBaseDir, "operatorgroup.yaml") + prometheusTemplate = filepath.Join(buildPruningBaseDir, "prometheus-nodeaffinity.yaml") subTemplate = filepath.Join(buildPruningBaseDir, "olm-subscription.yaml") - csvName = "etcdoperator.v0.9.4" ) - g.By("Start to create the CatalogSource CR") - catsrc := olmv0util.CatalogSourceDescription{ - Name: "prometheus-dependency-27680", - Namespace: oc.Namespace(), - DisplayName: "OLM QE", - Publisher: "OLM QE", - SourceType: "grpc", - Address: "quay.io/olmqe/etcd-prometheus-dependency-index:11.0", - Template: csImageTemplate, - } - defer catsrc.Delete(itName, dr) - catsrc.CreateWithCheck(oc, itName, dr) - g.By("Install the OperatorGroup in a random project") og := olmv0util.OperatorGroupDescription{ Name: "og-27680", @@ -406,50 +392,63 @@ var _ = g.Describe("[sig-operator][Jira:OLM] OLMv0 within a namespace", func() { defer og.Delete(itName, dr) og.CreateWithCheck(oc, itName, dr) - g.By("Install the etcdoperator v0.9.4 with Automatic approval") sub := olmv0util.SubscriptionDescription{ SubName: "sub-27680", Namespace: ns, - CatalogSourceName: catsrc.Name, - CatalogSourceNamespace: catsrc.Namespace, - Channel: "singlenamespace-alpha", + CatalogSourceName: "redhat-operators", + CatalogSourceNamespace: "openshift-marketplace", + Channel: "", IpApproval: "Automatic", - OperatorPackage: "etcd-service-monitor", - StartingCSV: csvName, + OperatorPackage: "odf-prometheus-operator", SingleNamespace: true, Template: subTemplate, } + exists, err := olmv0util.ClusterPackageExists(oc, sub) + o.Expect(err).NotTo(o.HaveOccurred(), "failed to query packagemanifest for %s in %s", sub.OperatorPackage, sub.CatalogSourceNamespace) + if !exists { + g.Skip("SKIP:PackageMissing odf-prometheus-operator does not exist in catalog redhat-operators") + } + + defaultChannel, channelErr := oc.AsAdmin().WithoutNamespace().Run("get").Args( + "packagemanifest", sub.OperatorPackage, "-n", sub.CatalogSourceNamespace, "-o=jsonpath={.status.defaultChannel}", + ).Output() + o.Expect(channelErr).NotTo(o.HaveOccurred(), "failed to get default channel for packagemanifest %s", sub.OperatorPackage) + sub.Channel = strings.TrimSpace(defaultChannel) + o.Expect(sub.Channel).NotTo(o.BeEmpty(), "default channel for packagemanifest %s is empty", sub.OperatorPackage) + + workerNodes, workerErr := exutil.GetSchedulableLinuxWorkerNodes(oc) + o.Expect(workerErr).NotTo(o.HaveOccurred(), "failed to list schedulable linux worker nodes") + firstNode := "" + for _, worker := range workerNodes { + for _, con := range worker.Status.Conditions { + if con.Type == "Ready" && con.Status == "True" { + firstNode = worker.Name + break + } + } + if firstNode != "" { + break + } + } + if firstNode == "" { + e2e.Failf("no schedulable worker node in READY state found") + } + + g.By("Install the Prometheus operator with Automatic approval") defer sub.Delete(itName, dr) defer sub.DeleteCSV(itName, dr) sub.Create(oc, itName, dr) - olmv0util.NewCheck("expect", exutil.AsAdmin, exutil.WithoutNamespace, exutil.Compare, "Succeeded", exutil.Ok, []string{"csv", csvName, "-n", ns, "-o=jsonpath={.status.phase}"}).Check(oc) + olmv0util.NewCheck("expect", exutil.AsAdmin, exutil.WithoutNamespace, exutil.Compare, "Succeeded", exutil.Ok, []string{"csv", sub.InstalledCSV, "-n", ns, "-o=jsonpath={.status.phase}"}).Check(oc) - g.By("Assert that prometheus dependency is resolved") - msg, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("csv", "-n", ns).Output() + g.By("Create a Prometheus resource that relies on Prometheus bundle types") + defer func() { + _ = oc.AsAdmin().WithoutNamespace().Run("delete").Args("prometheus", "example", "-n", ns, "--ignore-not-found").Execute() + }() + err = olmv0util.ApplyResourceFromTemplate(oc, "--ignore-unknown-parameters=true", "-f", prometheusTemplate, "-p", fmt.Sprintf("NAMESPACE=%s", ns), fmt.Sprintf("NODE_NAME=%s", firstNode)) o.Expect(err).NotTo(o.HaveOccurred()) - o.Expect(msg).To(o.ContainSubstring("prometheus")) - - g.By("Assert that ServiceMonitor is created") - err = wait.PollUntilContextTimeout(context.TODO(), 10*time.Second, 2*time.Minute, false, func(ctx context.Context) (bool, error) { - output, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("ServiceMonitor", "my-servicemonitor", "-n", ns).Output() - if err != nil { - e2e.Logf("waiting for ServiceMonitor: %v", err) - return false, nil - } - return strings.Contains(output, "my-servicemonitor"), nil - }) - exutil.AssertWaitPollNoErr(err, "ServiceMonitor was not created") - - g.By("Assert that PrometheusRule is created") - err = wait.PollUntilContextTimeout(context.TODO(), 10*time.Second, 2*time.Minute, false, func(ctx context.Context) (bool, error) { - output, err := oc.AsAdmin().WithoutNamespace().Run("get").Args("PrometheusRule", "my-prometheusrule", "-n", ns).Output() - if err != nil { - e2e.Logf("waiting for PrometheusRule: %v", err) - return false, nil - } - return strings.Contains(output, "my-prometheusrule"), nil - }) - exutil.AssertWaitPollNoErr(err, "PrometheusRule was not created") + // The package used for this test guarantees Prometheus types are served, but may not report + // status.conditions[0].type=Available for this standalone CR in all environments. + olmv0util.NewCheck("expect", exutil.AsAdmin, exutil.WithoutNamespace, exutil.Compare, "example2", exutil.Ok, []string{"Prometheus", "example", "-n", ns, "-o=jsonpath={.metadata.name}{.spec.replicas}"}).Check(oc) }) g.It("PolarionID:22200-[OTP][Skipped:Disconnected]add minimum kube version to CSV [Slow]", g.Label("NonHyperShiftHOST"), g.Label("original-name:[sig-operator][Jira:OLM] OLMv0 within a namespace PolarionID:22200-[Skipped:Disconnected]add minimum kube version to CSV [Slow]"), func() { diff --git a/tests-extension/test/qe/testdata/olm/cm-csv-sample-24387-modified.yaml b/tests-extension/test/qe/testdata/olm/cm-csv-sample-24387-modified.yaml new file mode 100644 index 0000000000..aa9b8067de --- /dev/null +++ b/tests-extension/test/qe/testdata/olm/cm-csv-sample-24387-modified.yaml @@ -0,0 +1,286 @@ +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + name: cm-csv-sample-24387-modified-template +objects: +- apiVersion: v1 + kind: ConfigMap + metadata: + name: "${NAME}" + namespace: "${NAMESPACE}" + data: + clusterServiceVersions: | + - apiVersion: operators.coreos.com/v1alpha1 + kind: ClusterServiceVersion + metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "cache.example.com/v1alpha1", + "kind": "Sample", + "metadata": { + "name": "sample-sample" + }, + "spec": null + } + ] + capabilities: Basic Install + createdAt: "2026-03-09T09:27:42Z" + operators.operatorframework.io/builder: operator-sdk-v1.31.0-ocp + operators.operatorframework.io/project_layout: ansible.sdk.operatorframework.io/v1 + name: sample-operator.v0.0.1 + namespace: "${NAMESPACE}" + spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - kind: Sample + name: samples.cache.example.com + version: v1alpha1 + description: An operator for QE testing + displayName: Sample Operator + icon: + - base64data: "" + mediatype: "" + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - "" + resources: + - secrets + - pods + - pods/exec + - pods/log + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - cache.example.com + resources: + - samples + - samples/status + - samples/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + serviceAccountName: sample-operator-controller-manager + deployments: + - label: + control-plane: controller-manager + name: sample-operator-controller-manager + spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + strategy: {} + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + containers: + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=0 + image: quay.io/olmqe/kube-rbac-proxy@sha256:3789634ce5991a19bc56f3143e739d7887f1e817c0a556a4f51e27b18ab3c5d6 + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + - args: + - --health-probe-bind-address=:6789 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + - --leader-election-id=sample-operator + env: + - name: ANSIBLE_GATHERING + value: explicit + image: quay.io/olmqe/sample-operator@sha256:e83e6ae660fe7c94ec61616c622dce6640bf912667ede0c17881e10ad8812be3 + livenessProbe: + httpGet: + path: /healthz + port: 6789 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 6789 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 768Mi + requests: + cpu: 10m + memory: 256Mi + securityContext: + allowPrivilegeEscalation: false + securityContext: + runAsNonRoot: true + serviceAccountName: sample-operator-controller-manager + terminationGracePeriodSeconds: 10 + permissions: + - rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + serviceAccountName: sample-operator-controller-manager + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - sample + - nginx + links: + - name: Sample Operator + url: https://sample-operator.domain + maintainers: + - email: jiazha@redhat.com + name: JianZhang + maturity: alpha + provider: + name: Jian + version: 0.0.1 + customResourceDefinitions: | + - apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + metadata: + name: samples.cache.example.com + spec: + group: cache.example.com + names: + kind: Sample + listKind: SampleList + plural: samples + singular: sample + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Sample is the Schema for the samples API + properties: + apiVersion: + description: APIVersion defines the versioned schema of this representation of an object. + type: string + kind: + description: Kind is a string value representing the REST resource this object represents. + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Sample + type: object + properties: + propertyIncludedTest: + type: string + x-kubernetes-preserve-unknown-fields: true + status: + description: Status defines the observed state of Sample + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + packages: | + - packageName: sample-operator + defaultChannel: alpha + channels: + - name: alpha + currentCSV: sample-operator.v0.0.1 +parameters: +- name: NAME +- name: NAMESPACE diff --git a/tests-extension/test/qe/testdata/olm/cm-csv-sample-24387.yaml b/tests-extension/test/qe/testdata/olm/cm-csv-sample-24387.yaml new file mode 100644 index 0000000000..b4cb7cdfb7 --- /dev/null +++ b/tests-extension/test/qe/testdata/olm/cm-csv-sample-24387.yaml @@ -0,0 +1,283 @@ +apiVersion: template.openshift.io/v1 +kind: Template +metadata: + name: cm-csv-sample-24387-template +objects: +- apiVersion: v1 + kind: ConfigMap + metadata: + name: "${NAME}" + namespace: "${NAMESPACE}" + data: + clusterServiceVersions: | + - apiVersion: operators.coreos.com/v1alpha1 + kind: ClusterServiceVersion + metadata: + annotations: + alm-examples: |- + [ + { + "apiVersion": "cache.example.com/v1alpha1", + "kind": "Sample", + "metadata": { + "name": "sample-sample" + }, + "spec": null + } + ] + capabilities: Basic Install + createdAt: "2026-03-09T09:27:42Z" + operators.operatorframework.io/builder: operator-sdk-v1.31.0-ocp + operators.operatorframework.io/project_layout: ansible.sdk.operatorframework.io/v1 + name: sample-operator.v0.0.1 + namespace: "${NAMESPACE}" + spec: + apiservicedefinitions: {} + customresourcedefinitions: + owned: + - kind: Sample + name: samples.cache.example.com + version: v1alpha1 + description: An operator for QE testing + displayName: Sample Operator + icon: + - base64data: "" + mediatype: "" + install: + spec: + clusterPermissions: + - rules: + - apiGroups: + - "" + resources: + - secrets + - pods + - pods/exec + - pods/log + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - apps + resources: + - deployments + - daemonsets + - replicasets + - statefulsets + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - cache.example.com + resources: + - samples + - samples/status + - samples/finalizers + verbs: + - create + - delete + - get + - list + - patch + - update + - watch + - apiGroups: + - authentication.k8s.io + resources: + - tokenreviews + verbs: + - create + - apiGroups: + - authorization.k8s.io + resources: + - subjectaccessreviews + verbs: + - create + serviceAccountName: sample-operator-controller-manager + deployments: + - label: + control-plane: controller-manager + name: sample-operator-controller-manager + spec: + replicas: 1 + selector: + matchLabels: + control-plane: controller-manager + strategy: {} + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + labels: + control-plane: controller-manager + spec: + containers: + - args: + - --secure-listen-address=0.0.0.0:8443 + - --upstream=http://127.0.0.1:8080/ + - --logtostderr=true + - --v=0 + image: quay.io/olmqe/kube-rbac-proxy@sha256:3789634ce5991a19bc56f3143e739d7887f1e817c0a556a4f51e27b18ab3c5d6 + name: kube-rbac-proxy + ports: + - containerPort: 8443 + name: https + protocol: TCP + resources: + limits: + cpu: 500m + memory: 128Mi + requests: + cpu: 5m + memory: 64Mi + - args: + - --health-probe-bind-address=:6789 + - --metrics-bind-address=127.0.0.1:8080 + - --leader-elect + - --leader-election-id=sample-operator + env: + - name: ANSIBLE_GATHERING + value: explicit + image: quay.io/olmqe/sample-operator@sha256:e83e6ae660fe7c94ec61616c622dce6640bf912667ede0c17881e10ad8812be3 + livenessProbe: + httpGet: + path: /healthz + port: 6789 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + readinessProbe: + httpGet: + path: /readyz + port: 6789 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 500m + memory: 768Mi + requests: + cpu: 10m + memory: 256Mi + securityContext: + allowPrivilegeEscalation: false + securityContext: + runAsNonRoot: true + serviceAccountName: sample-operator-controller-manager + terminationGracePeriodSeconds: 10 + permissions: + - rules: + - apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + - apiGroups: + - "" + resources: + - events + verbs: + - create + - patch + serviceAccountName: sample-operator-controller-manager + strategy: deployment + installModes: + - supported: true + type: OwnNamespace + - supported: true + type: SingleNamespace + - supported: true + type: MultiNamespace + - supported: true + type: AllNamespaces + keywords: + - sample + - nginx + links: + - name: Sample Operator + url: https://sample-operator.domain + maintainers: + - email: jiazha@redhat.com + name: JianZhang + maturity: alpha + provider: + name: Jian + version: 0.0.1 + customResourceDefinitions: | + - apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + metadata: + name: samples.cache.example.com + spec: + group: cache.example.com + names: + kind: Sample + listKind: SampleList + plural: samples + singular: sample + scope: Namespaced + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: Sample is the Schema for the samples API + properties: + apiVersion: + description: APIVersion defines the versioned schema of this representation of an object. + type: string + kind: + description: Kind is a string value representing the REST resource this object represents. + type: string + metadata: + type: object + spec: + description: Spec defines the desired state of Sample + type: object + x-kubernetes-preserve-unknown-fields: true + status: + description: Status defines the observed state of Sample + type: object + x-kubernetes-preserve-unknown-fields: true + type: object + served: true + storage: true + subresources: + status: {} + packages: | + - packageName: sample-operator + defaultChannel: alpha + channels: + - name: alpha + currentCSV: sample-operator.v0.0.1 +parameters: +- name: NAME +- name: NAMESPACE