Skip to content

Commit

Permalink
(c-r v0.2.0) *: bump controller-runtime to v0.2.0, update APIs and do…
Browse files Browse the repository at this point in the history
…cs (#1839)
  • Loading branch information
Eric Stroczynski committed Sep 3, 2019
1 parent 4d330f3 commit 7968c5a
Show file tree
Hide file tree
Showing 17 changed files with 290 additions and 138 deletions.
14 changes: 10 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
- 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))
- Upgrade Kubernetes version from `kubernetes-1.13.4` to `kubernetes-1.14.1`
- Upgrade `github.com/operator-framework/operator-lifecycle-manager` version from `b8a4faf68e36feb6d99a6aec623b405e587b17b1` to `0.10.1`
- Upgrade [`controller-runtime`](https://github.com/kubernetes-sigs/controller-runtime) version from `v0.1.12` to `v0.2.0-beta.3`
- Upgrade [`controller-runtime`](https://github.com/kubernetes-sigs/controller-runtime) version from `v0.1.12` to `v0.2.0`
- 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.
- 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.
- 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.
- [`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:
- 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.
- [`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:
```go
import (
"context"
Expand All @@ -30,12 +31,17 @@

...

listOpts := &client.ListOptions{}
// Old
listOpts := &client.ListOptions{}
listOpts.InNamespace("namespace")
err = r.client.List(context.TODO(), listOps, podList)
// New
err = r.client.List(context.TODO(), podList, client.UseListOptions(listOps))
listOpts := []client.ListOption{
client.InNamespace("namespace"),
}
err = r.client.List(context.TODO(), podList, listOpts...)
```
- [`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`.
- 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`.

### Deprecated
Expand Down
208 changes: 139 additions & 69 deletions doc/user/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -134,32 +134,10 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
```Go
// List retrieves a list of objects for a given namespace and list options
// and stores the list in obj.
func (c Client) List(ctx context.Context, list runtime.Object, opts ...client.ListOptionFunc) error
func (c Client) List(ctx context.Context, list runtime.Object, opts ...client.ListOption) error
```

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`:

```Go
type ListOptions struct {
// LabelSelector filters results by label. Use SetLabelSelector to
// set from raw string form.
LabelSelector labels.Selector

// FieldSelector filters results by a particular field. In order
// to use this with cache-based implementations, restrict usage to
// a single field-value pair that's been added to the indexers.
FieldSelector fields.Selector

// Namespace represents the namespace to list for, or empty for
// non-namespaced objects, or to list across all namespaces.
Namespace string

// Raw represents raw ListOptions, as passed to the API server. Note
// that these may not be respected by all implementations of interface,
// and the LabelSelector and FieldSelector fields are ignored.
Raw *metav1.ListOptions
}
```
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].

Example:

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

// Return all pods in the request namespace with a label of `app=<name>`
opts := &client.ListOptions{}
opts.SetLabelSelector(fmt.Sprintf("app=%s", request.NamespacedName.Name))
opts.InNamespace(request.NamespacedName.Namespace)

// and phase `Running`.
podList := &v1.PodList{}
opts := []client.ListOption{
client.InNamespace(request.NamespacedName.Namespace),
client.MatchingLabels{"app", request.NamespacedName.Name},
client.MatchingFields{"status.phase": "Running"},
}
ctx := context.TODO()
err := r.client.List(ctx, podList, client.UseListOptions(listOps))
err := r.client.List(ctx, podList, opts...)

...
}
```

[list-options]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#ListOptions
[matching-labels]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#MatchingLabels
[matching-fields]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#MatchingFields
[in-namespace]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#InNamespace

#### Create

```Go
// Create saves the object obj in the Kubernetes cluster.
// Returns an error
func (c Client) Create(ctx context.Context, obj runtime.Object) error
func (c Client) Create(ctx context.Context, obj runtime.Object, opts ...client.CreateOption) error
```

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.

Example:

```Go
import (
"context"
Expand All @@ -216,16 +205,22 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
}
```

[create-options]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#CreateOptions

#### Update

```Go
// Update updates the given obj in the Kubernetes cluster. obj must be a
// struct pointer so that obj can be updated with the content returned
// by the API server. Update does *not* update the resource's status
// subresource
func (c Client) Update(ctx context.Context, obj runtime.Object) error
func (c Client) Update(ctx context.Context, obj runtime.Object, opts ...client.UpdateOption) error
```

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.

Example:

```Go
import (
"context"
Expand All @@ -249,10 +244,55 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
}
```

[update-options]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#UpdateOptions

#### Patch

```Go
// Patch patches the given obj in the Kubernetes cluster. obj must be a
// struct pointer so that obj can be updated with the content returned by the Server.
func (c Client) Patch(ctx context.Context, obj runtime.Object, patch client.Patch, opts ...client.UpdateOption) error
```

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.

Example:

```Go
import (
"context"
"k8s.io/api/apps/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, error) {
...

dep := &v1.Deployment{}
err := r.client.Get(context.TODO(), request.NamespacedName, dep)

...

ctx := context.TODO()
dep.Spec.Selector.MatchLabels["is_running"] = "true"
// A merge patch will preserve other fields modified at runtime.
patch := client.MergeFrom(dep)
err := r.client.Patch(ctx, dep, patch)

...
}
```

[patch-options]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#PatchOption
[dry-run-all]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#DryRunAll
[force-ownership]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#ForceOwnership

##### Updating Status Subresource

When updating the [status subresource][cr-status-subresource] from the client,
the StatusWriter must be used which can be gotten with `Status()`
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()`.

`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.

##### Status

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

ctx := context.TODO()
mem := &cachev1alpha1.Memcached{}
err := r.client.Get(context.TODO(), request.NamespacedName, mem)
err := r.client.Get(ctx, request.NamespacedName, mem)

...

ctx := context.TODO()
// Update
mem.Status.Nodes = []string{"pod1", "pod2"}
err := r.client.Status().Update(ctx, mem)

...

// Patch
patch := client.MergeFrom(mem)
err := r.client.Status().Patch(ctx, mem, patch)

...
}
```

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

#### Delete

```Go
// Delete deletes the given obj from Kubernetes cluster.
func (c Client) Delete(ctx context.Context, obj runtime.Object, opts ...DeleteOptionFunc) error
```
A `client.DeleteOptionFunc` sets fields of `client.DeleteOptions` to configure a `Delete` call:
```Go
// DeleteOptionFunc is a function that mutates a DeleteOptions struct.
type DeleteOptionFunc func(*DeleteOptions)

type DeleteOptions struct {
// GracePeriodSeconds is the duration in seconds before the object should be
// deleted. Value must be non-negative integer. The value zero indicates
// delete immediately. If this value is nil, the default grace period for the
// specified type will be used.
GracePeriodSeconds *int64

// Preconditions must be fulfilled before a deletion is carried out. If not
// possible, a 409 Conflict status will be returned.
Preconditions *metav1.Preconditions

// PropagationPolicy determined whether and how garbage collection will be
// performed. Either this field or OrphanDependents may be set, but not both.
// The default policy is decided by the existing finalizer set in the
// metadata.finalizers and the resource-specific default policy.
// Acceptable values are: 'Orphan' - orphan the dependents; 'Background' -
// allow the garbage collector to delete the dependents in the background;
// 'Foreground' - a cascading policy that deletes all dependents in the
// foreground.
PropagationPolicy *metav1.DeletionPropagation

// Raw represents raw DeleteOptions, as passed to the API server.
Raw *metav1.DeleteOptions
}
func (c Client) Delete(ctx context.Context, obj runtime.Object, opts ...client.DeleteOption) error
```

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].

Example:

```Go
import (
"context"
Expand Down Expand Up @@ -351,6 +373,52 @@ func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, e
}
```

[delete-opts]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#DeleteOptions
[grace-period-seconds]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#GracePeriodSeconds
[preconditions]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#Preconditions
[propagation-policy]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#PropagationPolicy

#### DeleteAllOf

```Go
// DeleteAllOf deletes all objects of the given type matching the given options.
func (c Client) DeleteAllOf(ctx context.Context, obj runtime.Object, opts ...client.DeleteAllOfOption) error
```

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).

