main.yml 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204
  1. ---
  2. # Ensures all the operator artifacts are created and waits for CSV to succeed.
  3. #
  4. # The following variables must exist:
  5. #
  6. # added_operators: (list)
  7. # - catalog: the catalog of the manifest
  8. # catalog_namespace: (optional) catalog namespace (defaults to openshift-marketplace)
  9. # package: the name of the packagemanifest
  10. # subscription: the name of the operatorgroup and subscription (optional, defaults to package)
  11. # channel: which channel to install from
  12. # namespace: target namespace for subscription
  13. # desired_csv: for verification - wait for this CSV to appear
  14. # og_namespaces: (list) operatorgroup namespaces
  15. # approval: Automatic (default) or Manual
  16. #
  17. # This role must then be applied as:
  18. #
  19. # - include_role:
  20. # name: deploy-operators
  21. # loop: "{{ added_operators }}"
  22. # loop_control:
  23. # loop_var: role
  24. #
  25. # What this means is that each item of added_operators is expected to be
  26. # placed in the "role" variable prior to iterating over this role.
  27. #
  28. # OPTIONAL:
  29. #
  30. # kubeadmin_config kubeadmin (or other admin) credentials (tmp/kubeconfig-ocp4)
  31. #
  32. # NOTE: Do NOT test by checking for presence of API resources - they do not
  33. # always get cleaned up, so it might report a false positive.
  34. #
  35. - name: Tell what is happening
  36. ansible.builtin.pause:
  37. prompt: |
  38. *******************************************************************************
  39. * Deploying operator {{ role.package }} to namespace {{ role.namespace }}
  40. *******************************************************************************
  41. seconds: 0
  42. - name: Make sure the namespace is there
  43. kubernetes.core.k8s:
  44. kubeconfig: "{{ kubeadmin_config }}"
  45. validate_certs: no
  46. api_version: v1
  47. kind: namespace
  48. name: "{{ role.namespace }}"
  49. - name: Verify if the namespace has an OperatorGroup already
  50. kubernetes.core.k8s_info:
  51. kubeconfig: "{{ kubeadmin_config }}"
  52. validate_certs: no
  53. api_version: operators.coreos.com/v1
  54. kind: operatorgroup
  55. namespace: "{{ role.namespace }}"
  56. register: found_opgrp
  57. - name: Show the operator groups found at verbosity 2+
  58. debug:
  59. var: found_opgrp
  60. verbosity: 2
  61. - name: The OperatorGroup must have a matching targetNamespaces if it exists already, or we can not continue.
  62. ansible.builtin.assert:
  63. that:
  64. - >
  65. (role.og_namespaces is defined and
  66. found_opgrp.resources[0].spec.targetNamespaces is defined and
  67. found_opgrp.resources[0].spec.targetNamespaces == role.og_namespaces) or
  68. ((role.og_namespaces is not defined or role.og_namespaces == []) and
  69. found_opgrp.resources[0].spec.targetNamespaces is not defined)
  70. success_msg: "Found existing OperatorGroup with matching targetNamespaces."
  71. fail_msg: "FATAL: OperatorGroup already exists but does not have matching targetNamespaces."
  72. when:
  73. - found_opgrp.resources is defined
  74. - found_opgrp.resources[0] is defined
  75. - found_opgrp.resources[0].spec is defined
  76. - name: If not there yet, create an OperatorGroup
  77. kubernetes.core.k8s:
  78. kubeconfig: "{{ kubeadmin_config }}"
  79. validate_certs: no
  80. api_version: operators.coreos.com/v1
  81. kind: operatorgroup
  82. namespace: "{{ role.namespace }}"
  83. name: "{{ role.subscription | default(role.package) }}"
  84. definition:
  85. spec:
  86. targetNamespaces: "{{ role.og_namespaces | default(omit) }}"
  87. when:
  88. - >
  89. found_opgrp.resources is not defined or
  90. found_opgrp.resources[0] is not defined
  91. - name: Check if installPlans exist already before fondling around with subscriptions
  92. kubernetes.core.k8s_info:
  93. kubeconfig: "{{ kubeadmin_config }}"
  94. validate_certs: no
  95. api_version: operators.coreos.com/v1alpha1
  96. kind: installplan
  97. namespace: "{{ role.namespace }}"
  98. register: installplan_pre
  99. - name: Remember the installPlan(s) found prior to fondling around with subscriptions as a fact
  100. ansible.builtin.set_fact:
  101. sub_ip_pre: "{{ installplan_pre.resources | selectattr('metadata.ownerReferences.0.name', 'in', (role.subscription | default(role.package))) | sort(attribute='metadata.creationTimestamp', reverse=True) }}"
  102. - name: Show the installplan(s) found at verbosity 2+
  103. debug:
  104. var: sub_ip_pre
  105. verbosity: 2
  106. # TODO: sometimes a subscription is there and this just overwrites it and reports a change (installPlanApproval!)
  107. - name: Also make sure there is a subscription
  108. kubernetes.core.k8s:
  109. kubeconfig: "{{ kubeadmin_config }}"
  110. validate_certs: no
  111. api_version: operators.coreos.com/v1alpha1
  112. kind: subscription
  113. namespace: "{{ role.namespace }}"
  114. name: "{{ role.subscription | default(role.package) }}"
  115. definition:
  116. spec:
  117. source: "{{ role.catalog }}"
  118. sourceNamespace: "{{ role.catalog_namespace | default('openshift-marketplace') }}"
  119. name: "{{ role.package }}"
  120. channel: "{{ role.channel }}"
  121. startingCSV: "{{ role.desired_csv }}"
  122. installPlanApproval: "{{ role.approval | default('Automatic') }}"
  123. register: subscription
  124. - name: Handle installPlan if the subscription changed anything
  125. block:
  126. # TODO: sometimes an installPlan will list multiple subscriptions as owners?!?
  127. - name: Wait for installPlan to show up
  128. kubernetes.core.k8s_info:
  129. kubeconfig: "{{ kubeadmin_config }}"
  130. validate_certs: no
  131. api_version: operators.coreos.com/v1alpha1
  132. kind: installplan
  133. namespace: "{{ role.namespace }}"
  134. register: installplan
  135. until:
  136. - installplan.resources is defined
  137. - (installplan.resources | length) > 0
  138. - >
  139. (installplan.resources |
  140. selectattr('metadata.ownerReferences.0.name', 'in', (role.subscription | default(role.package))) |
  141. length) > (sub_ip_pre | length)
  142. retries: 12
  143. delay: 10
  144. - name: Remember the installPlan(s) found after the subscription has been modified
  145. ansible.builtin.set_fact:
  146. sub_ip_post: "{{ installplan.resources | selectattr('metadata.ownerReferences.0.name', 'in', (role.subscription | default(role.package))) | sort(attribute='metadata.creationTimestamp', reverse=True) }}"
  147. - name: Show the installplan(s) found at verbosity 2+
  148. debug:
  149. var: sub_ip_post
  150. verbosity: 2
  151. - name: Remember the latest installPlan name as a new fact
  152. ansible.builtin.set_fact:
  153. latest_install_plan: "{{ sub_ip_post[0].metadata.name }}"
  154. - name: Announce the installPlan name
  155. ansible.builtin.debug:
  156. msg: Found installPlan {{ latest_install_plan }}.
  157. - name: Approve the installPlan if the approval was Manual
  158. kubernetes.core.k8s_json_patch:
  159. kubeconfig: "{{ kubeadmin_config }}"
  160. validate_certs: no
  161. api_version: operators.coreos.com/v1alpha1
  162. kind: installplan
  163. namespace: "{{ role.namespace }}"
  164. name: "{{ latest_install_plan }}"
  165. patch:
  166. - op: replace
  167. path: /spec/approved
  168. value: true
  169. when: role.approval == "Manual"
  170. when: subscription.changed
  171. - name: Wait for CSV to show up and complete
  172. kubernetes.core.k8s_info:
  173. kubeconfig: "{{ kubeadmin_config }}"
  174. validate_certs: no
  175. api_version: operators.coreos.com/v1alpha1
  176. kind: clusterserviceversion
  177. namespace: "{{ role.namespace }}"
  178. name: "{{ role.desired_csv }}"
  179. register: new_csv
  180. until:
  181. - new_csv.resources is defined
  182. - (new_csv.resources | length) > 0
  183. - new_csv.resources[0].status is defined
  184. - new_csv.resources[0].status.phase == "Succeeded"
  185. retries: 30
  186. delay: 10
  187. ...