123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- ---
- # Ensures a project exists and is configured in accordance with ICHP rules:
- #
- # - has correct RBAC (user role binding)
- # - has network policies
- # - has quota and limitranges
- # - has an EgressIP allocated
- #
- # Requires the following structure:
- #
- # role:
- # state: present or absent
- # requester: the user requesting the project
- # name: the name of the project
- # displayname: optional displayname (defaults to name)
- # rbac_level: cluster role to assign to requester
- # egress_ip: an available egress IP to allocate to the project
- # quota: compute resourcequotas
- # requests: compute reservation
- # cpu: max cpu reserved (1500m, 1.5 CPU)
- # memory: max memory reserved (2048Mi, 2Gi)
- # limits: compute limits
- # cpu: max cpu consumed (4000m, 4 CPUs)
- # memory: max memory consumed (4096Mi, 4Gi)
- # lrange: compute limitranges, for both container and pod
- # default: default limits and requests
- # limit:
- # cpu: role.lrange.min.cpu * role.lrange.ratio.cpu
- # memory: role.lrange.min.memory * role.lrange.ratio.memory
- # request:
- # cpu: defaults to whatever role.lrange.min.cpu is
- # memory: defaults to whatever role.lrange.min.memory is
- # max: maximum limits
- # cpu: maximum cpu limit (4000m, 4 cpus)
- # memory: maximum memory limit (4096Mi, 4Gi)
- # min: minimum requests
- # cpu: minimum requested cpu (50m, 5%)
- # memory: minimum requested memory (64Mi)
- # ratio: max limit-to-request ratio (x-to-1)
- # cpu: cpu lrr (4)
- # memory: memory lrr (4)
- #
- # IMPORTANT: XXX: ALL COMPUTE UNITS MUST BE IN milicores AND Mi!
- #
- - name: Show the values at verbosity 1+
- ansible.builtin.debug:
- var: role
- verbosity: 1
- # TODO: conditional block for state: present
- - name: Check the values and apply sanity if state=present.
- block:
- - name: Verify that the requesting user exists.
- kubernetes.core.k8s_info:
- kubeconfig: tmp/kubeconfig-ocp4
- validate_certs: no
- api_version: user.openshift.io/v1
- kind: user
- name: "{{ role.requester }}"
- register: requester
- - name: Fail if the user is missing.
- ansible.builtin.assert:
- that:
- - requester.resources is defined
- - requester.resources | length == 1
- success_msg: "OK, requester exists as an OpenShift user."
- fail_msg: "FATAL: requester ({{ role.requester }}) does not exist as an OpenShift user."
- - name: Ensure that the project is not there yet.
- kubernetes.core.k8s_info:
- kubeconfig: tmp/kubeconfig-ocp4
- validate_certs: no
- api_version: v1
- kind: namespace
- name: "{{ role.name }}"
- register: namespace
- - name: Fail if the namespace exists.
- ansible.builtin.assert:
- that:
- - namespace.resources is defined
- - namespace.resources | length == 0
- success_msg: "OK, project does not exist yet."
- fail_msg: "FATAL: project \"{{ role.name }}\" already exists; remove it using delete-project.yml and retry."
- - name: Ensure that the clusterrole exists.
- kubernetes.core.k8s_info:
- kubeconfig: tmp/kubeconfig-ocp4
- validate_certs: no
- api_version: rbac.authorization.k8s.io/v1
- kind: clusterrole
- name: "{{ role.rbac_level }}"
- register: clusterrole
- - name: Fail if the requested cluster role is missing.
- ansible.builtin.assert:
- that:
- - clusterrole.resources is defined
- - clusterrole.resources | length == 1
- success_msg: "OK, clusterrole exists."
- fail_msg: "FATAL: clusterrole ({{ role.rbac_level }}) does not exist."
- - name: Get a full list of IPs from openshift.egress_range.
- ansible.builtin.set_fact:
- egressips_full: "{{ (openshift.egress_range | ansible.utils.usable_range)['usable_ips'] }}"
- - name: Get a list of allocated egress IPs in the cluster
- kubernetes.core.k8s_info:
- kubeconfig: tmp/kubeconfig-ocp4
- validate_certs: no
- api_version: k8s.ovn.org/v1
- kind: egressip
- register: egressips
- - name: Get the remaining available egress IPs from openshift.egress_range.
- ansible.builtin.set_fact:
- egressips_avail: "{{ egressips_full | difference(egressips | community.general.json_query('resources[*].status.items[*].egressIP') | flatten) }}"
- - name: Ensure that there are still available IPs.
- ansible.builtin.assert:
- that:
- - egressips_avail | length > 0
- success_msg: "OK, {{ egressips_avail | length }} egress IP(s) still available"
- fail_msg: "FATAL: No egress IPs remain available. Please remove some projects and release their IPs, then retry."
- - name: Find an available egress IP from openshift.egress_range, or...
- ansible.builtin.set_fact:
- allocated_egressip: "{{ egressips_avail[0] }}"
- when: role.egress_ip is not defined
- - name: ...if egress IP was specified, ensure it is available and in openshift.egress_range.
- block:
- - name: Verify the requested IP is still available.
- ansible.builtin.assert:
- that:
- - role.egress_ip in egressips_avail
- success_msg: "OK, requested egress IP is still available."
- fail_msg: "FATAL: requested egress IP ({{ role.egress_ip }}) is not available or not from egress range ({{ openshift.egress_range }})."
- - name: If we survived up until here, that is an acceptable egress IP.
- ansible.builtin.set_fact:
- allocated_egressip: "{{ role.egress_ip }}"
- when: role.egress_ip is defined
- when: (role.state | default('present')) == 'present'
- - name: Verify that the project exists and is a valid ICHP namespace.
- block:
- - name: Ensure that the project is there.
- kubernetes.core.k8s_info:
- kubeconfig: tmp/kubeconfig-ocp4
- validate_certs: no
- api_version: v1
- kind: namespace
- name: "{{ role.name }}"
- register: namespace
- - name: Fail if the namespace exists.
- ansible.builtin.assert:
- that:
- - namespace.resources is defined
- - namespace.resources | length == 1
- success_msg: "OK, project exists."
- fail_msg: "FATAL: project \"{{ role.name }}\" does not exist."
- - name: Fail if the namespace is not properly labeled.
- ansible.builtin.assert:
- that:
- - namespace.resources is defined
- - namespace.resources | length == 1
- - namespace.resources[0].metadata.labels["ichp.ing.net/generated"] is defined
- success_msg: "OK, project looks like ICHP."
- fail_msg: "FATAL: project \"{{ role.name }}\" does not look like an ICHP project."
- when: (role.state | default('present')) == 'absent'
- - name: Apply the project template to the cluster with correct state set.
- kubernetes.core.k8s:
- kubeconfig: tmp/kubeconfig-ocp4
- validate_certs: no
- template: templates/project-template.yml
- state: "{{ role.state | default('present') }}"
- ...
|