From 898d6ddfcc6cd25f4e9d85a9ce137ac9f5f958db Mon Sep 17 00:00:00 2001 From: Johnathan Kupferer Date: Wed, 1 Oct 2025 16:37:35 -0400 Subject: [PATCH] Change to use handler finalizer - Use simple /handler finalizer regardless of handler index. - Support deprecated finalizers. --- Containerfile | 2 +- operator/operator.py | 9 +- .../tasks/test-finalizers-01.yaml | 158 ++++++++++++++++++ .../roles/poolboy_test_simple/tasks/test.yaml | 1 + 4 files changed, 167 insertions(+), 3 deletions(-) create mode 100644 test/roles/poolboy_test_simple/tasks/test-finalizers-01.yaml diff --git a/Containerfile b/Containerfile index cf43ef0..1ecad06 100644 --- a/Containerfile +++ b/Containerfile @@ -8,7 +8,7 @@ RUN rm -rf /tmp/src/.git* && \ chown -R 1001 /tmp/src && \ chgrp -R 0 /tmp/src && \ chmod -R g+w /tmp/src && \ - pip install git+https://github.com/rhpds/kopf.git@add-label-selector + pip install git+https://github.com/rhpds/kopf.git@add-deprecated-finalizer-support USER 1001 diff --git a/operator/operator.py b/operator/operator.py index da2dd6c..6cf0104 100755 --- a/operator/operator.py +++ b/operator/operator.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 import asyncio import logging +import re from typing import Mapping import kopf @@ -25,13 +26,17 @@ async def startup(logger: kopf.ObjectLogger, settings: kopf.OperatorSettings, ** # Never give up from network errors settings.networking.error_backoffs = InfiniteRelativeBackoff() - # Use operator domain as finalizer + # Set finalizer based on operator mode settings.persistence.finalizer = ( - f"{Poolboy.operator_domain}/handler-{Poolboy.resource_handler_idx}" if Poolboy.operator_mode_resource_handler else + f"{Poolboy.operator_domain}/handler" if Poolboy.operator_mode_resource_handler else f"{Poolboy.operator_domain}/watch-{Poolboy.resource_watch_name}" if Poolboy.operator_mode_resource_watch else Poolboy.operator_domain ) + # Support deprecated resource handler finalizer + if Poolboy.operator_mode_resource_handler: + settings.persistence.deprecated_finalizer = re.compile(re.escape(Poolboy.operator_domain) + '/handler-\d+$') + # Store progress in status. settings.persistence.progress_storage = kopf.StatusProgressStorage(field='status.kopf.progress') diff --git a/test/roles/poolboy_test_simple/tasks/test-finalizers-01.yaml b/test/roles/poolboy_test_simple/tasks/test-finalizers-01.yaml new file mode 100644 index 0000000..f39897c --- /dev/null +++ b/test/roles/poolboy_test_simple/tasks/test-finalizers-01.yaml @@ -0,0 +1,158 @@ +--- +- name: Create ResourceProvider test-finalizers-01 + kubernetes.core.k8s: + definition: + apiVersion: "{{ poolboy_domain }}/v1" + kind: ResourceProvider + metadata: + name: test-finalizers-01 + namespace: "{{ poolboy_namespace }}" + labels: >- + {{ { + poolboy_domain ~ "/test": "simple" + } }} + spec: + override: + apiVersion: "{{ poolboy_domain }}/v1" + kind: ResourceClaimTest + metadata: + name: test-finalizers-01-{% raw %}{{ guid }}{% endraw %} + namespace: "{{ poolboy_test_namespace }}" + parameters: + - name: stringvar + allowUpdate: true + required: true + validation: + openAPIV3Schema: + type: string + default: one + enum: + - one + - two + - three + template: + definition: + spec: + stringvalue: "{% raw %}{{ stringvar }}{% endraw %}" + enable: true + updateFilters: + - pathMatch: /spec/.* + allowedOps: + - replace + +- name: Create ResourceClaim test-finalizers-01-a + kubernetes.core.k8s: + definition: + apiVersion: "{{ poolboy_domain }}/v1" + kind: ResourceClaim + metadata: + name: test-finalizers-01-a + namespace: "{{ poolboy_test_namespace }}" + labels: >- + {{ { + poolboy_domain ~ "/test": "simple" + } }} + spec: + provider: + name: test-finalizers-01 + parameterValues: + stringvar: "one" + +- name: Verify handling of ResourceClaim test-finalizers-01-a + kubernetes.core.k8s_info: + api_version: "{{ poolboy_domain }}/v1" + kind: ResourceClaim + name: test-finalizers-01-a + namespace: "{{ poolboy_test_namespace }}" + register: r_get_resource_claim + failed_when: >- + r_get_resource_claim.resources[0].status.resources[0].state is undefined + until: r_get_resource_claim is success + delay: 1 + retries: 10 + +- name: Save facts from for ResourceClaim test-finalizers-01-a + vars: + __name: >- + {{ r_get_resource_claim.resources[0].status.resourceHandle.name }} + set_fact: + resource_claim_test_finalizers_01_a_resource_handle_name: "{{ __name }}" + resource_claim_test_finalizers_01_a_resource_name: test-finalizers-01-{{ __name[5:] }} + +- name: Verify state of ResourceClaim test-finalizers-01-a + vars: + __state: "{{ r_get_resource_claim.resources[0] }}" + assert: + that: + - __state.status.resources[0].state.metadata.name == resource_claim_test_finalizers_01_a_resource_name + - __state.status.resources[0].state.spec.stringvalue == "one" + +- name: Verify creation of ResourceClaimTest test-finalizers-01-a + kubernetes.core.k8s_info: + api_version: "{{ poolboy_domain }}/v1" + kind: ResourceClaimTest + name: "{{ resource_claim_test_finalizers_01_a_resource_name }}" + namespace: "{{ poolboy_test_namespace }}" + register: r_get_resource_claim_test + failed_when: r_get_resource_claim_test.resources | length != 1 + until: r_get_resource_claim_test is success + delay: 1 + retries: 10 + +- name: Verify finalizers on ResourceHandle for test-finalizers-01-a + kubernetes.core.k8s_info: + api_version: "{{ poolboy_domain }}/v1" + kind: ResourceHandle + name: "{{ resource_claim_test_finalizers_01_a_resource_handle_name }}" + namespace: "{{ poolboy_namespace }}" + register: r_get_resource_handle + failed_when: >- + r_get_resource_handle.resources | length != 1 or + r_get_resource_handle.resources[0].metadata.finalizers is undefined or + r_get_resource_handle.resources[0].metadata.finalizers != [poolboy_domain ~ '/handler'] + +- name: Set deprecated finalizer on ResourceHandle for test-finalizers-01-a + kubernetes.core.k8s: + api_version: "{{ poolboy_domain }}/v1" + kind: ResourceHandle + name: "{{ resource_claim_test_finalizers_01_a_resource_handle_name }}" + namespace: "{{ poolboy_namespace }}" + definition: + metadata: + finalizers: >- + {{ [poolboy_domain ~ '/handler-9'] }} + +- name: Pause 2 seconds + ansible.builtin.pause: + seconds: 2 + +- name: Verify finalizers on ResourceHandle for test-finalizers-01-a + kubernetes.core.k8s_info: + api_version: "{{ poolboy_domain }}/v1" + kind: ResourceHandle + name: "{{ resource_claim_test_finalizers_01_a_resource_handle_name }}" + namespace: "{{ poolboy_namespace }}" + register: r_get_resource_handle + failed_when: >- + r_get_resource_handle.resources | length != 1 or + r_get_resource_handle.resources[0].metadata.finalizers is undefined or + r_get_resource_handle.resources[0].metadata.finalizers != [poolboy_domain ~ '/handler-9'] + +- name: Delete ResourceClaim test-finalizers-01-a + kubernetes.core.k8s: + api_version: "{{ poolboy_domain }}/v1" + kind: ResourceClaim + name: test-finalizers-01-a + namespace: "{{ poolboy_test_namespace }}" + state: absent + +- name: Verify deletion completes on ResourceHandle for test-finalizers-01-a + kubernetes.core.k8s_info: + api_version: "{{ poolboy_domain }}/v1" + kind: ResourceHandle + name: "{{ resource_claim_test_finalizers_01_a_resource_handle_name }}" + namespace: "{{ poolboy_namespace }}" + register: r_get_resource_handle + failed_when: >- + r_get_resource_handle.resources | length != 0 +... diff --git a/test/roles/poolboy_test_simple/tasks/test.yaml b/test/roles/poolboy_test_simple/tasks/test.yaml index 571f8f4..c07367f 100644 --- a/test/roles/poolboy_test_simple/tasks/test.yaml +++ b/test/roles/poolboy_test_simple/tasks/test.yaml @@ -7,6 +7,7 @@ - test-02.yaml - test-approval-01.yaml - test-ignore-01.yaml + - test-finalizers-01.yaml - test-lifespan-start-01.yaml - test-linked-01.yaml - test-linked-02.yaml