--- # Ensures all the operator artifacts are created and waits for CSV to succeed. # # The following variables must exist: # # op: # desired_csv # op_nsp # op_cat # op_pkg # op_chn # op_mod # # NOTE: Do NOT test by checking for presence of API resources - they do not always get cleaned up. - debug: msg: Deploying operator {{ op.op_pkg }} in namespace {{ op.op_nsp }}... # See if the CSV is available already (anywhere), meaning the operator is already installed. - name: Check if the CSV exists already k8s_info: kubeconfig: tmp/kubeconfig-ocp4 validate_certs: no api_version: operators.coreos.com/v1alpha1 kind: clusterserviceversion register: all_csv - name: Find the wanted CSV among all CSVs set_fact: found_csv: '{{ (all_csv | community.general.json_query("resources[?contains(metadata.name, `" + op.op_pkg + ".`)]")) }}' when: - all_csv.resources is defined - (all_csv.resources | length) > 0 - name: Reset CSV data set_fact: csv_ns: '' csv_name: '' - name: Get details about the CSV if found set_fact: csv_ns: "{{ found_csv[0] | community.general.json_query('metadata.namespace') }}" csv_name: "{{ found_csv[0] | community.general.json_query('metadata.name') }}" when: - found_csv is defined - (found_csv | length) > 0 - debug: msg: Operator {{ op.op_pkg }} is already installed in {{ csv_ns }} as {{ csv_name }} (desired_csv == {{ op.desired_csv }}). when: - csv_ns != '' - csv_name != '' - name: Only proceed here if the CSV was not found anywhere yet block: # Check if package provides desired_csv in any of the channels # XXX Due to the idiotic fact that some operators from different catalogs # have the same manifest name, this needs to be a two-phase query. # XXX First, query for all operators from the desired catalog. - name: Get packagemanifests from same catalog k8s_info: kubeconfig: tmp/kubeconfig-ocp4 validate_certs: no api_version: packages.operators.coreos.com/v1 kind: packagemanifest namespace: openshift-marketplace label_selectors: - "catalog = {{ op.op_cat }}" register: pkg_mft_samecat # XXX Then, search for the operator that has the status.packageName we need. - name: Reset pkg_mft before looking for it set_fact: pkg_mft: '' found_chn: '' - name: Weed out the manifest we need set_fact: pkg_mft: '{{ pkg_mft_samecat | community.general.json_query("resources[?status.packageName == `" + op.op_pkg + "`]") }}' - debug: var=pkg_mft - name: Search for any channels that provide desired_csv set_fact: found_chn: '{{ (pkg_mft | community.general.json_query("status.channels[?currentCSV == `" + op.desired_csv + "`].name")) }}' when: - pkg_mft is defined - pkg_mft != '' - debug: var=found_chn - name: Fail if no channel provides the desired_csv fail: msg: No {{ op.op_pkg }} channel provides {{ op.desired_csv }} when: - found_chn is defined - found_chn == '' - name: Fail if selected channel does not provide the desired_csv fail: msg: Operator {{ op.op_pkg }} selected channel {{ op.op_chn }} does not provide {{ op.desired_csv }} - {{ found_chn }} when: - found_chn is defined - found_chn | length > 0 - op.op_chn not in found_chn # Create the namespace if necessary - name: Make sure the namespace is there k8s: kubeconfig: tmp/kubeconfig-ocp4 validate_certs: no api_version: v1 kind: namespace name: "{{ op.op_nsp }}" # Check for operator group - if existing, make sure it's compatible; otherwise create it - name: See if there are any OperatorGroups k8s_info: kubeconfig: tmp/kubeconfig-ocp4 validate_certs: no api_version: operators.coreos.com/v1 kind: operatorgroup namespace: "{{ op.op_nsp }}" register: found_opgrp - name: Die if more than one OG ansible.builtin.fail: msg: More than one OperatorGroup found in project. when: (found_opgrp.resources | length) > 1 - name: Die if op_mod is not recognised ansible.builtin.fail: msg: Unrecognised op.op_mod ({{ op.op_mod }}) when: op.op_mod not in ["all", "self"] - name: Die if op_mod does not match found OG mode ansible.builtin.fail: msg: Found OG mode does not match required ({{ op.op_mod }}) when: | ((found_opgrp.resources | length) == 1 and op.op_mod == "all" and found_opgrp.resources[0].status.namespaces != [""]) or ((found_opgrp.resources | length) == 1 and op.op_mod == "self" and found_opgrp.resources[0].status.namespaces != [op.op_nsp]) - name: Set fact for namespaces of OG if we require all set_fact: og_spec: [] when: - op.op_mod == "all" - (found_opgrp.resources | length) == 0 - name: Set fact for namespaces of OG if we require self set_fact: og_spec: ["{{op.op_nsp}}"] when: - op.op_mod == "self" - (found_opgrp.resources | length) == 0 - name: Create the OperatorGroup if not there k8s: kubeconfig: tmp/kubeconfig-ocp4 validate_certs: no api_version: operators.coreos.com/v1 kind: operatorgroup namespace: "{{ op.op_nsp }}" name: "{{ op.op_nsp }}" definition: spec: targetNamespaces: "{{ og_spec }}" when: (found_opgrp.resources | length) == 0 # create a subscription if not there, and wait for the CSV - name: Also make sure there is a subscription k8s: kubeconfig: tmp/kubeconfig-ocp4 validate_certs: no api_version: operators.coreos.com/v1alpha1 kind: subscription namespace: "{{ op.op_nsp }}" name: "{{ op.op_pkg }}" definition: spec: source: "{{ op.op_cat }}" sourceNamespace: openshift-marketplace name: "{{ op.op_pkg }}" channel: "{{ op.op_chn }}" installPlanApproval: Automatic # TODO: Finish this at some point. #- name: Wait for installPlan to show up # k8s_info: # kubeconfig: tmp/kubeconfig-ocp4 # validate_certs: no # api_version: operators.coreos.com/v1alpha1 # kind: installplan # namespace: "{{ op_nsp }}" # register: installplan # until: # - installplan.resources is defined # - (installplan.resources | length) > 0 # - installplan.resources[0].spec.approved # retries: 12 # delay: 10 - name: Wait for CSV to show up and complete k8s_info: kubeconfig: tmp/kubeconfig-ocp4 validate_certs: no api_version: operators.coreos.com/v1alpha1 kind: clusterserviceversion namespace: "{{ op.op_nsp }}" name: "{{ op.desired_csv }}" register: new_csv until: - new_csv.resources is defined - (new_csv.resources | length) > 0 - new_csv.resources[0].status is defined - new_csv.resources[0].status.phase == "Succeeded" retries: 30 delay: 10 # TODO: Finish this at some point. #- name: Finally, wait for the pod # k8s_info: # kubeconfig: tmp/kubeconfig-ocp4 # validate_certs: no # api_version: v1 # kind: pod # namespace: rhsso # label_selectors: # - name = rhsso-operator # register: sso_pod # until: # - sso_pod.resources is defined # - (sso_pod.resources | length) > 0 # - sso_pod.resources[0].status is defined # - sso_pod.resources[0].status.phase == "Running" # retries: 30 # delay: 10 - debug: msg: Operator {{ op.op_pkg }} deployed in namespace {{ op.op_nsp }} with CSV {{ op.desired_csv }}! when: found_csv is not defined or (found_csv | length) == 0 ...