-
Notifications
You must be signed in to change notification settings - Fork 1.8k
doc: Update existing resources with owner refs #2013
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,194 @@ | ||||||
# 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](./advanced_options.md#turning-off-dependent-watches-and-owner-reference-injection) | ||||||
|
||||||
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):** | ||||||
|
||||||
```yaml | ||||||
apiVersion: cache.example.com/v1alpha1 | ||||||
kind: Memcached | ||||||
metadata: | ||||||
name: example-memcached | ||||||
namespace: default | ||||||
uid: 2a94ff2b-84e0-40ce-8b5e-2b7e4d2bc0e2 | ||||||
``` | ||||||
|
||||||
camilamacedo86 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
`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 (CRD) | ||||||
|
||||||
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:** | ||||||
|
||||||
```yaml | ||||||
camilamacedo86 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
metadata: | ||||||
...(snip) | ||||||
ownerReferences: | ||||||
- apiVersion: cache.example.com/v1alpha1 | ||||||
kind: Memcached | ||||||
name: example-memcached | ||||||
uid: ad834522-d9a5-4841-beac-991ff3798c00 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi @fabianvf, Is required to add the UID? If I would like to do it for a pod for example and the pod be re-created automatically by the API platform which is the default behaviour would not it assume a new UID? So, should not we be able to do that without informing a UID? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the UID field is required to construct an ownerReference. This is to correctly garbage collect if the owner is deleted and then re-created There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WDYT about we add a note with this info @asmacdo? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. To me, the delete/recreate edge case seems like an implementation detail which we should leave out to keep the guide simple. I'm happy to add it if it would be helpful though. |
||||||
``` | ||||||
|
||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. WDYT?
Suggested change
Is my understand correctly @fabianvf ? |
||||||
## For objects which are NOT in the same namespace as the Owner (CRD) | ||||||
|
||||||
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](https://github.com/operator-framework/operator-sdk-samples/blob/master/ansible/memcached-operator/deploy/crds/cache_v1alpha1_memcached_cr.yaml#L1) | ||||||
gives us the group `cache.example.com`. | ||||||
|
||||||
**Example Annotation:** | ||||||
|
||||||
```yaml | ||||||
metadata: | ||||||
...(snip) | ||||||
annotations: | ||||||
operator-sdk/primary-resource: default/example-memcached | ||||||
camilamacedo86 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
operator-sdk/primary-resource-type: Memcached.cache.example.com | ||||||
camilamacedo86 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
``` | ||||||
|
||||||
camilamacedo86 marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
## 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: | ||||||
|
||||||
asmacdo marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
``` bash | ||||||
$ 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 | ||||||
fabianvf marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
* apiVersion | ||||||
* kind | ||||||
* name | ||||||
* namespace | ||||||
* resources_to_own (list): For each resource, specify: | ||||||
* name | ||||||
* namespace (if applicable) | ||||||
* apiVersion | ||||||
* kind | ||||||
|
||||||
fabianvf marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
```yaml | ||||||
owning_resource: | ||||||
apiVersion: cache.example.com/v1alpha1 | ||||||
kind: Memcached | ||||||
name: example-memcached | ||||||
namespace: default | ||||||
|
||||||
resources_to_own: | ||||||
- name: example-memcached-memcached | ||||||
namespace: default | ||||||
apiVersion: apps/v1 | ||||||
kind: Deployment | ||||||
- name: example-memcached | ||||||
apiVersion: v1 | ||||||
kind: Namespace | ||||||
``` | ||||||
|
||||||
### playbook.yml | ||||||
|
||||||
This file can be used as-is without user adjustments. | ||||||
|
||||||
```yaml | ||||||
- hosts: localhost | ||||||
|
||||||
tasks: | ||||||
- name: Import user variables | ||||||
include_vars: vars.yml | ||||||
- name: Retrieve owning resource | ||||||
k8s_facts: | ||||||
api_version: "{{ owning_resource.apiVersion }}" | ||||||
kind: "{{ owning_resource.kind }}" | ||||||
name: "{{ owning_resource.name }}" | ||||||
namespace: "{{ owning_resource.namespace }}" | ||||||
register: extra_owner_data | ||||||
|
||||||
- name: Ensure resources are owned | ||||||
include_tasks: each_resource.yml | ||||||
loop: "{{ resources_to_own }}" | ||||||
vars: | ||||||
to_be_owned: '{{ q("k8s", | ||||||
api_version=item.apiVersion, | ||||||
kind=item.kind, | ||||||
resource_name=item.name, | ||||||
namespace=item.namespace | ||||||
).0 }}' | ||||||
owner_reference: | ||||||
apiVersion: "{{ owning_resource.apiVersion }}" | ||||||
kind: "{{ owning_resource.kind }}" | ||||||
name: "{{ owning_resource.name }}" | ||||||
uid: "{{ extra_owner_data.resources[0].metadata.uid }}" | ||||||
``` | ||||||
|
||||||
### `each_resource.yml` | ||||||
|
||||||
This file can be used as-is without user adjustments. | ||||||
|
||||||
``` yaml | ||||||
- name: Patch resource with owner reference | ||||||
when: | ||||||
- to_be_owned.metadata.namespace is defined | ||||||
- to_be_owned.metadata.namespace == owning_resource.namespace | ||||||
- (to_be_owned.metadata.ownerReferences is not defined) or | ||||||
(owner_reference not in to_be_owned.metadata.ownerReferences) | ||||||
k8s: | ||||||
state: present | ||||||
resource_definition: | ||||||
apiVersion: "{{ to_be_owned.apiVersion }}" | ||||||
kind: "{{ to_be_owned.kind }}" | ||||||
metadata: | ||||||
name: "{{ to_be_owned.metadata.name }}" | ||||||
namespace: "{{ to_be_owned.metadata.namespace }}" | ||||||
ownerReferences: "{{ (to_be_owned.metadata.ownerReferences | default([])) + [owner_reference] }}" | ||||||
|
||||||
- name: Patch resource with owner annotation | ||||||
when: to_be_owned.namespace is not defined or to_be_owned.namespace != owning_resource.namespace | ||||||
k8s: | ||||||
state: present | ||||||
resource_definition: | ||||||
apiVersion: "{{ to_be_owned.apiVersion }}" | ||||||
kind: "{{ to_be_owned.kind }}" | ||||||
metadata: | ||||||
name: "{{ to_be_owned.metadata.name }}" | ||||||
namespace: "{{ to_be_owned.metadata.namespace | default(omit)}}" | ||||||
annotations: | ||||||
operator-sdk/primary-resource: "{{ owning_resource.namespace }}/{{ owning_resource.name }}" | ||||||
operator-sdk/primary-resource-type: "{{ owning_resource.kind }}.{{ owning_resource.apiVersion.split('/')[0] }}" | ||||||
``` |
Uh oh!
There was an error while loading. Please reload this page.