Skip to content

Commit 7968c5a

Browse files
author
Eric Stroczynski
authored
(c-r v0.2.0) *: bump controller-runtime to v0.2.0, update APIs and docs (#1839)
1 parent 4d330f3 commit 7968c5a

File tree

17 files changed

+290
-138
lines changed

17 files changed

+290
-138
lines changed

CHANGELOG.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@
1616
- CSV config field `role-path` is now `role-paths` and takes a list of strings. Users can now specify multiple `Role` and `ClusterRole` manifests using `role-paths`. ([#1704](https://github.com/operator-framework/operator-sdk/pull/1704))
1717
- Upgrade Kubernetes version from `kubernetes-1.13.4` to `kubernetes-1.14.1`
1818
- Upgrade `github.com/operator-framework/operator-lifecycle-manager` version from `b8a4faf68e36feb6d99a6aec623b405e587b17b1` to `0.10.1`
19-
- Upgrade [`controller-runtime`](https://github.com/kubernetes-sigs/controller-runtime) version from `v0.1.12` to `v0.2.0-beta.3`
19+
- Upgrade [`controller-runtime`](https://github.com/kubernetes-sigs/controller-runtime) version from `v0.1.12` to `v0.2.0`
2020
- The package `sigs.k8s.io/controller-runtime/pkg/runtime/scheme` is deprecated, and contains no code. Replace this import with `sigs.k8s.io/controller-runtime/pkg/scheme` where relevant.
2121
- The package `sigs.k8s.io/controller-runtime/pkg/runtime/log` is deprecated. Replace this import with `sigs.k8s.io/controller-runtime/pkg/log` where relevant.
2222
- The package `sigs.k8s.io/controller-runtime/pkg/runtime/signals` is deprecated. Replace this import with `sigs.k8s.io/controller-runtime/pkg/manager/signals` where relevant.
23-
- [`sigs.k8s.io/controller-runtime/pkg/client.Client`](https://github.com/kubernetes-sigs/controller-runtime/blob/aaddbd9d9a89d8ff329a084aece23be0406e6467/pkg/client/interfaces.go#L101)'s `List()` method signature has been updated: `List(ctx context.Context, opts *client.ListOptions, list runtime.Object) error` is now [`List(ctx context.Context, list runtime.Object, opts ...client.ListOptionFunc) error`](https://github.com/kubernetes-sigs/controller-runtime/blob/aaddbd9d9a89d8ff329a084aece23be0406e6467/pkg/client/interfaces.go#L61). To migrate:
23+
- All methods on [`sigs.k8s.io/controller-runtime/pkg/client.Client`](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.2.0/pkg/client/interfaces.go#L104) (except for `Get()`) have been updated. Instead of each using a `struct`-typed or variadic functional option parameter, or having no option parameter, each now uses a variadic interface option parameter typed for each method. See `List()` below for an example.
24+
- [`sigs.k8s.io/controller-runtime/pkg/client.Client`](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.2.0/pkg/client/interfaces.go#L104)'s `List()` method signature has been updated: `List(ctx context.Context, opts *client.ListOptions, list runtime.Object) error` is now [`List(ctx context.Context, list runtime.Object, opts ...client.ListOption) error`](https://github.com/kubernetes-sigs/controller-runtime/blob/v0.2.0/pkg/client/interfaces.go#L61). To migrate:
2425
```go
2526
import (
2627
"context"
@@ -30,12 +31,17 @@
3031

3132
...
3233

33-
listOpts := &client.ListOptions{}
3434
// Old
35+
listOpts := &client.ListOptions{}
36+
listOpts.InNamespace("namespace")
3537
err = r.client.List(context.TODO(), listOps, podList)
3638
// New
37-
err = r.client.List(context.TODO(), podList, client.UseListOptions(listOps))
39+
listOpts := []client.ListOption{
40+
client.InNamespace("namespace"),
41+
}
42+
err = r.client.List(context.TODO(), podList, listOpts...)
3843
```
44+
- [`pkg/test.FrameworkClient`](https://github.com/operator-framework/operator-sdk/blob/master/pkg/test/client.go#L33) methods `List()` and `Delete()` have new signatures corresponding to the homonymous methods of `sigs.k8s.io/controller-runtime/pkg/client.Client`.
3945
- CRD file names were previously of the form `<group>_<version>_<kind>_crd.yaml`. Now that CRD manifest `spec.version` is deprecated in favor of `spec.versions`, i.e. multiple versions can be specified in one CRD, CRD file names have the form `<full group>_<resource>_crd.yaml`. `<full group>` is the full group name of your CRD while `<group>` is the last subdomain of `<full group>`, ex. `foo.bar.com` vs `foo`. `<resource>` is the plural lower-case CRD Kind found at `spec.names.plural`.
4046

4147
### Deprecated

doc/user/client.md

Lines changed: 139 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -134,32 +134,10 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
134134
```Go
135135
// List retrieves a list of objects for a given namespace and list options
136136
// and stores the list in obj.
137-
func (c Client) List(ctx context.Context, list runtime.Object, opts ...client.ListOptionFunc) error
137+
func (c Client) List(ctx context.Context, list runtime.Object, opts ...client.ListOption) error
138138
```
139139

140-
A `client.ListOptionFunc` can be created either by using the provided [functional options](https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#ListOptionFunc) or using `client.ListOptions`:
141-
142-
```Go
143-
type ListOptions struct {
144-
// LabelSelector filters results by label. Use SetLabelSelector to
145-
// set from raw string form.
146-
LabelSelector labels.Selector
147-
148-
// FieldSelector filters results by a particular field. In order
149-
// to use this with cache-based implementations, restrict usage to
150-
// a single field-value pair that's been added to the indexers.
151-
FieldSelector fields.Selector
152-
153-
// Namespace represents the namespace to list for, or empty for
154-
// non-namespaced objects, or to list across all namespaces.
155-
Namespace string
156-
157-
// Raw represents raw ListOptions, as passed to the API server. Note
158-
// that these may not be respected by all implementations of interface,
159-
// and the LabelSelector and FieldSelector fields are ignored.
160-
Raw *metav1.ListOptions
161-
}
162-
```
140+
A `client.ListOption` is an interface that sets [`client.ListOptions`][list-options] fields. A `client.ListOption` is created by using one of the provided implementations: [`MatchingLabels`][matching-labels], [`MatchingFields`][matching-fields], [`InNamespace`][in-namespace].
163141

164142
Example:
165143

@@ -176,26 +154,37 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
176154
...
177155

178156
// Return all pods in the request namespace with a label of `app=<name>`
179-
opts := &client.ListOptions{}
180-
opts.SetLabelSelector(fmt.Sprintf("app=%s", request.NamespacedName.Name))
181-
opts.InNamespace(request.NamespacedName.Namespace)
182-
157+
// and phase `Running`.
183158
podList := &v1.PodList{}
159+
opts := []client.ListOption{
160+
client.InNamespace(request.NamespacedName.Namespace),
161+
client.MatchingLabels{"app", request.NamespacedName.Name},
162+
client.MatchingFields{"status.phase": "Running"},
163+
}
184164
ctx := context.TODO()
185-
err := r.client.List(ctx, podList, client.UseListOptions(listOps))
165+
err := r.client.List(ctx, podList, opts...)
186166

187167
...
188168
}
189169
```
190170

171+
[list-options]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#ListOptions
172+
[matching-labels]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#MatchingLabels
173+
[matching-fields]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#MatchingFields
174+
[in-namespace]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#InNamespace
175+
191176
#### Create
192177

193178
```Go
194179
// Create saves the object obj in the Kubernetes cluster.
195180
// Returns an error
196-
func (c Client) Create(ctx context.Context, obj runtime.Object) error
181+
func (c Client) Create(ctx context.Context, obj runtime.Object, opts ...client.CreateOption) error
197182
```
183+
184+
A `client.CreateOption` is an interface that sets [`client.CreateOptions`][create-options] fields. A `client.CreateOption` is created by using one of the provided implementations: [`DryRunAll`][dry-run-all], [`ForceOwnership`][force-ownership]. Generally these options are not needed.
185+
198186
Example:
187+
199188
```Go
200189
import (
201190
"context"
@@ -216,16 +205,22 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
216205
}
217206
```
218207

208+
[create-options]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#CreateOptions
209+
219210
#### Update
220211

221212
```Go
222213
// Update updates the given obj in the Kubernetes cluster. obj must be a
223214
// struct pointer so that obj can be updated with the content returned
224215
// by the API server. Update does *not* update the resource's status
225216
// subresource
226-
func (c Client) Update(ctx context.Context, obj runtime.Object) error
217+
func (c Client) Update(ctx context.Context, obj runtime.Object, opts ...client.UpdateOption) error
227218
```
219+
220+
A `client.UpdateOption` is an interface that sets [`client.UpdateOptions`][update-options] fields. A `client.UpdateOption` is created by using one of the provided implementations: [`DryRunAll`][dry-run-all], [`ForceOwnership`][force-ownership]. Generally these options are not needed.
221+
228222
Example:
223+
229224
```Go
230225
import (
231226
"context"
@@ -249,10 +244,55 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
249244
}
250245
```
251246

247+
[update-options]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#UpdateOptions
248+
249+
#### Patch
250+
251+
```Go
252+
// Patch patches the given obj in the Kubernetes cluster. obj must be a
253+
// struct pointer so that obj can be updated with the content returned by the Server.
254+
func (c Client) Patch(ctx context.Context, obj runtime.Object, patch client.Patch, opts ...client.UpdateOption) error
255+
```
256+
257+
A `client.PatchOption` is an interface that sets [`client.PatchOptions`][patch-options] fields. A `client.PatchOption` is created by using one of the provided implementations: [`DryRunAll`][dry-run-all], [`ForceOwnership`][force-ownership]. Generally these options are not needed.
258+
259+
Example:
260+
261+
```Go
262+
import (
263+
"context"
264+
"k8s.io/api/apps/v1"
265+
"sigs.k8s.io/controller-runtime/pkg/client"
266+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
267+
)
268+
269+
func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, error) {
270+
...
271+
272+
dep := &v1.Deployment{}
273+
err := r.client.Get(context.TODO(), request.NamespacedName, dep)
274+
275+
...
276+
277+
ctx := context.TODO()
278+
dep.Spec.Selector.MatchLabels["is_running"] = "true"
279+
// A merge patch will preserve other fields modified at runtime.
280+
patch := client.MergeFrom(dep)
281+
err := r.client.Patch(ctx, dep, patch)
282+
283+
...
284+
}
285+
```
286+
287+
[patch-options]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#PatchOption
288+
[dry-run-all]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#DryRunAll
289+
[force-ownership]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#ForceOwnership
290+
252291
##### Updating Status Subresource
253292

254-
When updating the [status subresource][cr-status-subresource] from the client,
255-
the StatusWriter must be used which can be gotten with `Status()`
293+
When updating the [status subresource][cr-status-subresource] from the client, the [`StatusWriter`][status-writer] must be used. The status subresource is retrieved with `Status()` and updated with `Update()` or patched with `Patch()`.
294+
295+
`Update()` takes variadic `client.UpdateOption`'s, and `Patch()` takes variadic `client.PatchOption`'s. See [`Client.Update()`](#update) and [`Client.Patch()`](#patch) for more details. Generally these options are not needed.
256296

257297
##### Status
258298

@@ -273,57 +313,39 @@ import (
273313
func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, error) {
274314
...
275315

316+
ctx := context.TODO()
276317
mem := &cachev1alpha1.Memcached{}
277-
err := r.client.Get(context.TODO(), request.NamespacedName, mem)
318+
err := r.client.Get(ctx, request.NamespacedName, mem)
278319

279320
...
280321

281-
ctx := context.TODO()
322+
// Update
282323
mem.Status.Nodes = []string{"pod1", "pod2"}
283324
err := r.client.Status().Update(ctx, mem)
284325

285326
...
327+
328+
// Patch
329+
patch := client.MergeFrom(mem)
330+
err := r.client.Status().Patch(ctx, mem, patch)
331+
332+
...
286333
}
287334
```
288335

336+
[status-writer]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#StatusWriter
289337

290338
#### Delete
291339

292340
```Go
293341
// Delete deletes the given obj from Kubernetes cluster.
294-
func (c Client) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error
295-
```
296-
A `client.DeleteOptionFunc` sets fields of `client.DeleteOptions` to configure a `Delete` call:
297-
```Go
298-
// DeleteOptionFunc is a function that mutates a DeleteOptions struct.
299-
type DeleteOptionFunc func(*DeleteOptions)
300-
301-
type DeleteOptions struct {
302-
// GracePeriodSeconds is the duration in seconds before the object should be
303-
// deleted. Value must be non-negative integer. The value zero indicates
304-
// delete immediately. If this value is nil, the default grace period for the
305-
// specified type will be used.
306-
GracePeriodSeconds *int64
307-
308-
// Preconditions must be fulfilled before a deletion is carried out. If not
309-
// possible, a 409 Conflict status will be returned.
310-
Preconditions *metav1.Preconditions
311-
312-
// PropagationPolicy determined whether and how garbage collection will be
313-
// performed. Either this field or OrphanDependents may be set, but not both.
314-
// The default policy is decided by the existing finalizer set in the
315-
// metadata.finalizers and the resource-specific default policy.
316-
// Acceptable values are: 'Orphan' - orphan the dependents; 'Background' -
317-
// allow the garbage collector to delete the dependents in the background;
318-
// 'Foreground' - a cascading policy that deletes all dependents in the
319-
// foreground.
320-
PropagationPolicy *metav1.DeletionPropagation
321-
322-
// Raw represents raw DeleteOptions, as passed to the API server.
323-
Raw *metav1.DeleteOptions
324-
}
342+
func (c Client) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOption) error
325343
```
344+
345+
A `client.DeleteOption` is an interface that sets [`client.DeleteOptions`][delete-opts] fields. A `client.DeleteOption` is created by using one of the provided implementations: [`GracePeriodSeconds`][grace-period-seconds], [`Preconditions`][preconditions], [`PropagationPolicy`][propagation-policy].
346+
326347
Example:
348+
327349
```Go
328350
import (
329351
"context"
@@ -351,6 +373,52 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
351373
}
352374
```
353375

376+
[delete-opts]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#DeleteOptions
377+
[grace-period-seconds]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#GracePeriodSeconds
378+
[preconditions]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#Preconditions
379+
[propagation-policy]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#PropagationPolicy
380+
381+
#### DeleteAllOf
382+
383+
```Go
384+
// DeleteAllOf deletes all objects of the given type matching the given options.
385+
func (c Client) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...client.DeleteAllOfOption) error
386+
```
387+
388+
A `client.DeleteAllOfOption` is an interface that sets [`client.DeleteAllOfOptions`][deleteallof-opts] fields. A `client.DeleteAllOfOption` wraps a [`client.ListOption`](#list) and [`client.DeleteOption`](#delete).
389+
390+
Example:
391+
392+
```Go
393+
import (
394+
"context"
395+
"fmt"
396+
"k8s.io/api/core/v1"
397+
"sigs.k8s.io/controller-runtime/pkg/client"
398+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
399+
)
400+
401+
func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, error) {
402+
...
403+
404+
// Delete all pods in the request namespace with a label of `app=<name>`
405+
// and phase `Failed`.
406+
pod := &v1.Pod{}
407+
opts := []client.DeleteAllOfOption{
408+
client.InNamespace(request.NamespacedName.Namespace),
409+
client.MatchingLabels{"app", request.NamespacedName.Name},
410+
client.MatchingFields{"status.phase": "Failed"},
411+
client.GracePeriodSeconds(5),
412+
}
413+
ctx := context.TODO()
414+
err := r.client.DeleteAllOf(ctx, pod, opts...)
415+
416+
...
417+
}
418+
```
419+
420+
[deleteallof-opts]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#DeleteAllOfOptions
421+
354422
### Example usage
355423

356424
```Go
@@ -418,9 +486,11 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
418486
// Update the App status with the pod names.
419487
// List the pods for this app's deployment.
420488
podList := &corev1.PodList{}
421-
labelSelector := labels.SelectorFromSet(labelsForApp(app.Name))
422-
listOps := &client.ListOptions{Namespace: app.Namespace, LabelSelector: labelSelector}
423-
if err = r.client.List(context.TODO(), podList, client.UseListOptions(listOps)); err != nil {
489+
listOpts := []client.ListOption{
490+
client.InNamespace(app.Namespace),
491+
client.MatchingLabels(labelsForApp(app.Name)),
492+
}
493+
if err = r.client.List(context.TODO(), podList, listOpts...); err != nil {
424494
return reconcile.Result{}, err
425495
}
426496

example/memcached-operator/memcached_controller.go.tmpl

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
corev1 "k8s.io/api/core/v1"
1111
"k8s.io/apimachinery/pkg/api/errors"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13-
"k8s.io/apimachinery/pkg/labels"
1413
"k8s.io/apimachinery/pkg/runtime"
1514
"k8s.io/apimachinery/pkg/types"
1615
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -142,10 +141,11 @@ func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Res
142141
// Update the Memcached status with the pod names
143142
// List the pods for this memcached's deployment
144143
podList := &corev1.PodList{}
145-
labelSelector := labels.SelectorFromSet(labelsForMemcached(memcached.Name))
146-
listOps := &client.ListOptions{Namespace: memcached.Namespace, LabelSelector: labelSelector}
147-
err = r.client.List(context.TODO(), podList, client.UseListOptions(listOps))
148-
if err != nil {
144+
listOpts := []client.ListOption{
145+
client.InNamespace(memcached.Namespace),
146+
client.MatchingLabels(labelsForMemcached(memcached.Name)),
147+
}
148+
if err = r.client.List(context.TODO(), podList, listOpts...); err != nil {
149149
reqLogger.Error(err, "Failed to list pods", "Memcached.Namespace", memcached.Namespace, "Memcached.Name", memcached.Name)
150150
return reconcile.Result{}, err
151151
}

0 commit comments

Comments
 (0)