Skip to content

Commit 775aad2

Browse files
committed
docs: Improvements to consistency and functionality of example code
- Consistently refer to cluster as mailgunCluster - Add that you need to import the cluster-api package to your project before you can use the util function - Use mailgunCluster.ObjectMeta instead of a pointer in GetOwnerCluster call - Add explanation that we need to wait for the Cluster API controller to set the ownerref before we can use the cluster object, update code to do that - Show entire Reconcile function again after adding many lines to it Signed-off-by: cprivitere <[email protected]>
1 parent 9f95a40 commit 775aad2

File tree

1 file changed

+57
-19
lines changed

1 file changed

+57
-19
lines changed

docs/book/src/developer/providers/getting-started/controllers-and-reconciliation.md

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,8 @@ By returning an error, you request that our controller will get `Reconcile()` ca
116116
That may not always be what you want - what if the object's been deleted? So let's check that:
117117

118118
```go
119-
var cluster infrav1.MailgunCluster
120-
if err := r.Get(ctx, req.NamespacedName, &cluster); err != nil {
119+
var mailgunCluster infrav1.MailgunCluster
120+
if err := r.Get(ctx, req.NamespacedName, &mailgunCluster); err != nil {
121121
// import apierrors "k8s.io/apimachinery/pkg/api/errors"
122122
if apierrors.IsNotFound(err) {
123123
return ctrl.Result{}, nil
@@ -126,19 +126,57 @@ That may not always be what you want - what if the object's been deleted? So let
126126
}
127127
```
128128

129-
Now, if this were any old `kubebuilder` project you'd be done, but in our case you have one more object to retrieve.
130-
Cluster API splits a cluster into two objects: the [`Cluster` defined by Cluster API itself][cluster].
131-
We'll want to retrieve that as well.
132-
Luckily, cluster API [provides a helper for us][getowner].
129+
Now, if this were any old `kubebuilder` project you'd be done, but in our case you have one more object to retrieve. While we defined our own cluster object (`MailGunCluster`) that represents all the infrastructure provider specific details for our cluster, we also need to retrieve the upstream [`Cluster` object that is defined by Cluster API itself][cluster]. Luckily, cluster API [provides a helper for us][getowner].
130+
131+
First, you'll need to import the cluster-api package into our project if you haven't done so yet:
132+
133+
```bash
134+
# In your Mailgun repository's root directory
135+
go get sigs.k8s.io/cluster-api
136+
go mod tidy
137+
```
138+
139+
Now we can add in a call to the `GetOwnerCluster` function to retrieve the cluster object:
133140

134141
```go
135-
cluster, err := util.GetOwnerCluster(ctx, r.Client, &mg)
142+
// import sigs.k8s.io/cluster-api/util
143+
cluster, err := util.GetOwnerCluster(ctx, r.Client, mailgunCluster.ObjectMeta)
136144
if err != nil {
137145
return ctrl.Result{}, err
138-
139146
}
140147
```
141148

