In a kubernetes operator, what's the correct way to trigger reconciliation on another resource type?

Viewed 85

I have written an Ansible operator using the operator-sdk that assists with our cluster on boarding: from a single ProjectDefinition resource, the operator provisions a namespace, groups, rolebindings, resourcequotas, and limitranges.

The resourcequotas and limitranges are defined in ProjectQuota resource, and are referenced by name in the ProjectDefinition.

When the content of a ProjectQuota resource is modified, I want to ensure that those changes propagate to any managed namespaces that use the named quota. Right now, I'm doing it this way:

  1. calculating a content hash for the ProjectQuota
  2. Look up namespaces that reference the quota using a label selector
  3. Annotate the discovered namespaces with the content hash

The namespace update triggers a reconciliation of the associated ProjectDefinition because of the ownerReference on the namespace, and this in turn propagates the changes in the ProjectQuota.

In other words, the projectquota role does this:

---
# tasks file for ProjectQuota
- name: Calculate content_hash
  set_fact:
    content_hash: "{{ quotadef|to_json|hash('sha256') }}"
  vars:
    quotadef:
      q: "{{ resource_quota|default({}) }}"
      l: "{{ limit_range|default({}) }}"

- name: Lookup up affected namespaces
  kubernetes.core.k8s_info:
    api_version: v1
    kind: namespace
    label_selectors:
      - "example.com/named-quota = {{ ansible_operator_meta.name }}"
  register: namespaces

- name: Update namespaces
  kubernetes.core.k8s:
    state: present
    definition:
      apiVersion: v1
      kind: Namespace
      metadata:
        name: "{{ namespace.metadata.name }}"
        annotations:
          example.com/named-quota-hash: "{{ content_hash }}"
  loop: "{{ namespaces.resources }}"
  loop_control:
    loop_var: namespace
    label: "{{ namespace.metadata.name }}"

And the projectdefinition role does (among other things) this:

- name: "{{ ansible_operator_meta.name }} : handle named quota"
  when: >-
    quota.quota_name|default(false)
  block:
    - name: "{{ ansible_operator_meta.name }} : look up named quota"
      kubernetes.core.k8s_info:
        api_version: "{{ apiVersion }}"
        kind: ProjectQuota
        name: "{{ quota.quota_name }}"
      register: named_quota

    - name: "{{ ansible_operator_meta.name }} : label namespace"
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: Namespace
          metadata:
            name: "{{ ansible_operator_meta.name }}"
            namespace: "{{ ansible_operator_meta.name }}"
            labels:
              example.com/named-quota: "{{ quota.quota_name }}"

    - name: "{{ ansible_operator_meta.name }} : apply resourcequota"
      when: >-
        "resourceQuota" in named_quota.resources[0].spec
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: ResourceQuota
          metadata:
            name: "default"
            namespace: "{{ ansible_operator_meta.name }}"
            labels:
              example.com/project: "{{ ansible_operator_meta.name }}"
          spec: "{{ named_quota.resources[0].spec.resourceQuota }}"

    - name: "{{ ansible_operator_meta.name }} : apply limitrange"
      when: >-
        "limitRange" in named_quota.resources[0].spec
      kubernetes.core.k8s:
        state: present
        definition:
          apiVersion: v1
          kind: LimitRange
          metadata:
            name: "default"
            namespace: "{{ ansible_operator_meta.name }}"
            labels:
              example.com/project: "{{ ansible_operator_meta.name }}"
          spec: "{{ named_quota.resources[0].spec.limitRange }}"

This all works, but this seems like the sort of thing for which there is probably a canonical solution. Is this it? I initially tried using the generation on the ProjectQuota instead of a content hash, but this value isn't exposed to the role by the Ansible operator.

0 Answers
Related