Example:

```Go
import (
"context"
"fmt"
"k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
)

func (r *ReconcileApp) Reconcile(request reconcile.Request) (reconcile.Result, error) {
...

// Delete all pods in the request namespace with a label of `app=<name>`
// and phase `Failed`.
pod := &v1.Pod{}
opts := []client.DeleteAllOfOption{
client.InNamespace(request.NamespacedName.Namespace),
client.MatchingLabels{"app", request.NamespacedName.Name},
client.MatchingFields{"status.phase": "Failed"},
client.GracePeriodSeconds(5),
}
ctx := context.TODO()
err := r.client.DeleteAllOf(ctx, pod, opts...)

...
}
```

[deleteallof-opts]:https://godoc.org/sigs.k8s.io/controller-runtime/pkg/client#DeleteAllOfOptions

### Example usage

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

Expand Down
10 changes: 5 additions & 5 deletions example/memcached-operator/memcached_controller.go.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -142,10 +141,11 @@ func (r *ReconcileMemcached) Reconcile(request reconcile.Request) (reconcile.Res
// Update the Memcached status with the pod names
// List the pods for this memcached's deployment
podList := &corev1.PodList{}
labelSelector := labels.SelectorFromSet(labelsForMemcached(memcached.Name))
listOps := &client.ListOptions{Namespace: memcached.Namespace, LabelSelector: labelSelector}
err = r.client.List(context.TODO(), podList, client.UseListOptions(listOps))
if err != nil {
listOpts := []client.ListOption{
client.InNamespace(memcached.Namespace),
client.MatchingLabels(labelsForMemcached(memcached.Name)),
}
if err = r.client.List(context.TODO(), podList, listOpts...); err != nil {
reqLogger.Error(err, "Failed to list pods", "Memcached.Namespace", memcached.Namespace, "Memcached.Name", memcached.Name)
return reconcile.Result{}, err
}
Expand Down
Loading

0 comments on commit 7968c5a

Please sign in to comment.