Adding Owner References for Existing Resources

Owner references are automatically injected only during creation of resources. Enabling owner reference injection will not update objects created while owner reference injection is disabled

This guide will demonstrate how to retroactively set owner references for existing resources.

A GET request to the owning resource will provide the necessary data to construct an ownerReference or an annotation.

$ kubectl get memcacheds.cache.example.com -o yaml

Example Response (Abbreviated):

  1. apiVersion: cache.example.com/v1alpha1
  2. kind: Memcached
  3. metadata:
  4. name: example-memcached
  5. namespace: default
  6. uid: 2a94ff2b-84e0-40ce-8b5e-2b7e4d2bc0e2

kubectl edit can be used to update the resources by hand. See below for example ownerReference and annotations.

For objects in the same namespace as the Owner (CR)

Dependent resources within the same namespace as the owning CR are tracked with the ownerReference field.

ownerReference structure:

  • apiVersion: {group}/{version}
  • kind: {kind}
  • name: {metadata.name}
  • uid: {metadata.uid}

Example ownerReference:

  1. metadata:
  2. ...(snip)
  3. ownerReferences:
  4. - apiVersion: cache.example.com/v1alpha1
  5. kind: Memcached
  6. name: example-memcached
  7. uid: ad834522-d9a5-4841-beac-991ff3798c00

For objects which are NOT in the same namespace as the Owner (CR)

An annotation is used instead of an ownerReference if the dependent resource is in a different namespace than the CR, or the dependent resource is a cluster level resource.

annotation structure:

  • operator-sdk/primary-resource: {metadata.namespace}/{metadata.name}
  • operator-sdk/primary-resource-type: {kind}.{group}

NOTE: The {group} can be found by splitting the apiVersion metadata of the CR, into group and version. As an example, this apiVersion field gives us the group cache.example.com.

Example Annotation:

  1. metadata:
  2. ...(snip)
  3. annotations:
  4. operator-sdk/primary-resource: default/example-memcached
  5. operator-sdk/primary-resource-type: Memcached.cache.example.com

Migration using Ansible assets

If you have many resources to update, it may be easier to use the following Ansible assets, which should be considered an example rather than an officially supported workflow.

To use these assets, create a vars.yml as specified below and copy playbook.yml and each_resource.yml into the same directory. Execute the playbook with:

  1. $ ansible-playbook -i localhost playbook.yml

vars.yml

This file should be created by the user to configure the playbook, and needs to contain:

  • owning_resource
    • apiVersion
    • kind
    • name
    • namespace
  • resources_to_own (list): For each resource, specify:
    • name
    • namespace (if applicable)
    • apiVersion
    • kind
  1. owning_resource:
  2. apiVersion: cache.example.com/v1alpha1
  3. kind: Memcached
  4. name: example-memcached
  5. namespace: default
  6. resources_to_own:
  7. - name: example-memcached-memcached
  8. namespace: default
  9. apiVersion: apps/v1
  10. kind: Deployment
  11. - name: example-memcached
  12. apiVersion: v1
  13. kind: Namespace

playbook.yml

This file can be used as-is without user adjustments.

  1. - hosts: localhost
  2. tasks:
  3. - name: Import user variables
  4. include_vars: vars.yml
  5. - name: Retrieve owning resource
  6. community.kubernetes.k8s_info:
  7. api_version: "{{ owning_resource.apiVersion }}"
  8. kind: "{{ owning_resource.kind }}"
  9. name: "{{ owning_resource.name }}"
  10. namespace: "{{ owning_resource.namespace }}"
  11. register: extra_owner_data
  12. - name: Ensure resources are owned
  13. include_tasks: each_resource.yml
  14. loop: "{{ resources_to_own }}"
  15. vars:
  16. to_be_owned: '{{ q("community.kubernetes.k8s",
  17. api_version=item.apiVersion,
  18. kind=item.kind,
  19. resource_name=item.name,
  20. namespace=item.namespace
  21. ).0 }}'
  22. owner_reference:
  23. apiVersion: "{{ owning_resource.apiVersion }}"
  24. kind: "{{ owning_resource.kind }}"
  25. name: "{{ owning_resource.name }}"
  26. uid: "{{ extra_owner_data.resources[0].metadata.uid }}"

each_resource.yml

This file can be used as-is without user adjustments.

  1. - name: Patch resource with owner reference
  2. when:
  3. - to_be_owned.metadata.namespace is defined
  4. - to_be_owned.metadata.namespace == owning_resource.namespace
  5. - (to_be_owned.metadata.ownerReferences is not defined) or
  6. (owner_reference not in to_be_owned.metadata.ownerReferences)
  7. community.kubernetes.k8s:
  8. state: present
  9. resource_definition:
  10. apiVersion: "{{ to_be_owned.apiVersion }}"
  11. kind: "{{ to_be_owned.kind }}"
  12. metadata:
  13. name: "{{ to_be_owned.metadata.name }}"
  14. namespace: "{{ to_be_owned.metadata.namespace }}"
  15. ownerReferences: "{{ (to_be_owned.metadata.ownerReferences | default([])) + [owner_reference] }}"
  16. - name: Patch resource with owner annotation
  17. when: to_be_owned.namespace is not defined or to_be_owned.namespace != owning_resource.namespace
  18. community.kubernetes.k8s:
  19. state: present
  20. resource_definition:
  21. apiVersion: "{{ to_be_owned.apiVersion }}"
  22. kind: "{{ to_be_owned.kind }}"
  23. metadata:
  24. name: "{{ to_be_owned.metadata.name }}"
  25. namespace: "{{ to_be_owned.metadata.namespace | default(omit)}}"
  26. annotations:
  27. operator-sdk/primary-resource: "{{ owning_resource.namespace }}/{{ owning_resource.name }}"
  28. operator-sdk/primary-resource-type: "{{ owning_resource.kind }}.{{ owning_resource.apiVersion.split('/')[0] }}"

Last modified January 1, 0001