main.yml 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. ---
  2. # Ensures a project exists and is configured in accordance with ICHP rules:
  3. #
  4. # - has correct RBAC (user role binding)
  5. # - has network policies
  6. # - has quota and limitranges
  7. # - has an EgressIP allocated
  8. #
  9. # Requires the following structure:
  10. #
  11. # role:
  12. # state: present or absent
  13. # requester: the user requesting the project
  14. # name: the name of the project
  15. # displayname: optional displayname (defaults to name)
  16. # rbac_level: cluster role to assign to requester
  17. # egress_ip: an available egress IP to allocate to the project
  18. # quota: compute resourcequotas
  19. # requests: compute reservation
  20. # cpu: max cpu reserved (1500m, 1.5 CPU)
  21. # memory: max memory reserved (2048Mi, 2Gi)
  22. # limits: compute limits
  23. # cpu: max cpu consumed (4000m, 4 CPUs)
  24. # memory: max memory consumed (4096Mi, 4Gi)
  25. # lrange: compute limitranges, for both container and pod
  26. # default: default limits and requests
  27. # limit:
  28. # cpu: role.lrange.min.cpu * role.lrange.ratio.cpu
  29. # memory: role.lrange.min.memory * role.lrange.ratio.memory
  30. # request:
  31. # cpu: defaults to whatever role.lrange.min.cpu is
  32. # memory: defaults to whatever role.lrange.min.memory is
  33. # max: maximum limits
  34. # cpu: maximum cpu limit (4000m, 4 cpus)
  35. # memory: maximum memory limit (4096Mi, 4Gi)
  36. # min: minimum requests
  37. # cpu: minimum requested cpu (50m, 5%)
  38. # memory: minimum requested memory (64Mi)
  39. # ratio: max limit-to-request ratio (x-to-1)
  40. # cpu: cpu lrr (4)
  41. # memory: memory lrr (4)
  42. #
  43. # IMPORTANT: XXX: ALL COMPUTE UNITS MUST BE IN milicores AND Mi!
  44. #
  45. - name: Show the values at verbosity 1+
  46. ansible.builtin.debug:
  47. var: role
  48. verbosity: 1
  49. # TODO: conditional block for state: present
  50. - name: Check the values and apply sanity if state=present.
  51. block:
  52. - name: Verify that the requesting user exists.
  53. kubernetes.core.k8s_info:
  54. kubeconfig: tmp/kubeconfig-ocp4
  55. validate_certs: no
  56. api_version: user.openshift.io/v1
  57. kind: user
  58. name: "{{ role.requester }}"
  59. register: requester
  60. - name: Fail if the user is missing.
  61. ansible.builtin.assert:
  62. that:
  63. - requester.resources is defined
  64. - requester.resources | length == 1
  65. success_msg: "OK, requester exists as an OpenShift user."
  66. fail_msg: "FATAL: requester ({{ role.requester }}) does not exist as an OpenShift user."
  67. - name: Ensure that the project is not there yet.
  68. kubernetes.core.k8s_info:
  69. kubeconfig: tmp/kubeconfig-ocp4
  70. validate_certs: no
  71. api_version: v1
  72. kind: namespace
  73. name: "{{ role.name }}"
  74. register: namespace
  75. - name: Fail if the namespace exists.
  76. ansible.builtin.assert:
  77. that:
  78. - namespace.resources is defined
  79. - namespace.resources | length == 0
  80. success_msg: "OK, project does not exist yet."
  81. fail_msg: "FATAL: project \"{{ role.name }}\" already exists; remove it using delete-project.yml and retry."
  82. - name: Ensure that the clusterrole exists.
  83. kubernetes.core.k8s_info:
  84. kubeconfig: tmp/kubeconfig-ocp4
  85. validate_certs: no
  86. api_version: rbac.authorization.k8s.io/v1
  87. kind: clusterrole
  88. name: "{{ role.rbac_level }}"
  89. register: clusterrole
  90. - name: Fail if the requested cluster role is missing.
  91. ansible.builtin.assert:
  92. that:
  93. - clusterrole.resources is defined
  94. - clusterrole.resources | length == 1
  95. success_msg: "OK, clusterrole exists."
  96. fail_msg: "FATAL: clusterrole ({{ role.rbac_level }}) does not exist."
  97. - name: Get a full list of IPs from openshift.egress_range.
  98. ansible.builtin.set_fact:
  99. egressips_full: "{{ (openshift.egress_range | ansible.utils.usable_range)['usable_ips'] }}"
  100. - name: Get a list of allocated egress IPs in the cluster
  101. kubernetes.core.k8s_info:
  102. kubeconfig: tmp/kubeconfig-ocp4
  103. validate_certs: no
  104. api_version: k8s.ovn.org/v1
  105. kind: egressip
  106. register: egressips
  107. - name: Get the remaining available egress IPs from openshift.egress_range.
  108. ansible.builtin.set_fact:
  109. egressips_avail: "{{ egressips_full | difference(egressips | community.general.json_query('resources[*].status.items[*].egressIP') | flatten) }}"
  110. - name: Ensure that there are still available IPs.
  111. ansible.builtin.assert:
  112. that:
  113. - egressips_avail | length > 0
  114. success_msg: "OK, {{ egressips_avail | length }} egress IP(s) still available"
  115. fail_msg: "FATAL: No egress IPs remain available. Please remove some projects and release their IPs, then retry."
  116. - name: Find an available egress IP from openshift.egress_range, or...
  117. ansible.builtin.set_fact:
  118. allocated_egressip: "{{ egressips_avail[0] }}"
  119. when: role.egress_ip is not defined
  120. - name: ...if egress IP was specified, ensure it is available and in openshift.egress_range.
  121. block:
  122. - name: Verify the requested IP is still available.
  123. ansible.builtin.assert:
  124. that:
  125. - role.egress_ip in egressips_avail
  126. success_msg: "OK, requested egress IP is still available."
  127. fail_msg: "FATAL: requested egress IP ({{ role.egress_ip }}) is not available or not from egress range ({{ openshift.egress_range }})."
  128. - name: If we survived up until here, that is an acceptable egress IP.
  129. ansible.builtin.set_fact:
  130. allocated_egressip: "{{ role.egress_ip }}"
  131. when: role.egress_ip is defined
  132. when: (role.state | default('present')) == 'present'
  133. - name: Verify that the project exists and is a valid ICHP namespace.
  134. block:
  135. - name: Ensure that the project is there.
  136. kubernetes.core.k8s_info:
  137. kubeconfig: tmp/kubeconfig-ocp4
  138. validate_certs: no
  139. api_version: v1
  140. kind: namespace
  141. name: "{{ role.name }}"
  142. register: namespace
  143. - name: Fail if the namespace exists.
  144. ansible.builtin.assert:
  145. that:
  146. - namespace.resources is defined
  147. - namespace.resources | length == 1
  148. success_msg: "OK, project exists."
  149. fail_msg: "FATAL: project \"{{ role.name }}\" does not exist."
  150. - name: Fail if the namespace is not properly labeled.
  151. ansible.builtin.assert:
  152. that:
  153. - namespace.resources is defined
  154. - namespace.resources | length == 1
  155. - namespace.resources[0].metadata.labels["ichp.ing.net/generated"] is defined
  156. success_msg: "OK, project looks like ICHP."
  157. fail_msg: "FATAL: project \"{{ role.name }}\" does not look like an ICHP project."
  158. when: (role.state | default('present')) == 'absent'
  159. - name: Apply the project template to the cluster with correct state set.
  160. kubernetes.core.k8s:
  161. kubeconfig: tmp/kubeconfig-ocp4
  162. validate_certs: no
  163. template: templates/project-template.yml
  164. state: "{{ role.state | default('present') }}"
  165. ...