149+
If our cluster was just created, the Cluster API controller may not have set the ownership reference on our object yet, so we'll have to return here and wait to do more with our cluster object until then. We can leave a log message noting that we're waiting for the main Cluster API controller to set the ownership reference. Here's what our `Reconcile()` function looks like now:
150+
151+
```go
152+
func (r *MailgunClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
153+
// You'll eventually get rid of this and use a context passed in from your main.go
154+
ctx := context.Background()
155+
156+
// We change the _ to `log` since we're going to log something now
157+
log = ctrl.LoggerFrom(ctx)
158+
159+
var mailgunCluster infrav1.MailgunCluster
160+
if err := r.Get(ctx, req.NamespacedName, &mailgunCluster); err != nil {
161+
// import apierrors "k8s.io/apimachinery/pkg/api/errors"
162+
if apierrors.IsNotFound(err) {
163+
return ctrl.Result{}, nil
164+
}
165+
return ctrl.Result{}, err
166+
}
167+
168+
// import sigs.k8s.io/cluster-api/util
169+
cluster, err := util.GetOwnerCluster(ctx, r.Client, mailgunCluster.ObjectMeta)
170+
if err != nil {
171+
return ctrl.Result{}, err
172+
}
173+
174+
if cluster == nil {
175+
log.Info("Waiting for Cluster Controller to set OwnerRef on MailGunCluster")
176+
return ctrl.Result{}, nil
177+
}
178+
```
179+
142180
### The fun part
143181
144182
_More Documentation: [The Kubebuilder Book][book] has some excellent documentation on many things, including [how to write good controllers!][implement]_
@@ -151,10 +189,10 @@ This is where your provider really comes into its own.
151189
In our case, let's try sending some mail:
152190
153191
```go
154-
subject := fmt.Sprintf("[%s] New Cluster %s requested", mgCluster.Spec.Priority, cluster.Name)
155-
body := fmt.Sprint("Hello! One cluster please.\n\n%s\n", mgCluster.Spec.Request)
192+
subject := fmt.Sprintf("[%s] New Cluster %s requested", mailgunCluster.Spec.Priority, cluster.Name)
193+
body := fmt.Sprintf("Hello! One cluster please.\n\n%s\n", mailgunCluster.Spec.Request)
156194

157-
msg := mailgun.NewMessage(mgCluster.Spec.Requester, subject, body, r.Recipient)
195+
msg := r.mailgun.NewMessage(mailgunCluster.Spec.Requester, subject, body, r.Recipient)
158196
_, _, err = r.Mailgun.Send(msg)
159197
if err != nil {
160198
return ctrl.Result{}, err
@@ -171,28 +209,28 @@ This is an important thing about controllers: they need to be idempotent. This m
171209
So in our case, we'll store the result of sending a message, and then check to see if we've sent one before.
172210
173211
```go
174-
if mgCluster.Status.MessageID != nil {
212+
if mailgunCluster.Status.MessageID != nil {
175213
// We already sent a message, so skip reconciliation
176214
return ctrl.Result{}, nil
177215
}
178216

179-
subject := fmt.Sprintf("[%s] New Cluster %s requested", mgCluster.Spec.Priority, cluster.Name)
180-
body := fmt.Sprintf("Hello! One cluster please.\n\n%s\n", mgCluster.Spec.Request)
217+
subject := fmt.Sprintf("[%s] New Cluster %s requested", mailgunCluster.Spec.Priority, cluster.Name)
218+
body := fmt.Sprintf("Hello! One cluster please.\n\n%s\n", mailgunCluster.Spec.Request)
181219

182-
msg := mailgun.NewMessage(mgCluster.Spec.Requester, subject, body, r.Recipient)
220+
msg := r.Mailgun.NewMessage(mailgunCluster.Spec.Requester, subject, body, r.Recipient)
183221
_, msgID, err := r.Mailgun.Send(msg)
184222
if err != nil {
185223
return ctrl.Result{}, err
186224
}
187225

188226
// patch from sigs.k8s.io/cluster-api/util/patch
189-
helper, err := patch.NewHelper(&mgCluster, r.Client)
227+
helper, err := patch.NewHelper(&mailgunCluster, r.Client)
190228
if err != nil {
191229
return ctrl.Result{}, err
192230
}
193-
mgCluster.Status.MessageID = &msgID
194-
if err := helper.Patch(ctx, &mgCluster); err != nil {
195-
return ctrl.Result{}, errors.Wrapf(err, "couldn't patch cluster %q", mgCluster.Name)
231+
mailgunCluster.Status.MessageID = &msgID
232+
if err := helper.Patch(ctx, &mailgunCluster); err != nil {
233+
return ctrl.Result{}, errors.Wrapf(err, "couldn't patch cluster %q", mailgunCluster.Name)
196234
}
197235

198236
return ctrl.Result{}, nil

0 commit comments

Comments
 (0)