Copilot
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
# SPDX-License-Identifier: MIT-0
|
||||
---
|
||||
- name: Validate rendered Kubernetes resources without a cluster
|
||||
hosts: localhost
|
||||
connection: local
|
||||
gather_facts: false
|
||||
vars:
|
||||
template_directory: "{{ playbook_dir }}/../templates"
|
||||
tasks:
|
||||
- name: Load the role defaults
|
||||
ansible.builtin.include_vars:
|
||||
file: "{{ playbook_dir }}/../defaults/main.yml"
|
||||
|
||||
- name: Set required test inputs
|
||||
ansible.builtin.set_fact:
|
||||
the_button_image: registry.example.com/the-button:1.0.0
|
||||
the_button_ingress_host: button.example.com
|
||||
|
||||
- name: Render default manifests using Ansible's template engine
|
||||
ansible.builtin.set_fact:
|
||||
deployment: "{{ lookup('ansible.builtin.template', template_directory ~ '/deployment.yml.j2') | from_yaml }}"
|
||||
service: "{{ lookup('ansible.builtin.template', template_directory ~ '/service.yml.j2') | from_yaml }}"
|
||||
ingress: "{{ lookup('ansible.builtin.template', template_directory ~ '/ingress.yml.j2') | from_yaml }}"
|
||||
pvc: "{{ lookup('ansible.builtin.template', template_directory ~ '/pvc.yml.j2') | from_yaml }}"
|
||||
|
||||
- name: Check TLS routing, persistent storage, and single-writer invariants
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- deployment.apiVersion == 'apps/v1'
|
||||
- deployment.spec.replicas == 1
|
||||
- deployment.spec.strategy.type == 'Recreate'
|
||||
- deployment.spec.selector.matchLabels == service.spec.selector
|
||||
- deployment.spec.template.metadata.labels == service.spec.selector
|
||||
- deployment.spec.template.spec.volumes[0].persistentVolumeClaim.claimName == pvc.metadata.name
|
||||
- deployment.spec.template.spec.containers[0].volumeMounts[0].mountPath == '/data'
|
||||
- deployment.spec.template.spec.containers[0].image == the_button_image
|
||||
- deployment.spec.template.spec.containers[0].ports[0].containerPort == 8000
|
||||
- service.spec.type == 'ClusterIP'
|
||||
- service.spec.ports[0].port == 80
|
||||
- service.spec.ports[0].targetPort == 'http'
|
||||
- ingress.apiVersion == 'networking.k8s.io/v1'
|
||||
- ingress.metadata.annotations['cert-manager.io/cluster-issuer'] == 'ca-issuer'
|
||||
- ingress.spec.tls[0].hosts == [the_button_ingress_host]
|
||||
- ingress.spec.tls[0].secretName == 'the-button-tls'
|
||||
- ingress.spec.rules[0].host == the_button_ingress_host
|
||||
- ingress.spec.rules[0].http.paths[0].backend.service.name == service.metadata.name
|
||||
- ingress.spec.rules[0].http.paths[0].backend.service.port.name == 'http'
|
||||
- ingress.spec.rules[0].http.paths[0].pathType == 'Prefix'
|
||||
- "'ingressClassName' not in ingress.spec"
|
||||
- "'storageClassName' not in pvc.spec"
|
||||
- pvc.spec.accessModes == ['ReadWriteOnce']
|
||||
- pvc.spec.resources.requests.storage == '1Gi'
|
||||
|
||||
- name: Check container hardening and health probes
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- not deployment.spec.template.spec.automountServiceAccountToken
|
||||
- deployment.spec.template.spec.securityContext.runAsNonRoot
|
||||
- deployment.spec.template.spec.securityContext.runAsUser == 10001
|
||||
- deployment.spec.template.spec.securityContext.fsGroup == 10001
|
||||
- deployment.spec.template.spec.securityContext.seccompProfile.type == 'RuntimeDefault'
|
||||
- not deployment.spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation
|
||||
- deployment.spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem
|
||||
- deployment.spec.template.spec.containers[0].securityContext.capabilities.drop == ['ALL']
|
||||
- deployment.spec.template.spec.containers[0].startupProbe.httpGet.path == '/api/state'
|
||||
- deployment.spec.template.spec.containers[0].readinessProbe.httpGet.port == 'http'
|
||||
- deployment.spec.template.spec.containers[0].livenessProbe.httpGet.port == 'http'
|
||||
|
||||
- name: Configure custom deployment settings
|
||||
ansible.builtin.set_fact:
|
||||
the_button_name: custom-button
|
||||
the_button_namespace: games
|
||||
the_button_ingress_class_name: nginx
|
||||
the_button_ingress_annotations:
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
cert-manager.io/cluster-issuer: custom-ca-issuer
|
||||
the_button_existing_claim: restored-game-data
|
||||
the_button_storage_class: fast
|
||||
the_button_image_pull_secrets:
|
||||
- private-registry
|
||||
the_button_duration_seconds: 60
|
||||
the_button_node_selector:
|
||||
kubernetes.io/os: linux
|
||||
the_button_tolerations:
|
||||
- key: games
|
||||
operator: Exists
|
||||
effect: NoSchedule
|
||||
|
||||
- name: Render custom manifests
|
||||
ansible.builtin.set_fact:
|
||||
deployment: "{{ lookup('ansible.builtin.template', template_directory ~ '/deployment.yml.j2') | from_yaml }}"
|
||||
ingress: "{{ lookup('ansible.builtin.template', template_directory ~ '/ingress.yml.j2') | from_yaml }}"
|
||||
pvc: "{{ lookup('ansible.builtin.template', template_directory ~ '/pvc.yml.j2') | from_yaml }}"
|
||||
|
||||
- name: Check configurable settings and custom annotations
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- deployment.metadata.name == 'custom-button'
|
||||
- deployment.metadata.namespace == 'games'
|
||||
- deployment.spec.template.spec.volumes[0].persistentVolumeClaim.claimName == 'restored-game-data'
|
||||
- deployment.spec.template.spec.imagePullSecrets == [{'name':'private-registry'}]
|
||||
- deployment.spec.template.spec.nodeSelector['kubernetes.io/os'] == 'linux'
|
||||
- deployment.spec.template.spec.tolerations[0].key == 'games'
|
||||
- deployment.spec.template.spec.containers[0].env[2].value == '60'
|
||||
- ingress.spec.ingressClassName == 'nginx'
|
||||
- ingress.metadata.annotations['nginx.ingress.kubernetes.io/ssl-redirect'] == 'true'
|
||||
- ingress.metadata.annotations['cert-manager.io/cluster-issuer'] == 'custom-ca-issuer'
|
||||
- ingress.spec.tls[0].secretName == 'custom-button-tls'
|
||||
- pvc.spec.storageClassName == 'fast'
|
||||
|
||||
- name: Configure a namespace-scoped issuer through annotations
|
||||
ansible.builtin.set_fact:
|
||||
the_button_ingress_annotations:
|
||||
cert-manager.io/issuer: namespace-issuer
|
||||
|
||||
- name: Render ingress with a namespace-scoped issuer
|
||||
ansible.builtin.set_fact:
|
||||
ingress: "{{ lookup('ansible.builtin.template', template_directory ~ '/ingress.yml.j2') | from_yaml }}"
|
||||
|
||||
- name: Check issuer annotations are rendered without injected defaults
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ingress.metadata.annotations == the_button_ingress_annotations
|
||||
- "'cert-manager.io/cluster-issuer' not in ingress.metadata.annotations"
|
||||
|
||||
- name: Configure an empty annotations map
|
||||
ansible.builtin.set_fact:
|
||||
the_button_ingress_annotations: {}
|
||||
|
||||
- name: Render ingress without annotations
|
||||
ansible.builtin.set_fact:
|
||||
ingress: "{{ lookup('ansible.builtin.template', template_directory ~ '/ingress.yml.j2') | from_yaml }}"
|
||||
|
||||
- name: Check annotations can be cleared entirely
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- ingress.metadata.annotations == {}
|
||||
|
||||
- name: Disable dynamic provisioning
|
||||
ansible.builtin.set_fact:
|
||||
the_button_storage_class: ""
|
||||
|
||||
- name: Render a claim with dynamic provisioning disabled
|
||||
ansible.builtin.set_fact:
|
||||
static_pvc: "{{ lookup('ansible.builtin.template', template_directory ~ '/pvc.yml.j2') | from_yaml }}"
|
||||
|
||||
- name: Check explicit empty StorageClass is preserved
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- static_pvc.spec.storageClassName == ''
|
||||
Reference in New Issue
Block a user