Skip to content

Commit 781e93f

Browse files
✨ (go/v4): Add Hub and Spoke for conversion webhooks (#4254)
(go/v4): Add hub and spoke implementation for conversion webhook This commit introduces support for the conversion webhook by adding a hub and spoke implementation.
1 parent cbc6e38 commit 781e93f

File tree

39 files changed

+890
-240
lines changed

39 files changed

+890
-240
lines changed

docs/book/src/multiversion-tutorial/conversion.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,16 @@
11
# Implementing conversion
22

33
With our model for conversion in place, it's time to actually implement
4-
the conversion functions. We'll put them in a file called
5-
`cronjob_conversion.go` next to our `cronjob_types.go` file, to avoid
4+
the conversion functions. We'll create a conversion webhook
5+
for our CronJob API version `v1` (Hub) to Spoke our CronJob API version
6+
`v2` see:
7+
8+
```go
9+
kubebuilder create webhook --group batch --version v1 --kind CronJob --conversion --spoke v2
10+
```
11+
12+
The above command will generate the `cronjob_conversion.go` next to our
13+
`cronjob_types.go` file, to avoid
614
cluttering up our main types file with extra functions.
715

816
## Hub...

docs/book/src/multiversion-tutorial/testdata/project/PROJECT

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ resources:
1818
path: tutorial.kubebuilder.io/project/api/v1
1919
version: v1
2020
webhooks:
21+
conversion: true
2122
defaulting: true
23+
spoke:
24+
- v2
2225
validation: true
2326
webhookVersion: v1
2427
- api:
@@ -30,7 +33,6 @@ resources:
3033
path: tutorial.kubebuilder.io/project/api/v2
3134
version: v2
3235
webhooks:
33-
conversion: true
3436
defaulting: true
3537
validation: true
3638
webhookVersion: v1

docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_conversion.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/*
2+
Copyright 2024 The Kubernetes authors.
3+
24
Licensed under the Apache License, Version 2.0 (the "License");
35
you may not use this file except in compliance with the License.
46
You may obtain a copy of the License at

docs/book/src/multiversion-tutorial/testdata/project/api/v1/cronjob_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,8 @@ type CronJobStatus struct {
127127
*/
128128

129129
// +kubebuilder:object:root=true
130+
// +kubebuilder:storageversion
131+
// +kubebuilder:conversion:hub
130132
// +kubebuilder:subresource:status
131133
// +versionName=v1
132134
// +kubebuilder:storageversion

docs/book/src/multiversion-tutorial/testdata/project/api/v2/cronjob_conversion.go

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
/*
2+
Copyright 2024 The Kubernetes authors.
3+
24
Licensed under the Apache License, Version 2.0 (the "License");
35
you may not use this file except in compliance with the License.
46
You may obtain a copy of the License at
@@ -21,16 +23,17 @@ For imports, we'll need the controller-runtime
2123
package, plus the API version for our hub type (v1), and finally some of the
2224
standard packages.
2325
*/
26+
2427
import (
2528
"fmt"
2629
"strings"
2730

28-
"sigs.k8s.io/controller-runtime/pkg/conversion"
31+
"log"
2932

30-
v1 "tutorial.kubebuilder.io/project/api/v1"
31-
)
33+
"sigs.k8s.io/controller-runtime/pkg/conversion"
3234

33-
// +kubebuilder:docs-gen:collapse=Imports
35+
batchv1 "tutorial.kubebuilder.io/project/api/v1"
36+
) // +kubebuilder:docs-gen:collapse=Imports
3437

