Ver código fonte

basic role to create a new project and egressip - lots of todos

Grega Bremec 1 mês atrás
pai
commit
3dc31561a0

+ 68 - 0
playbooks/create-project.yml

@@ -0,0 +1,68 @@
+---
+# Pass variables to this playbook on the command line (-e):
+#
+#   user:         the user requesting the project (role.requester)
+#   project:      the name of the project (role.name)
+#   rbac:         last token of "ichp-project-${foo}"
+#                 (admin, editor, viewer, debugger)
+#                 (becomes role.rbac_level, defaults to "editor")
+#
+# For anything more complex, create a vars file and load it (-e @file.yml).
+# See the structure of the vars below. Generally do not set egress_ip.
+#
+# TODO: establish egress IP?
+# TODO: remove egress IPs without their corresponding projects
+#
+- name: Create an ICHP-lookalike project.
+  hosts: workstation.lab.example.com
+  gather_subset: min
+  become: no
+  tasks:
+    # Get auth info, and test comms.
+    - include_role:
+        name: check-env
+        apply:
+          tags:
+            - check
+      tags:
+        - check
+    - include_role:
+        name: create-ichp-project
+        apply:
+          tags:
+            - create
+      vars:
+        role:
+          requester: "{{ user }}"
+          name: "{{ project }}"
+          displayname: "{{ displayname | default(omit) }}"
+          rbac_level: "ichp-project-{{ rbac | default('editor') }}"
+          egress_ip: "192.168.50.38"
+          #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 (no defaults)
+          #    limit:
+          #      cpu:
+          #      memory:
+          #    request:
+          #      cpu:
+          #      memory:
+          #  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)
+      tags:
+        - create
+...

+ 38 - 0
playbooks/delete-project.yml

@@ -0,0 +1,38 @@
+---
+# Pass variables to this playbook on the command line (-e):
+#
+#   project:      the name of the project (role.name)
+#
+- name: Ensure an ICHP-lookalike project is gone.
+  hosts: workstation.lab.example.com
+  gather_subset: min
+  become: no
+  tasks:
+    - name: Ensure that the parameters are specified.
+      ansible.builtin.assert:
+        that:
+          - project is defined
+        success_msg: "OK, got all parameters, continuing."
+        fail_msg: "FATAL: You must specify the name of the project to delete using the \"project\" variable."
+
+    # Get auth info, and test comms.
+    - include_role:
+        name: check-env
+        apply:
+          tags:
+            - check
+      tags:
+        - check
+
+    - include_role:
+        name: create-ichp-project
+        apply:
+          tags:
+            - delete
+      vars:
+        role:
+          state: absent
+          name: "{{ project }}"
+      tags:
+        - delete
+...

+ 58 - 0
playbooks/roles/create-ichp-project/tasks/main.yml

@@ -0,0 +1,58 @@
+---
+# 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!
+#
+# TODO: verify stuff before applying template
+#
+- name: Show the values at verbosity 1+
+  ansible.builtin.debug:
+    var: role
+    verbosity: 1
+
+- name: Apply the project template to the cluster.
+  kubernetes.core.k8s:
+    kubeconfig: tmp/kubeconfig-ocp4
+    validate_certs: no
+    template: templates/project-template.yml
+    state: "{{ role.state | default('present') }}"
+...

+ 143 - 0
playbooks/roles/create-ichp-project/templates/project-template.yml

