Skip to content

Commit 77a404e

Browse files
ksawio97smira
authored andcommitted
feat: support for strategic merge patches
This commit implements strategic merge patch by reusing talos StrategicMergePatch implementation. Additionally, it adds an integration test for strategic merge patches. This resolves issue #181. Signed-off-by: Ksawery Kuczyński <[email protected]>
1 parent 171daf4 commit 77a404e

8 files changed

+105
-3
lines changed

README.md

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,15 @@ spec:
145145
Machine configuration can be customized by applying configuration patches.
146146
Any field of the [Talos machine configuration](https://www.talos.dev/docs/latest/reference/configuration/)
147147
can be overridden on a per-machine basis using this method.
148-
The format of these patches is based on [JSON 6902](http://jsonpatch.com/) that you may be used to in tools like `kustomize`.
148+
149+
There are two [patch formats](https://www.talos.dev/latest/talos-guides/configuration/patching/) supported by CABPT:
150+
151+
- the [JSON 6902](http://jsonpatch.com/) format that you may be used to in tools like `kustomize`;
152+
- strategic merge patches which look like incomplete machine configuration documents.
153+
154+
See Talos Linux documentation for more information on patching.
155+
156+
JSON 6902 patch:
149157

150158
```yaml
151159
spec:
@@ -164,6 +172,26 @@ spec:
164172
- https://docs.projectcalico.org/v3.18/manifests/calico.yaml
165173
```
166174

175+
Strategic merge patch:
176+
177+
```yaml
178+
spec:
179+
generateType: controlplane
180+
talosVersion: v1.6
181+
strategicPatches:
182+
- |
183+
machine:
184+
install:
185+
disk: /dev/sda
186+
- |
187+
cluster:
188+
network:
189+
cni:
190+
name: custom
191+
urls:
192+
- https://docs.projectcalico.org/v3.18/manifests/calico.yaml
193+
```
194+
167195
### Retrieving `talosconfig`
168196

169197
Client-side `talosconfig` is required to access the cluster using Talos API.

api/v1alpha3/talosconfig_types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type TalosConfigSpec struct {
2020
GenerateType string `json:"generateType"` //none,init,controlplane,worker mutually exclusive w/ data
2121
Data string `json:"data,omitempty"`
2222
ConfigPatches []ConfigPatches `json:"configPatches,omitempty"`
23+
// Talos Linux machine configuration strategic merge patch list.
24+
StrategicPatches []string `json:"strategicPatches,omitempty"`
2325
// Set hostname in the machine configuration to some value.
2426
Hostname HostnameSpec `json:"hostname,omitempty"`
2527
// Important: Run "make" to regenerate code after modifying this file

api/v1alpha3/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/bootstrap.cluster.x-k8s.io_talosconfigs.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,12 @@ spec:
129129
Allowed values: "MachineName" (use linked Machine's Name).
130130
type: string
131131
type: object
132+
strategicPatches:
133+
description: Talos Linux machine configuration strategic merge patch
134+
list.
135+
items:
136+
type: string
137+
type: array
132138
talosVersion:
133139
type: string
134140
required:

config/crd/bases/bootstrap.cluster.x-k8s.io_talosconfigtemplates.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,12 @@ spec:
124124
Allowed values: "MachineName" (use linked Machine's Name).
125125
type: string
126126
type: object
127+
strategicPatches:
128+
description: Talos Linux machine configuration strategic merge
129+
patch list.
130+
items:
131+
type: string
132+
type: array
127133
talosVersion:
128134
type: string
129135
required:

controllers/talosconfig_controller.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ func (r *TalosConfigReconciler) reconcileGenerate(ctx context.Context, tcScope *
298298
return fmt.Errorf("unknown generate type specified: %q", config.Spec.GenerateType)
299299
}
300300

301-
// Handle patches to the machine config if they were specified
301+
// Handle JSON6902 patches to the machine config if they were specified
302302
// Note this will patch both pre-generated and user-provided configs.
303303
if len(config.Spec.ConfigPatches) > 0 {
304304
marshalledPatches, err := json.Marshal(config.Spec.ConfigPatches)
@@ -319,6 +319,32 @@ func (r *TalosConfigReconciler) reconcileGenerate(ctx context.Context, tcScope *
319319
retData.BootstrapData = string(patchedBytes)
320320
}
321321

322+
// Handle strategic merge patches.
323+
if len(config.Spec.StrategicPatches) > 0 {
324+
patches := make([]configpatcher.Patch, 0, len(config.Spec.StrategicPatches))
325+
326+
for _, strategicPatch := range config.Spec.StrategicPatches {
327+
patch, err := configpatcher.LoadPatch([]byte(strategicPatch))
328+
if err != nil {
329+
return fmt.Errorf("failure loading StrategicPatch: %w", err)
330+
}
331+
332+
patches = append(patches, patch)
333+
}
334+
335+
out, err := configpatcher.Apply(configpatcher.WithBytes([]byte(retData.BootstrapData)), patches)
336+
if err != nil {
337+
return fmt.Errorf("failure applying StrategicPatches: %w", err)
338+
}
339+
340+
outBytes, err := out.Bytes()
341+
if err != nil {
342+
return fmt.Errorf("failure converting result to bytes: %w", err)
343+
}
344+
345+
retData.BootstrapData = string(outBytes)
346+
}
347+
322348
// Packet acts a fool if you don't prepend #!talos to the userdata
323349
// so we try to suss out if that's the type of machine/machinePool getting created.
324350
if tcScope.ConfigOwner.IsMachinePool() {

hack/release.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ github_repo = "siderolabs/cluster-api-bootstrap-provider-talos"
66
match_deps = "^github.com/(siderolabs/[a-zA-Z0-9-]+)$"
77

88
# previous release
9-
previous = "v0.6.3"
9+
previous = "v0.6.4"
1010

1111
pre_release = false
1212

@@ -15,3 +15,8 @@ preface = """\
1515

1616
[notes]
1717

18+
[notes.patches]
19+
title = "Patches"
20+
description = """\
21+
CABPT now supports Talos Linux machine configuration strategic merge patches via 'strategicPatches' field on the `TalosConfig` CRD.
22+
"""

internal/integration/integration_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,30 @@ func TestIntegration(t *testing.T) {
217217
assert.Equal(t, []string{"myserver.com"}, provider.Machine().Security().CertSANs())
218218
})
219219

220+
t.Run("StrategicMergePatch", func(t *testing.T) {
221+
t.Parallel()
222+
223+
namespaceName := setupTest(ctx, t, c)
224+
cluster := createCluster(ctx, t, c, namespaceName, nil, true)
225+
226+
talosConfig := createTalosConfig(ctx, t, c, namespaceName, bootstrapv1alpha3.TalosConfigSpec{
227+
GenerateType: talosmachine.TypeInit.String(),
228+
TalosVersion: TalosVersion,
229+
StrategicPatches: []string{
230+
"machine:\n network:\n hostname: foo.bar",
231+
"machine:\n time:\n servers: [time.cloudflare.com]",
232+
},
233+
})
234+
235+
createMachine(ctx, t, c, cluster, talosConfig, true)
236+
waitForReady(ctx, t, c, talosConfig)
237+
238+
provider := assertMachineConfiguration(ctx, t, c, talosConfig)
239+
240+
assert.Equal(t, "foo.bar", provider.Machine().Network().Hostname())
241+
assert.Equal(t, []string{"time.cloudflare.com"}, provider.Machine().Time().Servers())
242+
})
243+
220244
t.Run("LegacyClusterSecret", func(t *testing.T) {
221245
t.Parallel()
222246

0 commit comments

Comments
 (0)