Skip to content

Commit 4751b95

Browse files
authored
doc: Update existing resources with owner refs (#2013)
* doc: Update existing resources with owner refs Operator deployed resources created while dependent watches are disabled cannot have owner information retroactively injected by the proxy. This patch documents the process of adding that information to existing resources manually. Fixes #1977
1 parent 888dde5 commit 4751b95

File tree

2 files changed

+199
-0
lines changed

2 files changed

+199
-0
lines changed

doc/ansible/dev/advanced_options.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,12 @@ The ansible runner will keep information about the ansible run in the container.
4646
You may want to manage what your operator watches and the owner references. This means that your operator will need to understand how to clean up after itself when your CR is deleted. To disable these features you will need to edit your `build/Dockerfile` to include the line below.
4747

4848
**NOTE**: That if you use this feature there will be a warning that dependent watches is turned off but there will be no error.
49+
**WARNING**: Once a CR is deployed without owner reference injection, there is no automatic way to add those references.
4950

5051
```
5152
ENTRYPOINT ["/usr/local/bin/entrypoint", "--inject-owner-ref=false"]
5253
```
54+
55+
If you have created resources without owner reference injection, it is
56+
possible to manually to update resources following [this
57+
guide.](./retroactively-owned-resources.md)
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
# Adding Owner References for Existing Resources
2+
3+
Owner references are automatically injected `only during creation of
4+
resources`. Enabling owner reference injection `will not update objects`
5+
created while [owner reference injection is
6+
disabled](./advanced_options.md#turning-off-dependent-watches-and-owner-reference-injection)
7+
8+
This guide will demonstrate how to retroactively set owner references
9+
for existing resources.
10+
11+
A GET request to the owning resource will provide the necessary data to
12+
construct an `ownerReference` or an `annotation`.
13+
14+
`$ kubectl get memcacheds.cache.example.com -o yaml`
15+
16+
**Example Response (Abbreviated):**
17+
18+
```yaml
19+
apiVersion: cache.example.com/v1alpha1
20+
kind: Memcached
21+
metadata:
22+
name: example-memcached
23+
namespace: default
24+
uid: 2a94ff2b-84e0-40ce-8b5e-2b7e4d2bc0e2
25+
```
26+
27+
`kubectl edit` can be used to update the resources by hand. See below
28+
for example `ownerReference` and `annotations`.
29+
30+
## For objects in the same namespace as the Owner (CRD)
31+
32+
Dependent resources `within the same namespace as the owning CR` are
33+
tracked with the `ownerReference` field.
34+
35+
`ownerReference` structure:
36+
* apiVersion: {group}/{version}
37+
* kind: {kind}
38+
* name: {metadata.name}
39+
* uid: {metadata.uid}
40+
41+
**Example ownerReference:**
42+
43+
```yaml
44+
metadata:
45+
...(snip)
46+
ownerReferences:
47+
- apiVersion: cache.example.com/v1alpha1
48+
kind: Memcached
49+
name: example-memcached
50+
uid: ad834522-d9a5-4841-beac-991ff3798c00
51+
```
52+
53+
## For objects which are NOT in the same namespace as the Owner (CRD)
54+
55+
An `annotation` is used instead of an `ownerReference` if the dependent
56+
resource is in a different namespace than the CR, or the dependent
57+
resource is a cluster level resource.
58+
59+
`annotation` structure:
60+
* operator-sdk/primary-resource: {metadata.namespace}/{metadata.name}
61+
* operator-sdk/primary-resource-type: {kind}.{group}
62+
63+
**NOTE**: The {group} can be found by splitting the `apiVersion`
64+
metadata of the CR, into `group` and `version`. As an example,
65+
[this apiVersion field](https://github.com/operator-framework/operator-sdk-samples/blob/master/ansible/memcached-operator/deploy/crds/cache_v1alpha1_memcached_cr.yaml#L1)
66+
gives us the group `cache.example.com`.
67+
68+
**Example Annotation:**
69+
70+
```yaml
71+
metadata:
72+
...(snip)
73+
annotations:
74+
operator-sdk/primary-resource: default/example-memcached
75+
operator-sdk/primary-resource-type: Memcached.cache.example.com
76+
```
77+
78+
## Migration using Ansible assets
79+
80+
If you have many resources to update, it may be easier to use the
81+
following Ansible assets, which **should be considered an example rather
82+
than an officially supported workflow**.
83+
84+
To use these assets, create a `vars.yml` as specified below and copy
85+
`playbook.yml` and `each_resource.yml` into the same directory. Execute
86+
the playbook with:
87+
88+
``` bash
89+
$ ansible-playbook -i localhost playbook.yml
90+
```
91+
92+
### vars.yml
93+
94+
This file should be created by the user to configure the playbook, and
95+
needs to contain:
96+
97+
* owning_resource
98+
* apiVersion
99+
* kind
100+
* name
101+
* namespace
102+
* resources_to_own (list): For each resource, specify:
103+
* name
104+
* namespace (if applicable)
105+
* apiVersion
106+
* kind
107+
108+
```yaml
109+
owning_resource:
110+
apiVersion: cache.example.com/v1alpha1
111+
kind: Memcached
112+
name: example-memcached
113+
namespace: default
114+
115+
resources_to_own:
116+
- name: example-memcached-memcached
117+
namespace: default
118+
apiVersion: apps/v1
119+
kind: Deployment
120+
- name: example-memcached
121+
apiVersion: v1
122+
kind: Namespace
123+
```
124+
125+
### playbook.yml
126+
127+
This file can be used as-is without user adjustments.
128+
129+
```yaml
130+
- hosts: localhost
131+
132+
tasks:
133+
- name: Import user variables
134+
include_vars: vars.yml
135+
- name: Retrieve owning resource
136+
k8s_facts:
137+
api_version: "{{ owning_resource.apiVersion }}"
138+
kind: "{{ owning_resource.kind }}"
139+
name: "{{ owning_resource.name }}"
140+
namespace: "{{ owning_resource.namespace }}"
141+
register: extra_owner_data
142+
143+
- name: Ensure resources are owned
144+
include_tasks: each_resource.yml
145+
loop: "{{ resources_to_own }}"
146+
vars:
147+
to_be_owned: '{{ q("k8s",
148+
api_version=item.apiVersion,
149+
kind=item.kind,
150+
resource_name=item.name,
151+
namespace=item.namespace
152+
).0 }}'
153+
owner_reference:
154+
apiVersion: "{{ owning_resource.apiVersion }}"
155+
kind: "{{ owning_resource.kind }}"
156+
name: "{{ owning_resource.name }}"
157+
uid: "{{ extra_owner_data.resources[0].metadata.uid }}"
158+
```
159+
160+
### `each_resource.yml`
161+
162+
This file can be used as-is without user adjustments.
163+
164+
``` yaml
165+
- name: Patch resource with owner reference
166+
when:
167+
- to_be_owned.metadata.namespace is defined
168+
- to_be_owned.metadata.namespace == owning_resource.namespace
169+
- (to_be_owned.metadata.ownerReferences is not defined) or
170+
(owner_reference not in to_be_owned.metadata.ownerReferences)
171+
k8s:
172+
state: present
173+
resource_definition:
174+
apiVersion: "{{ to_be_owned.apiVersion }}"
175+
kind: "{{ to_be_owned.kind }}"
176+
metadata:
177+
name: "{{ to_be_owned.metadata.name }}"
178+
namespace: "{{ to_be_owned.metadata.namespace }}"
179+
ownerReferences: "{{ (to_be_owned.metadata.ownerReferences | default([])) + [owner_reference] }}"
180+
181+
- name: Patch resource with owner annotation
182+
when: to_be_owned.namespace is not defined or to_be_owned.namespace != owning_resource.namespace
183+
k8s:
184+
state: present
185+
resource_definition:
186+
apiVersion: "{{ to_be_owned.apiVersion }}"
187+
kind: "{{ to_be_owned.kind }}"
188+
metadata:
189+
name: "{{ to_be_owned.metadata.name }}"
190+
namespace: "{{ to_be_owned.metadata.namespace | default(omit)}}"
191+
annotations:
192+
operator-sdk/primary-resource: "{{ owning_resource.namespace }}/{{ owning_resource.name }}"
193+
operator-sdk/primary-resource-type: "{{ owning_resource.kind }}.{{ owning_resource.apiVersion.split('/')[0] }}"
194+
```

0 commit comments

Comments
 (0)