@@ -0,0 +1,143 @@
+---
+apiVersion: v1
+kind: List
+metadata: {}
+items:
+- apiVersion: project.openshift.io/v1
+  kind: Project
+  metadata:
+{% if (role.state | default("present")) == "present" %}
+    annotations:
+      openshift.io/description: "ICHP Namespace Requested For {{ role.requester }}"
+      openshift.io/display-name: "{{ role.displayname | default(role.name) }}"
+      openshift.io/requester: {{ role.requester }}
+{% endif %}
+    name: {{ role.name }}
+  spec: {}
+{% if (role.state | default("present")) == "present" %}
+- apiVersion: rbac.authorization.k8s.io/v1
+  kind: RoleBinding
+  metadata:
+    name: {{ role.rbac_level }}
+    namespace: {{ role.name }}
+    labels:
+      ichp.ing.net/requester-rolebinding: ''
+  roleRef:
+    apiGroup: rbac.authorization.k8s.io
+    kind: ClusterRole
+    name: {{ role.rbac_level }}
+  subjects:
+  - apiGroup: rbac.authorization.k8s.io
+    kind: User
+    name: {{ role.requester }}
+- apiVersion: networking.k8s.io/v1
+  kind: NetworkPolicy
+  metadata:
+    name: allow-from-ichp-infra
+    namespace: {{ role.name }}
+  spec:
+    ingress:
+    - from:
+      - namespaceSelector:
+          matchLabels:
+            ichp_infra: "true"
+    podSelector: {}
+    policyTypes:
+    - Ingress
+- apiVersion: networking.k8s.io/v1
+  kind: NetworkPolicy
+  metadata:
+    name: allow-from-openshift-ingress
+    namespace: {{ role.name }}
+  spec:
+    ingress:
+    - from:
+      - namespaceSelector:
+          matchLabels:
+            network.openshift.io/policy-group: ingress
+    podSelector: {}
+    policyTypes:
+    - Ingress
+- apiVersion: networking.k8s.io/v1
+  kind: NetworkPolicy
+  metadata:
+    name: allow-from-same-namespace
+    namespace: {{ role.name }}
+  spec:
+    ingress:
+    - from:
+      - podSelector: {}
+    podSelector: {}
+    policyTypes:
+    - Ingress
+- apiVersion: networking.k8s.io/v1
+  kind: NetworkPolicy
+  metadata:
+    name: deny-from-all
+    namespace: {{ role.name }}
+  spec:
+    podSelector: {}
+    policyTypes:
+    - Ingress
+- apiVersion: v1
+  kind: ResourceQuota
+  metadata:
+    name: compute-quota
+    namespace: {{ role.name }}
+  spec:
+    hard:
+      requests.cpu: {{ role.quota.requests.cpu | default("1500m") }}
+      requests.memory: {{ role.quota.requests.memory | default("2048Mi") }}
+      limits.cpu: {{ role.quota.limits.cpu | default("4000m") }}
+      limits.memory: {{ role.quota.limits.memory | default("4096Mi") }}
+- apiVersion: v1
+  kind: ResourceQuota
+  metadata:
+    name: storage-quota
+    namespace: {{ role.name }}
+  spec:
+    hard:
+      persistentvolumeclaims: 0
+      requests.storage: "0"
+      requests.ephemeral-storage: 2048Mi
+      limits.ephemeral-storage: 4096Mi
+- apiVersion: v1
+  kind: LimitRange
+  metadata:
+    name: limit-ranges
+    namespace: {{ role.name }}
+  spec:
+    limits:
+      - type: Container
+        max:
+          cpu: {{ role.lrange.max.cpu | default("4000m") }}
+          memory: {{ role.lrange.max.memory | default("4096Mi") }}
+        min:
+          cpu: {{ role.lrange.min.cpu | default("50m") }}
+          memory: {{ role.lrange.min.memory|  default("64Mi") }}
+        maxLimitRequestRatio:
+          cpu: {{ role.lrange.ratio.cpu | default(4) }}
+          memory: {{ role.lrange.ratio.memory | default(4) }}
+        default:
+          cpu: {{ role.lrange.default.limit.cpu | default((role.lrange.min.cpu | default("50m") | regex_replace('m$', '') | int) * (role.lrange.ratio.cpu | default(4))) | regex_replace('m$', '') }}m
+          memory: {{ role.lrange.default.limit.memory | default((role.lrange.min.memory | default("64Mi") | regex_replace('Mi$', '') | int) * (role.lrange.ratio.memory | default(4))) | regex_replace('Mi$', '') }}Mi
+        defaultRequest:
+          cpu: {{ role.lrange.default.request.cpu | default(role.lrange.min.cpu | default("50m")) }}
+          memory: {{ role.lrange.default.request.memory | default(role.lrange.min.memory | default("64Mi")) }}
+{% endif %}
+- apiVersion: k8s.ovn.org/v1
+  kind: EgressIP
+  metadata:
+    name: egress-ns-{{ role.name }}
+    labels:
+      egress.for.namespace: {{ role.name }}
+{% if (role.state | default("present")) == "present" %}
+  spec:
+    egressIPs:
+      - {{ role.egress_ip }}
+    namespaceSelector:
+      matchLabels:
+        kubernetes.io/metadata.name: {{ role.name }}
+    podSelector: {}
+{% endif %}
+...