--- - block: - name: Ensure namespace exists k8s: definition: apiVersion: v1 kind: Namespace metadata: name: "{{ test_namespace }}" - name: Add a configmap k8s: name: "apply-configmap" namespace: "{{ test_namespace }}" definition: kind: ConfigMap apiVersion: v1 data: one: "1" two: "2" three: "3" apply: yes register: k8s_configmap - name: Check configmap was created assert: that: - k8s_configmap is changed - k8s_configmap.result.metadata.annotations|default(False) - name: Add same configmap again k8s: definition: kind: ConfigMap apiVersion: v1 metadata: name: "apply-configmap" namespace: "{{ test_namespace }}" data: one: "1" two: "2" three: "3" apply: yes register: k8s_configmap_2 - name: Check nothing changed assert: that: - k8s_configmap_2 is not changed - name: Add same configmap again with check mode on k8s: definition: kind: ConfigMap apiVersion: v1 metadata: name: "apply-configmap" namespace: "{{ test_namespace }}" data: one: "1" two: "2" three: "3" apply: yes check_mode: yes register: k8s_configmap_check - name: Check nothing changed assert: that: - k8s_configmap_check is not changed - name: Add same configmap again but using name and namespace args k8s: name: "apply-configmap" namespace: "{{ test_namespace }}" definition: kind: ConfigMap apiVersion: v1 data: one: "1" two: "2" three: "3" apply: yes register: k8s_configmap_2a - name: Check nothing changed assert: that: - k8s_configmap_2a is not changed - name: Update configmap k8s: definition: kind: ConfigMap apiVersion: v1 metadata: name: "apply-configmap" namespace: "{{ test_namespace }}" data: one: "1" three: "3" four: "4" apply: yes register: k8s_configmap_3 - name: Ensure that configmap has been correctly updated assert: that: - k8s_configmap_3 is changed - "'four' in k8s_configmap_3.result.data" - "'two' not in k8s_configmap_3.result.data" - name: Add a service k8s: definition: apiVersion: v1 kind: Service metadata: name: apply-svc namespace: "{{ test_namespace }}" spec: selector: app: whatever ports: - name: http port: 8080 targetPort: 8080 apply: yes register: k8s_service - name: Add exactly same service k8s: definition: apiVersion: v1 kind: Service metadata: name: apply-svc namespace: "{{ test_namespace }}" spec: selector: app: whatever ports: - name: http port: 8080 targetPort: 8080 apply: yes register: k8s_service_2 - name: Check nothing changed assert: that: - k8s_service_2 is not changed - name: Add exactly same service in check mode k8s: definition: apiVersion: v1 kind: Service metadata: name: apply-svc namespace: "{{ test_namespace }}" spec: selector: app: whatever ports: - name: http port: 8080 targetPort: 8080 apply: yes register: k8s_service_3 check_mode: yes - name: Check nothing changed assert: that: - k8s_service_3 is not changed - name: Change service ports k8s: definition: apiVersion: v1 kind: Service metadata: name: apply-svc namespace: "{{ test_namespace }}" spec: selector: app: whatever ports: - name: http port: 8081 targetPort: 8081 apply: yes register: k8s_service_4 - name: Check ports are correct assert: that: - k8s_service_4 is changed - k8s_service_4.result.spec.ports | length == 1 - k8s_service_4.result.spec.ports[0].port == 8081 - name: Insert new service port k8s: definition: apiVersion: v1 kind: Service metadata: name: apply-svc namespace: "{{ test_namespace }}" spec: selector: app: whatever ports: - name: mesh port: 8080 targetPort: 8080 - name: http port: 8081 targetPort: 8081 apply: yes register: k8s_service_4 - name: Check ports are correct assert: that: - k8s_service_4 is changed - k8s_service_4.result.spec.ports | length == 2 - k8s_service_4.result.spec.ports[0].port == 8080 - k8s_service_4.result.spec.ports[1].port == 8081 - name: Remove new service port (check mode) k8s: definition: apiVersion: v1 kind: Service metadata: name: apply-svc namespace: "{{ test_namespace }}" spec: selector: app: whatever ports: - name: http port: 8081 targetPort: 8081 apply: yes check_mode: yes register: k8s_service_check - name: Check ports are correct assert: that: - k8s_service_check is changed - k8s_service_check.result.spec.ports | length == 1 - k8s_service_check.result.spec.ports[0].port == 8081 - name: Remove new service port k8s: definition: apiVersion: v1 kind: Service metadata: name: apply-svc namespace: "{{ test_namespace }}" spec: selector: app: whatever ports: - name: http port: 8081 targetPort: 8081 apply: yes register: k8s_service_5 - name: Check ports are correct assert: that: - k8s_service_5 is changed - k8s_service_5.result.spec.ports | length == 1 - k8s_service_5.result.spec.ports[0].port == 8081 - name: Add a serviceaccount k8s: definition: apiVersion: v1 kind: ServiceAccount metadata: name: apply-deploy namespace: "{{ test_namespace }}" - name: Add a deployment k8s: definition: apiVersion: apps/v1 kind: Deployment metadata: name: apply-deploy namespace: "{{ test_namespace }}" spec: replicas: 1 selector: matchLabels: app: "{{ k8s_pod_name }}" template: "{{ k8s_pod_template }}" wait: yes wait_timeout: "{{ k8s_wait_timeout | default(omit) }}" apply: yes vars: k8s_pod_name: apply-deploy k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green k8s_pod_service_account: apply-deploy k8s_pod_ports: - containerPort: 8080 name: http protocol: TCP k8s_pod_resources: requests: cpu: 100m memory: 100Mi limits: cpu: 100m memory: 100Mi - name: Update the earlier deployment in check mode k8s: definition: apiVersion: apps/v1 kind: Deployment metadata: name: apply-deploy namespace: "{{ test_namespace }}" spec: replicas: 1 selector: matchLabels: app: "{{ k8s_pod_name }}" template: "{{ k8s_pod_template }}" wait: yes wait_timeout: "{{ k8s_wait_timeout | default(omit) }}" apply: yes check_mode: yes vars: k8s_pod_name: apply-deploy k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple k8s_pod_service_account: apply-deploy k8s_pod_ports: - containerPort: 8080 name: http protocol: TCP k8s_pod_resources: requests: cpu: 50m limits: cpu: 50m memory: 50Mi register: update_deploy_check_mode - name: Ensure check mode change took assert: that: - update_deploy_check_mode is changed - "update_deploy_check_mode.result.spec.template.spec.containers[0].image == 'gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple'" - name: Update the earlier deployment k8s: definition: apiVersion: apps/v1 kind: Deployment metadata: name: apply-deploy namespace: "{{ test_namespace }}" spec: replicas: 1 selector: matchLabels: app: "{{ k8s_pod_name }}" template: "{{ k8s_pod_template }}" wait: yes wait_timeout: "{{ k8s_wait_timeout | default(omit) }}" apply: yes vars: k8s_pod_name: apply-deploy k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple k8s_pod_service_account: apply-deploy k8s_pod_ports: - containerPort: 8080 name: http protocol: TCP k8s_pod_resources: requests: cpu: 50m limits: cpu: 50m memory: 50Mi register: update_deploy_for_real - name: Ensure change took assert: that: - update_deploy_for_real is changed - "update_deploy_for_real.result.spec.template.spec.containers[0].image == 'gcr.io/kuar-demo/kuard-amd64:v0.10.0-purple'" - name: Remove the serviceaccount k8s: state: absent definition: apiVersion: v1 kind: ServiceAccount metadata: name: apply-deploy namespace: "{{ test_namespace }}" - name: Apply deployment after service account removed k8s: definition: apiVersion: apps/v1 kind: Deployment metadata: name: apply-deploy namespace: "{{ test_namespace }}" spec: replicas: 1 selector: matchLabels: app: "{{ k8s_pod_name }}" template: "{{ k8s_pod_template }}" wait: yes wait_timeout: "{{ k8s_wait_timeout | default(omit) }}" apply: yes vars: k8s_pod_name: apply-deploy k8s_pod_image: gcr.io/kuar-demo/kuard-amd64:v0.10.0-green k8s_pod_service_account: apply-deploy k8s_pod_ports: - containerPort: 8080 name: http protocol: TCP k8s_pod_resources: requests: cpu: 50m limits: cpu: 50m memory: 50Mi register: deploy_after_serviceaccount_removal ignore_errors: yes - name: Ensure that updating deployment after service account removal failed assert: that: - deploy_after_serviceaccount_removal is failed - name: Add a secret k8s: definition: apiVersion: v1 kind: Secret metadata: name: apply-secret namespace: "{{ test_namespace }}" type: Opaque stringData: foo: bar register: k8s_secret - name: Check secret was created assert: that: - k8s_secret is changed - k8s_secret.result.data.foo - name: Add same secret k8s: definition: apiVersion: v1 kind: Secret metadata: name: apply-secret namespace: "{{ test_namespace }}" type: Opaque stringData: foo: bar register: k8s_secret - name: Check nothing changed assert: that: - k8s_secret is not changed - name: Add same secret with check mode on k8s: definition: apiVersion: v1 kind: Secret metadata: name: apply-secret namespace: "{{ test_namespace }}" type: Opaque stringData: foo: bar check_mode: yes register: k8s_secret - name: Check nothing changed assert: that: - k8s_secret is not changed - name: Add same secret with check mode on using data k8s: definition: apiVersion: v1 kind: Secret metadata: name: apply-secret namespace: "{{ test_namespace }}" type: Opaque data: foo: YmFy check_mode: yes register: k8s_secret - name: Check nothing changed assert: that: - k8s_secret is not changed - name: Create network policy (egress array with empty dict) k8s: namespace: "{{ test_namespace }}" apply: true definition: kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: apply-netpolicy labels: app: apply-netpolicy annotations: {} spec: podSelector: matchLabels: app: apply-netpolicy policyTypes: - Ingress - Egress ingress: - ports: - port: 9093 protocol: TCP egress: - {} - name: Apply network policy k8s: namespace: "{{ test_namespace }}" definition: kind: NetworkPolicy apiVersion: networking.k8s.io/v1 metadata: name: apply-netpolicy labels: app: apply-netpolicy annotations: {} spec: podSelector: matchLabels: app: apply-netpolicy policyTypes: - Ingress - Egress ingress: - ports: - port: 9093 protocol: TCP egress: - {} apply: true register: k8s_networkpolicy - name: Check that nothing changed assert: that: - k8s_networkpolicy is not changed # Server Side Apply - name: Create Configmap using server side apply - field_manager not specified k8s: namespace: "{{ test_namespace }}" definition: apiVersion: v1 kind: ConfigMap metadata: name: server-side-cm data: key: value-0 apply: yes server_side_apply: force_conflicts: false register: result ignore_errors: true - name: Check that configmap creation failed assert: that: - result is failed - '"field_manager" in result.msg' - name: Create Configmap using server side apply k8s: namespace: "{{ test_namespace }}" definition: apiVersion: v1 kind: ConfigMap metadata: name: server-side-cm data: key: value-0 apply: yes server_side_apply: field_manager: "manager-00" register: result - name: Check configmap was created with expected manager assert: that: - result is changed - result.result.metadata.managedFields | length == 1 - result.result.metadata.managedFields[0].manager == 'manager-00' - name: Apply ConfigMap using same parameters k8s: namespace: "{{ test_namespace }}" definition: apiVersion: v1 kind: ConfigMap metadata: name: server-side-cm data: key: value-0 apply: yes server_side_apply: field_manager: "manager-00" register: result - name: Assert that nothing change using check_mode assert: that: - result is not changed - name: Apply ConfigMap adding new manager k8s: namespace: "{{ test_namespace }}" definition: apiVersion: v1 kind: ConfigMap metadata: name: server-side-cm data: key: value-0 apply: yes server_side_apply: field_manager: "manager-01" register: result - name: Assert that number of manager has increased assert: that: - result is changed - result.result.metadata.managedFields | length == 2 - name: Apply changes to Configmap using new field_manager k8s: namespace: "{{ test_namespace }}" definition: apiVersion: v1 kind: ConfigMap metadata: name: server-side-cm data: key: value-1 apply: yes server_side_apply: field_manager: "manager-02" register: result ignore_errors: true - name: assert that operation failed with conflicts assert: that: - result is failed - result.reason == 'Conflict' - name: Apply changes to Configmap using new field_manager and force_conflicts k8s: namespace: "{{ test_namespace }}" definition: apiVersion: v1 kind: ConfigMap metadata: name: server-side-cm data: key: value-1 apply: yes server_side_apply: field_manager: "manager-02" force_conflicts: true register: result - name: assert that operation failed with conflicts assert: that: - result is changed - result.result.metadata.managedFields | length == 1 - result.result.metadata.managedFields[0].manager == 'manager-02' - result.result.data.key == 'value-1' # check_mode with server side apply - name: Ensure namespace does not exist k8s: state: absent kind: Namespace name: testing wait: true - name: Create namespace using server_side_apply=true and check_mode=true k8s: apply: true server_side_apply: field_manager: ansible definition: kind: Namespace apiVersion: v1 metadata: name: testing check_mode: true register: _create - name: Ensure namespace was not created k8s_info: kind: Namespace name: testing register: _info - name: Validate that check_mode reported change even if namespace was not created assert: that: - _create is changed - not _info.resources # server side apply over kubernetes client releases - name: Create temporary directory tempfile: state: directory suffix: .server register: path - set_fact: virtualenv_src: "{{ path.path }}" - include_tasks: tasks/server_side_apply.yml with_items: - '24.2.0' - '25.2.0a1' - '25.3.0b1' - '25.3.0' - '23.6.0' always: - name: Remove namespace k8s: kind: Namespace name: "{{ test_namespace }}" state: absent - name: Delete temporary directory file: path: "{{ virtualenv_src }}" state: absent ignore_errors: true when: virtualenv_src is defined