Skip to content

Commit b5d23a0

Browse files
authored
feat: support configuring CoreDNS image (#950)
**What problem does this PR solve?**: New API to support setting CoreDNS image repository and image tag. ``` spec: topology: variables: - name: clusterConfig value: dns: coreDNS: image: repository: my-registry.io/my-org/my-repo tag: "v1.11.3_custom.0" ``` **Which issue(s) this PR fixes**: Fixes # **How Has This Been Tested?**: <!-- Please describe the tests that you ran to verify your changes. Provide output from the tests and any manual steps needed to replicate the tests. --> 1. New unit tests. 2. Brought up a Nutanix cluster with and verified the expected image was set in the CoreDNS Deployment. ``` dns: coreDNS: image: repository: docker.io/dkoshkin tag: "v1.11.3" ``` **Special notes for your reviewer**: <!-- Use this to provide any additional information to the reviewers. This may include: - Best way to review the PR. - Where the author wants the most review attention on. - etc. -->
1 parent c6307ea commit b5d23a0

13 files changed

+554
-1
lines changed

api/v1alpha1/clusterconfig_types.go

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,8 +207,11 @@ type GenericClusterConfigSpec struct {
207207
// +kubebuilder:validation:Optional
208208
Users []User `json:"users,omitempty"`
209209

210-
// +optional
210+
// +kubebuilder:validation:Optional
211211
EncryptionAtRest *EncryptionAtRest `json:"encryptionAtRest,omitempty"`
212+
213+
// +kubebuilder:validation:Optional
214+
DNS *DNS `json:"dns,omitempty"`
212215
}
213216

214217
type Image struct {
@@ -310,6 +313,19 @@ type AESConfiguration struct{}
310313

311314
type SecretboxConfiguration struct{}
312315

316+
// DNS defines the DNS configuration for the cluster.
317+
type DNS struct {
318+
// CoreDNS defines the CoreDNS configuration for the cluster.
319+
// +kubebuilder:validation:Optional
320+
CoreDNS *CoreDNS `json:"coreDNS,omitempty"`
321+
}
322+
323+
type CoreDNS struct {
324+
// Image required for overriding Kubernetes DNS image details.
325+
// +kubebuilder:validation:Optional
326+
Image *Image `json:"image,omitempty"`
327+
}
328+
313329
//nolint:gochecknoinits // Idiomatic to use init functions to register APIs with scheme.
314330
func init() {
315331
SchemeBuilder.Register(

api/v1alpha1/constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,8 @@ const (
3333
// ImageRegistriesVariableName is the image registries patch variable name.
3434
ImageRegistriesVariableName = "imageRegistries"
3535

36+
// DNSVariableName is the DNS external patch variable name.
37+
DNSVariableName = "dns"
38+
3639
ClusterUUIDAnnotationKey = APIGroup + "/cluster-uuid"
3740
)

api/v1alpha1/crds/caren.nutanix.com_awsclusterconfigs.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,26 @@ spec:
372372
type: object
373373
type: array
374374
type: object
375+
dns:
376+
description: DNS defines the DNS configuration for the cluster.
377+
properties:
378+
coreDNS:
379+
description: CoreDNS defines the CoreDNS configuration for the cluster.
380+
properties:
381+
image:
382+
description: Image required for overriding Kubernetes DNS image details.
383+
properties:
384+
repository:
385+
description: Repository is used to override the image repository to pull from.
386+
pattern: ^((?:[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*|\[(?:[a-fA-F0-9:]+)\])(:[0-9]+)?/)?[a-z0-9]+((?:[._]|__|[-]+)[a-z0-9]+)*(/[a-z0-9]+((?:[._]|__|[-]+)[a-z0-9]+)*)*$
387+
type: string
388+
tag:
389+
description: Tag is used to override the default image tag.
390+
pattern: ^[\w][\w.-]{0,127}$
391+
type: string
392+
type: object
393+
type: object
394+
type: object
375395
encryptionAtRest:
376396
description: |-
377397
EncryptionAtRest defines the configuration to enable encryption at REST

api/v1alpha1/crds/caren.nutanix.com_dockerclusterconfigs.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,26 @@ spec:
289289
type: object
290290
type: array
291291
type: object
292+
dns:
293+
description: DNS defines the DNS configuration for the cluster.
294+
properties:
295+
coreDNS:
296+
description: CoreDNS defines the CoreDNS configuration for the cluster.
297+
properties:
298+
image:
299+
description: Image required for overriding Kubernetes DNS image details.
300+
properties:
301+
repository:
302+
description: Repository is used to override the image repository to pull from.
303+
pattern: ^((?:[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*|\[(?:[a-fA-F0-9:]+)\])(:[0-9]+)?/)?[a-z0-9]+((?:[._]|__|[-]+)[a-z0-9]+)*(/[a-z0-9]+((?:[._]|__|[-]+)[a-z0-9]+)*)*$
304+
type: string
305+
tag:
306+
description: Tag is used to override the default image tag.
307+
pattern: ^[\w][\w.-]{0,127}$
308+
type: string
309+
type: object
310+
type: object
311+
type: object
292312
docker:
293313
type: object
294314
encryptionAtRest:

api/v1alpha1/crds/caren.nutanix.com_genericclusterconfigs.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,30 @@ spec:
5050
spec:
5151
description: GenericClusterConfigSpec defines the desired state of GenericClusterConfig.
5252
properties:
53+
dns:
54+
description: DNS defines the DNS configuration for the cluster.
55+
properties:
56+
coreDNS:
57+
description: CoreDNS defines the CoreDNS configuration for the
58+
cluster.
59+
properties:
60+
image:
61+
description: Image required for overriding Kubernetes DNS
62+
image details.
63+
properties:
64+
repository:
65+
description: Repository is used to override the image
66+
repository to pull from.
67+
pattern: ^((?:[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*|\[(?:[a-fA-F0-9:]+)\])(:[0-9]+)?/)?[a-z0-9]+((?:[._]|__|[-]+)[a-z0-9]+)*(/[a-z0-9]+((?:[._]|__|[-]+)[a-z0-9]+)*)*$
68+
type: string
69+
tag:
70+
description: Tag is used to override the default image
71+
tag.
72+
pattern: ^[\w][\w.-]{0,127}$
73+
type: string
74+
type: object
75+
type: object
76+
type: object
5377
encryptionAtRest:
5478
description: |-
5579
EncryptionAtRest defines the configuration to enable encryption at REST

api/v1alpha1/crds/caren.nutanix.com_nutanixclusterconfigs.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,26 @@ spec:
442442
type: object
443443
type: array
444444
type: object
445+
dns:
446+
description: DNS defines the DNS configuration for the cluster.
447+
properties:
448+
coreDNS:
449+
description: CoreDNS defines the CoreDNS configuration for the cluster.
450+
properties:
451+
image:
452+
description: Image required for overriding Kubernetes DNS image details.
453+
properties:
454+
repository:
455+
description: Repository is used to override the image repository to pull from.
456+
pattern: ^((?:[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*|\[(?:[a-fA-F0-9:]+)\])(:[0-9]+)?/)?[a-z0-9]+((?:[._]|__|[-]+)[a-z0-9]+)*(/[a-z0-9]+((?:[._]|__|[-]+)[a-z0-9]+)*)*$
457+
type: string
458+
tag:
459+
description: Tag is used to override the default image tag.
460+
pattern: ^[\w][\w.-]{0,127}$
461+
type: string
462+
type: object
463+
type: object
464+
type: object
445465
encryptionAtRest:
446466
description: |-
447467
EncryptionAtRest defines the configuration to enable encryption at REST

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 45 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
+++
2+
title = "etcd"
3+
+++
4+
5+
This customization will be available when the
6+
[provider-specific cluster configuration patch]({{< ref "..">}}) is included in the `ClusterClass`.
7+
8+
The DNS configuration can then be manipulated via the cluster variables.
9+
If the `dns` property is not specified, then the customization will be skipped.
10+
11+
## CoreDNS
12+
13+
The CoreDNS configuration can then be manipulated via the cluster variables.
14+
If the `dns.coreDNS` property is not specified, then the customization will be skipped.
15+
16+
### Example
17+
18+
To change the repository and tag for the container image for the CoreDNS pod, specify the following configuration:
19+
20+
> Note do not include "coredns" in the repository, kubeadm already appends it.
21+
22+
```yaml
23+
apiVersion: cluster.x-k8s.io/v1beta1
24+
kind: Cluster
25+
metadata:
26+
name: <NAME>
27+
spec:
28+
topology:
29+
variables:
30+
- name: clusterConfig
31+
value:
32+
dns:
33+
coreDNS:
34+
image:
35+
repository: my-registry.io/my-org/my-repo
36+
tag: "v1.11.3_custom.0"
37+
```
38+
39+
Applying this configuration will result in the following value being set:
40+
41+
- `KubeadmControlPlaneTemplate`:
42+
43+
- ```yaml
44+
spec:
45+
kubeadmConfigSpec:
46+
clusterConfiguration:
47+
dns:
48+
imageRepository: "my-registry.io/my-org/my-repo"
49+
imageTag: "v1.11.3_custom.0"
50+
```

docs/content/customization/generic/etcd.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ the customization will be skipped.
1212

1313
To change the repository and tag for the container image for the etcd pod, specify the following configuration:
1414

15+
> Note do not include "etcd" in the repository, kubeadm already appends it.
16+
1517
```yaml
1618
apiVersion: cluster.x-k8s.io/v1beta1
1719
kind: Cluster
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
// Copyright 2023 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package coredns
5+
6+
import (
7+
"context"
8+
9+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
10+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
11+
bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
12+
controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta1"
13+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
14+
ctrl "sigs.k8s.io/controller-runtime"
15+
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
16+
17+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
18+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/mutation"
19+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches"
20+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/patches/selectors"
21+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables"
22+
)
23+
24+
const (
25+
// VariableName is the external patch variable name.
26+
VariableName = "coreDNS"
27+
)
28+
29+
type coreDNSPatchHandler struct {
30+
variableName string
31+
variableFieldPath []string
32+
}
33+
34+
func NewPatch() *coreDNSPatchHandler {
35+
return newKubernetesDNSPatchHandlerPatchHandler(
36+
v1alpha1.ClusterConfigVariableName, v1alpha1.DNSVariableName, VariableName,
37+
)
38+
}
39+
40+
func newKubernetesDNSPatchHandlerPatchHandler(
41+
variableName string,
42+
variableFieldPath ...string,
43+
) *coreDNSPatchHandler {
44+
return &coreDNSPatchHandler{
45+
variableName: variableName,
46+
variableFieldPath: variableFieldPath,
47+
}
48+
}
49+
50+
func (h *coreDNSPatchHandler) Mutate(
51+
ctx context.Context,
52+
obj *unstructured.Unstructured,
53+
vars map[string]apiextensionsv1.JSON,
54+
holderRef runtimehooksv1.HolderReference,
55+
_ ctrlclient.ObjectKey,
56+
_ mutation.ClusterGetter,
57+
) error {
58+
log := ctrl.LoggerFrom(ctx).WithValues(
59+
"holderRef", holderRef,
60+
)
61+
62+
coreDNSVar, err := variables.Get[v1alpha1.CoreDNS](
63+
vars,
64+
h.variableName,
65+
h.variableFieldPath...,
66+
)
67+
if err != nil {
68+
if variables.IsNotFoundError(err) {
69+
log.V(5).Info("coreDNSVar variable not defined")
70+
return nil
71+
}
72+
return err
73+
}
74+
75+
log = log.WithValues(
76+
"variableName",
77+
h.variableName,
78+
"variableFieldPath",
79+
h.variableFieldPath,
80+
"variableValue",
81+
coreDNSVar,
82+
)
83+
84+
return patches.MutateIfApplicable(
85+
obj, vars, &holderRef, selectors.ControlPlane(), log,
86+
func(obj *controlplanev1.KubeadmControlPlaneTemplate) error {
87+
log.WithValues(
88+
"patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(),
89+
"patchedObjectName", ctrlclient.ObjectKeyFromObject(obj),
90+
).Info("setting CoreDNS version if needed")
91+
92+
if obj.Spec.Template.Spec.KubeadmConfigSpec.ClusterConfiguration == nil {
93+
obj.Spec.Template.Spec.KubeadmConfigSpec.ClusterConfiguration = &bootstrapv1.ClusterConfiguration{}
94+
}
95+
96+
if coreDNSVar.Image == nil {
97+
return nil
98+
}
99+
100+
dns := obj.Spec.Template.Spec.KubeadmConfigSpec.ClusterConfiguration.DNS
101+
102+
if coreDNSVar.Image.Tag != "" {
103+
dns.ImageTag = coreDNSVar.Image.Tag
104+
}
105+
106+
if coreDNSVar.Image.Repository != "" {
107+
dns.ImageRepository = coreDNSVar.Image.Repository
108+
}
109+
110+
obj.Spec.Template.Spec.KubeadmConfigSpec.ClusterConfiguration.DNS = dns
111+
112+
return nil
113+
})
114+
}

0 commit comments

Comments
 (0)