Skip to content
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

📖 Add more examples in documentation #2498

Merged
merged 2 commits into from Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
99 changes: 97 additions & 2 deletions example_test.go
Expand Up @@ -18,14 +18,21 @@ package controllerruntime_test

import (
"context"
"encoding/json"
"fmt"
"os"
"time"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"

ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/reconcile"

// since we invoke tests with -ginkgo.junit-report we need to import ginkgo.
_ "github.com/onsi/ginkgo/v2"
Expand All @@ -38,7 +45,7 @@ import (
//
// * Start the application.
func Example() {
var log = ctrl.Log.WithName("builder-examples")
log := ctrl.Log.WithName("builder-examples")

manager, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
if err != nil {
Expand All @@ -62,6 +69,94 @@ func Example() {
}
}

type ExampleCRDWithConfigMapRef struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
ConfigMapRef corev1.LocalObjectReference `json:"configMapRef"`
}

func deepCopyObject(arg any) runtime.Object {
// DO NOT use this code in production code, this is only for presentation purposes.
// in real code you should generate DeepCopy methods by using controller-gen CLI tool.
argBytes, err := json.Marshal(arg)
if err != nil {
panic(err)
}
out := &ExampleCRDWithConfigMapRefList{}
if err := json.Unmarshal(argBytes, out); err != nil {
panic(err)
}
return out
}

// DeepCopyObject implements client.Object.
func (in *ExampleCRDWithConfigMapRef) DeepCopyObject() runtime.Object {
return deepCopyObject(in)
}

type ExampleCRDWithConfigMapRefList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []ExampleCRDWithConfigMapRef `json:"items"`
}

// DeepCopyObject implements client.ObjectList.
func (in *ExampleCRDWithConfigMapRefList) DeepCopyObject() runtime.Object {
return deepCopyObject(in)
}

// This example creates a simple application Controller that is configured for ExampleCRDWithConfigMapRef CRD.
// Any change in the configMap referenced in this Custom Resource will cause the re-reconcile of the parent ExampleCRDWithConfigMapRef
// due to the implementation of the .Watches method of "sigs.k8s.io/controller-runtime/pkg/builder".Builder.
func Example_customHandler() {
log := ctrl.Log.WithName("builder-examples")

manager, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{})
if err != nil {
log.Error(err, "could not create manager")
os.Exit(1)
}

err = ctrl.
NewControllerManagedBy(manager).
For(&ExampleCRDWithConfigMapRef{}).
Watches(&corev1.ConfigMap{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, cm client.Object) []ctrl.Request {
// map a change from referenced configMap to ExampleCRDWithConfigMapRef, which causes its re-reconcile
crList := &ExampleCRDWithConfigMapRefList{}
if err := manager.GetClient().List(ctx, crList); err != nil {
manager.GetLogger().Error(err, "while listing ExampleCRDWithConfigMapRefs")
return nil
}

reqs := make([]ctrl.Request, 0, len(crList.Items))
for _, item := range crList.Items {
if item.ConfigMapRef.Name == cm.GetName() {
reqs = append(reqs, ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: item.GetNamespace(),
Name: item.GetName(),
},
})
}
}

return reqs
})).
Complete(reconcile.Func(func(ctx context.Context, r reconcile.Request) (reconcile.Result, error) {
// Your business logic to implement the API by creating, updating, deleting objects goes here.
return reconcile.Result{}, nil
}))
if err != nil {
log.Error(err, "could not create controller")
os.Exit(1)
}

if err := manager.Start(ctrl.SetupSignalHandler()); err != nil {
log.Error(err, "could not start manager")
os.Exit(1)
}
}

// This example creates a simple application Controller that is configured for ReplicaSets and Pods.
// This application controller will be running leader election with the provided configuration in the manager options.
// If leader election configuration is not provided, controller runs leader election with default values.
Expand All @@ -75,7 +170,7 @@ func Example() {
//
// * Start the application.
func Example_updateLeaderElectionDurations() {
var log = ctrl.Log.WithName("builder-examples")
log := ctrl.Log.WithName("builder-examples")
leaseDuration := 100 * time.Second
renewDeadline := 80 * time.Second
retryPeriod := 20 * time.Second
Expand Down
4 changes: 2 additions & 2 deletions pkg/builder/example_test.go
Expand Up @@ -38,7 +38,7 @@ import (
func ExampleBuilder_metadata_only() {
logf.SetLogger(zap.New())

var log = logf.Log.WithName("builder-examples")
log := logf.Log.WithName("builder-examples")

mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{})
if err != nil {
Expand Down Expand Up @@ -95,7 +95,7 @@ func ExampleBuilder_metadata_only() {
func ExampleBuilder() {
logf.SetLogger(zap.New())

var log = logf.Log.WithName("builder-examples")
log := logf.Log.WithName("builder-examples")

mgr, err := manager.New(config.GetConfigOrDie(), manager.Options{})
if err != nil {
Expand Down
19 changes: 17 additions & 2 deletions pkg/client/example_test.go
Expand Up @@ -25,11 +25,14 @@ import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/apimachinery/pkg/types"
corev1ac "k8s.io/client-go/applyconfigurations/core/v1"

"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/config"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
)

var (
Expand Down Expand Up @@ -159,7 +162,7 @@ func ExampleClient_update() {
Namespace: "namespace",
Name: "name",
}, pod)
pod.SetFinalizers(append(pod.GetFinalizers(), "new-finalizer"))
controllerutil.AddFinalizer(pod, "new-finalizer")
_ = c.Update(context.Background(), pod)

// Using a unstructured object.
Expand All @@ -173,7 +176,7 @@ func ExampleClient_update() {
Namespace: "namespace",
Name: "name",
}, u)
u.SetFinalizers(append(u.GetFinalizers(), "new-finalizer"))
controllerutil.AddFinalizer(u, "new-finalizer")
_ = c.Update(context.Background(), u)
}

Expand All @@ -188,6 +191,18 @@ func ExampleClient_patch() {
}, client.RawPatch(types.StrategicMergePatchType, patch))
}

// This example shows how to use the client with unstructured objects to create/patch objects using Server Side Apply,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please mention why the dance of converting to unstructured is needed

// "k8s.io/apimachinery/pkg/runtime".DefaultUnstructuredConverter.ToUnstructured is used to convert an object into map[string]any representation,
// which is then set as an "Object" field in *unstructured.Unstructured struct, which implements client.Object.
func ExampleClient_apply() {
// Using a typed object.
configMap := corev1ac.ConfigMap("name", "namespace").WithData(map[string]string{"key": "value"})
// c is a created client.
u := &unstructured.Unstructured{}
u.Object, _ = runtime.DefaultUnstructuredConverter.ToUnstructured(configMap)
_ = c.Patch(context.Background(), u, client.Apply, client.ForceOwnership, client.FieldOwner("field-owner"))
}

// This example shows how to use the client with typed and unstructured objects to patch objects' status.
func ExampleClient_patchStatus() {
u := &unstructured.Unstructured{}
Expand Down
6 changes: 4 additions & 2 deletions pkg/handler/example_test.go
Expand Up @@ -32,8 +32,10 @@ import (
"sigs.k8s.io/controller-runtime/pkg/source"
)

var mgr manager.Manager
var c controller.Controller
var (
mgr manager.Manager
c controller.Controller
)

// This example watches Pods and enqueues Requests with the Name and Namespace of the Pod from
// the Event (i.e. change caused by a Create, Update, Delete).
Expand Down