3538
/*
3639
Our "spoke" versions need to implement the
@@ -43,9 +46,12 @@ methods to convert to/from the hub version.
4346
ConvertTo is expected to modify its argument to contain the converted object.
4447
Most of the conversion is straightforward copying, except for converting our changed field.
4548
*/
46-
// ConvertTo converts this CronJob to the Hub version (v1).
49+
50+
// ConvertTo converts this CronJob (v2) to the Hub version (v1).
4751
func (src *CronJob) ConvertTo(dstRaw conversion.Hub) error {
48-
dst := dstRaw.(*v1.CronJob)
52+
dst := dstRaw.(*batchv1.CronJob)
53+
log.Printf("ConvertTo: Converting CronJob from Spoke version v2 to Hub version v1;"+
54+
"source: %s/%s, target: %s/%s", src.Namespace, src.Name, dst.Namespace, dst.Name)
4955

5056
sched := src.Spec.Schedule
5157
scheduleParts := []string{"*", "*", "*", "*", "*"}
@@ -74,7 +80,7 @@ func (src *CronJob) ConvertTo(dstRaw conversion.Hub) error {
7480

7581
// Spec
7682
dst.Spec.StartingDeadlineSeconds = src.Spec.StartingDeadlineSeconds
77-
dst.Spec.ConcurrencyPolicy = v1.ConcurrencyPolicy(src.Spec.ConcurrencyPolicy)
83+
dst.Spec.ConcurrencyPolicy = batchv1.ConcurrencyPolicy(src.Spec.ConcurrencyPolicy)
7884
dst.Spec.Suspend = src.Spec.Suspend
7985
dst.Spec.JobTemplate = src.Spec.JobTemplate
8086
dst.Spec.SuccessfulJobsHistoryLimit = src.Spec.SuccessfulJobsHistoryLimit
@@ -93,9 +99,11 @@ ConvertFrom is expected to modify its receiver to contain the converted object.
9399
Most of the conversion is straightforward copying, except for converting our changed field.
94100
*/
95101

96-
// ConvertFrom converts from the Hub version (v1) to this version.
102+
// ConvertFrom converts the Hub version (v1) to this CronJob (v2).
97103
func (dst *CronJob) ConvertFrom(srcRaw conversion.Hub) error {
98-
src := srcRaw.(*v1.CronJob)
104+
src := srcRaw.(*batchv1.CronJob)
105+
log.Printf("ConvertFrom: Converting CronJob from Hub version v1 to Spoke version v2;"+
106+
"source: %s/%s, target: %s/%s", src.Namespace, src.Name, dst.Namespace, dst.Name)
99107

100108
schedParts := strings.Split(src.Spec.Schedule, " ")
101109
if len(schedParts) != 5 {

docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ types implement the
4949
[Hub](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/conversion?tab=doc#Hub) and
5050
[Convertible](https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/conversion?tab=doc#Convertible)
5151
interfaces, a conversion webhook will be registered.
52+
5253
*/
5354

5455
// SetupCronJobWebhookWithManager registers the webhook for CronJob in the manager.

docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v1/cronjob_webhook_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,4 +164,14 @@ var _ = Describe("CronJob Webhook", func() {
164164
})
165165
})
166166

167+
Context("When creating CronJob under Conversion Webhook", func() {
168+
// TODO (user): Add logic to convert the object to the desired version and verify the conversion
169+
// Example:
170+
// It("Should convert the object correctly", func() {
171+
// convertedObj := &batchv1.CronJob{}
172+
// Expect(obj.ConvertTo(convertedObj)).To(Succeed())
173+
// Expect(convertedObj).ToNot(BeNil())
174+
// })
175+
})
176+
167177
})

docs/book/src/multiversion-tutorial/testdata/project/internal/webhook/v2/cronjob_webhook_test.go

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,4 @@ var _ = Describe("CronJob Webhook", func() {
8484
// })
8585
})
8686

87-
Context("When creating CronJob under Conversion Webhook", func() {
88-
// TODO (user): Add logic to convert the object to the desired version and verify the conversion
89-
// Example:
90-
// It("Should convert the object correctly", func() {
91-
// convertedObj := &batchv2.CronJob{}
92-
// Expect(obj.ConvertTo(convertedObj)).To(Succeed())
93-
// Expect(convertedObj).ToNot(BeNil())
94-
// })
95-
})
96-
9787
})

docs/book/src/multiversion-tutorial/webhooks.md

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,6 @@
33
Our conversion is in place, so all that's left is to tell
44
controller-runtime about our conversion.
55

6-
Normally, we'd run
7-
8-
```shell
9-
kubebuilder create webhook --group batch --version v1 --kind CronJob --conversion
10-
```
11-
12-
to scaffold out the webhook setup. However, we've already got webhook
13-
setup, from when we built our defaulting and validating webhooks!
14-
156
## Webhook setup...
167

178
{{#literatego ./testdata/project/internal/webhook/v1/cronjob_webhook.go}}

docs/book/src/reference/project-config.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ Now let's check its layout fields definition:
150150
| `resources.core` | It is `true` when the group used is from Kubernetes API and the API resource is not defined on the project. |
151151
| `resources.external` | It is `true` when the flag `--external-api-path` was used to generated the scaffold for an [External Type][external-type]. |
152152
| `resources.webhooks` | Store the webhooks data when the sub-command `create webhook` is used. |
153+
| `resources.webhooks.spoke` | Store the API version that will act as the Spoke with the designated Hub version for conversion webhooks. |
153154
| `resources.webhooks.webhookVersion` | The Kubernetes API version (`apiVersion`) used to scaffold the webhook resource. |
154155
| `resources.webhooks.conversion` | It is `true` when the webhook was scaffold with the `--conversion` flag which means that is a conversion webhook. |
155156
| `resources.webhooks.defaulting` | It is `true` when the webhook was scaffold with the `--defaulting` flag which means that is a defaulting webhook. |

0 commit comments

Comments
 (0)