main.yml 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. # TODO: remove egress IPs without their corresponding projects
  46. #
  47. - name: Show the values at verbosity 1+
  48. ansible.builtin.debug:
  49. var: role
  50. verbosity: 1
  51. # TODO: conditional block for state: present
  52. - name: Check the values and apply sanity if state=present.
  53. block:
  54. - name: Verify that the requesting user exists.
  55. kubernetes.core.k8s_info:
  56. kubeconfig: tmp/kubeconfig-ocp4
  57. validate_certs: no
  58. api_version: user.openshift.io/v1
  59. kind: user
  60. name: "{{ role.requester }}"
  61. register: requester
  62. - name: Fail if the user is missing.
  63. ansible.builtin.assert:
  64. that:
  65. - requester.resources is defined
  66. - requester.resources | length == 1
  67. success_msg: "OK, requester exists as an OpenShift user."
  68. fail_msg: "FATAL: requester ({{ role.requester }}) does not exist as an OpenShift user."
  69. - name: Ensure that the project is not there yet.
  70. kubernetes.core.k8s_info:
  71. kubeconfig: tmp/kubeconfig-ocp4
  72. validate_certs: no
  73. api_version: v1
  74. kind: namespace
  75. name: "{{ role.name }}"
  76. register: namespace
  77. - name: Fail if the namespace exists.
  78. ansible.builtin.assert:
  79. that:
  80. - namespace.resources is defined
  81. - namespace.resources | length == 0
  82. success_msg: "OK, project does not exist yet."
  83. fail_msg: "FATAL: project \"{{ role.name }}\" already exists; remove it using delete-project.yml and retry."
  84. - name: Ensure that the clusterrole exists.
  85. kubernetes.core.k8s_info:
  86. kubeconfig: tmp/kubeconfig-ocp4
  87. validate_certs: no
  88. api_version: rbac.authorization.k8s.io/v1
  89. kind: clusterrole
  90. name: "{{ role.rbac_level }}"
  91. register: clusterrole
  92. - name: Fail if the requested cluster role is missing.
  93. ansible.builtin.assert:
  94. that:
  95. - clusterrole.resources is defined
  96. - clusterrole.resources | length == 1
  97. success_msg: "OK, clusterrole exists."
  98. fail_msg: "FATAL: clusterrole ({{ role.rbac_level }}) does not exist."
  99. - name: Get a full list of IPs from openshift.egress_range.
  100. ansible.builtin.set_fact:
  101. egressips_full: "{{ (openshift.egress_range | ansible.utils.usable_range)['usable_ips'] }}"
  102. - name: Get a list of allocated egress IPs in the cluster
  103. kubernetes.core.k8s_info:
  104. kubeconfig: tmp/kubeconfig-ocp4
  105. validate_certs: no
  106. api_version: k8s.ovn.org/v1
  107. kind: egressip
  108. register: egressips
  109. - name: Get the remaining available egress IPs from openshift.egress_range.
  110. ansible.builtin.set_fact:
  111. egressips_avail: "{{ egressips_full | difference(egressips | community.general.json_query('resources[*].status.items[*].egressIP') | flatten) }}"
  112. - name: Ensure that there are still available IPs.
  113. ansible.builtin.assert:
  114. that:
  115. - egressips_avail | length > 0
  116. success_msg: "OK, {{ egressips_avail | length }} egress IP(s) still available"
  117. fail_msg: "FATAL: No egress IPs remain available. Please remove some projects and release their IPs, then retry."
  118. - name: Find an available egress IP from openshift.egress_range, or...
  119. ansible.builtin.set_fact:
  120. allocated_egressip: "{{ egressips_avail[0] }}"
  121. when: role.egress_ip is not defined
  122. - name: ...if egress IP was specified, ensure it is available and in openshift.egress_range.
  123. block:
  124. - name: Verify the requested IP is still available.
  125. ansible.builtin.assert:
  126. that:
  127. - role.egress_ip in egressips_avail
  128. success_msg: "OK, requested egress IP is still available."
  129. fail_msg: "FATAL: requested egress IP ({{ role.egress_ip }}) is not available or not from egress range ({{ openshift.egress_range }})."
  130. - name: If we survived up until here, that is an acceptable egress IP.
  131. ansible.builtin.set_fact:
  132. allocated_egressip: "{{ role.egress_ip }}"
  133. when: role.egress_ip is defined
  134. when: (role.state | default('present')) == 'present'
  135. - name: Verify that the project exists and is a valid ICHP namespace.
  136. block:
  137. - name: Ensure that the project is there.
  138. kubernetes.core.k8s_info:
  139. kubeconfig: tmp/kubeconfig-ocp4
  140. validate_certs: no
  141. api_version: v1
  142. kind: namespace
  143. name: "{{ role.name }}"
  144. register: namespace
  145. - name: Fail if the namespace exists.
  146. ansible.builtin.assert:
  147. that:
  148. - namespace.resources is defined
  149. - namespace.resources | length == 1
  150. success_msg: "OK, project exists."
  151. fail_msg: "FATAL: project \"{{ role.name }}\" does not exist."
  152. - name: Fail if the namespace is not properly labeled.
  153. ansible.builtin.assert:
  154. that:
  155. - namespace.resources is defined
  156. - namespace.resources | length == 1
  157. - namespace.resources.metadata.labels["ichp.ing.net/generated"] is defined
  158. success_msg: "OK, project looks like ICHP."
  159. fail_msg: "FATAL: project \"{{ role.name }}\" does not look like an ICHP project."
  160. when: (role.state | default('present')) == 'absent'
  161. - name: Apply the project template to the cluster with correct state set.
  162. kubernetes.core.k8s:
  163. kubeconfig: tmp/kubeconfig-ocp4
  164. validate_certs: no
  165. template: templates/project-template.yml
  166. state: "{{ role.state | default('present') }}"
  167. ...