Skip to content

Commit 7819611

Browse files
committed
feat: move OVN identity bootstrap to cniprovisioner
- Move DPU OVN bootstrap kubeconfig generation from Helm init logic into dpucniprovisioner - Write /host-kubernetes/kubelet.conf and /var/run/ovn-kubernetes/host-node-name from resolved host-node identity - Remove bootstrap init-container and make ovnkube wrappers consume provisioner output - Gate artifact generation on K8S_APISERVER to keep non-bootstrap paths unchanged Signed-off-by: Hareesh Puthalath <hareeshp@nvidia.com>
1 parent d9b4a8d commit 7819611

File tree

3 files changed

+110
-57
lines changed

3 files changed

+110
-57
lines changed

dpf-utils/cmd/dpucniprovisioner/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ func main() {
128128
}
129129

130130
provisioner := dpucniprovisioner.New(ctx, mode, c, ovsClient, networkhelper.New(), exec, clientset, vtepIPNet, gateway, vtepCIDR, hostCIDR, pfIPNet, node, gatewayDiscoveryNetwork, ovnMTU)
131+
provisioner.K8sAPIServer = os.Getenv("K8S_APISERVER")
131132

132133
err = provisioner.RunOnce()
133134
if err != nil {

dpf-utils/internal/cniprovisioner/dpu/provisioner.go

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"os"
2626
"path/filepath"
2727
"strconv"
28+
"strings"
2829
"time"
2930

3031
"github.com/nvidia/doca-platform/pkg/utils/networkhelper"
@@ -84,6 +85,10 @@ const (
8485
// netplanApplyCooldownDuration determines the cooldown period of a successful netplan apply command before a
8586
// subsequent netplan apply command is executed.
8687
netplanApplyCooldownDuration = time.Minute * 2
88+
// hostBootstrapKubeconfigPath is the path where bootstrap kubeconfig is written for ovnkube identity.
89+
hostBootstrapKubeconfigPath = "/host-kubernetes/kubelet.conf"
90+
// hostNodeNameFilePath is the path used to publish mapped host node name for other containers in the pod.
91+
hostNodeNameFilePath = "/var/run/ovn-kubernetes/host-node-name"
8792
)
8893

8994
type DPUCNIProvisioner struct {
@@ -98,6 +103,13 @@ type DPUCNIProvisioner struct {
98103
// FileSystemRoot controls the file system root. It's used for enabling easier testing of the package. Defaults to
99104
// empty.
100105
FileSystemRoot string
106+
// K8sAPIServer is the host cluster API server endpoint used in the generated bootstrap kubeconfig.
107+
// Leave empty to skip bootstrap kubeconfig generation.
108+
K8sAPIServer string
109+
// BootstrapKubeconfigPath is where the bootstrap kubeconfig is written. Defaults to hostBootstrapKubeconfigPath.
110+
BootstrapKubeconfigPath string
111+
// HostNodeNameFilePath is where the mapped host node name is written. Defaults to hostNodeNameFilePath.
112+
HostNodeNameFilePath string
101113

102114
// vtepIPNet is the IP that should be added to the VTEP interface.
103115
vtepIPNet *net.IPNet
@@ -154,6 +166,9 @@ func New(ctx context.Context,
154166
exec: exec,
155167
kubernetesClient: kubernetesClient,
156168
FileSystemRoot: "",
169+
K8sAPIServer: "",
170+
BootstrapKubeconfigPath: hostBootstrapKubeconfigPath,
171+
HostNodeNameFilePath: hostNodeNameFilePath,
157172
vtepIPNet: vtepIPNet,
158173
gateway: gateway,
159174
vtepCIDR: vtepCIDR,
@@ -208,9 +223,13 @@ func (p *DPUCNIProvisioner) EnsureConfiguration() {
208223
// configure runs the provisioning flow once
209224
func (p *DPUCNIProvisioner) configure() error {
210225
klog.Info("Configuring Kubernetes host name in OVS")
211-
if err := p.findAndSetKubernetesHostNameInOVS(); err != nil {
226+
hostName, err := p.findAndSetKubernetesHostNameInOVS()
227+
if err != nil {
212228
return fmt.Errorf("error while setting the Kubernetes Host Name in OVS: %w", err)
213229
}
230+
if err := p.writeHostIdentityBootstrapArtifacts(hostName); err != nil {
231+
return fmt.Errorf("error while writing host identity bootstrap artifacts: %w", err)
232+
}
214233

215234
if p.mode == ExternalIPAM {
216235
klog.Info("Configuring br-ovn")
@@ -238,22 +257,83 @@ func (p *DPUCNIProvisioner) configure() error {
238257
}
239258

240259
// findAndSetKubernetesHostNameInOVS discovers and sets the Kubernetes Host Name in OVS
241-
func (p *DPUCNIProvisioner) findAndSetKubernetesHostNameInOVS() error {
260+
func (p *DPUCNIProvisioner) findAndSetKubernetesHostNameInOVS() (string, error) {
242261
nodeClient := p.kubernetesClient.CoreV1().Nodes()
243262
n, err := nodeClient.Get(p.ctx, p.dpuHostName, metav1.GetOptions{})
244263
if err != nil {
245-
return fmt.Errorf("error while getting Kubernetes Node: %w", err)
264+
return "", fmt.Errorf("error while getting Kubernetes Node: %w", err)
246265
}
247266
hostName, ok := n.Labels[constants.HostNameDPULabelKey]
248267
if !ok {
249-
return fmt.Errorf("required label %s is not set on node %s in the DPU cluster", constants.HostNameDPULabelKey, p.dpuHostName)
268+
return "", fmt.Errorf("required label %s is not set on node %s in the DPU cluster", constants.HostNameDPULabelKey, p.dpuHostName)
269+
}
270+
hostName = strings.TrimSpace(hostName)
271+
if hostName == "" {
272+
return "", fmt.Errorf("label %s on node %s cannot be empty", constants.HostNameDPULabelKey, p.dpuHostName)
250273
}
251274

252275
if err := p.ovsClient.SetKubernetesHostNodeName(hostName); err != nil {
253-
return fmt.Errorf("error while setting the Kubernetes Host Name in OVS: %w", err)
276+
return "", fmt.Errorf("error while setting the Kubernetes Host Name in OVS: %w", err)
254277
}
255278
if err := p.ovsClient.SetHostName(hostName); err != nil {
256-
return fmt.Errorf("error while setting the hostname external ID in OVS: %w", err)
279+
return "", fmt.Errorf("error while setting the hostname external ID in OVS: %w", err)
280+
}
281+
return hostName, nil
282+
}
283+
284+
// writeHostIdentityBootstrapArtifacts writes host identity data for other pod containers.
285+
// It writes artifacts only when K8sAPIServer is set, which enables the bootstrap flow.
286+
func (p *DPUCNIProvisioner) writeHostIdentityBootstrapArtifacts(hostName string) error {
287+
if strings.TrimSpace(p.K8sAPIServer) == "" {
288+
return nil
289+
}
290+
291+
hostNodeNamePath := p.HostNodeNameFilePath
292+
if hostNodeNamePath == "" {
293+
hostNodeNamePath = hostNodeNameFilePath
294+
}
295+
hostNodeNamePath = filepath.Join(p.FileSystemRoot, hostNodeNamePath)
296+
if err := os.MkdirAll(filepath.Dir(hostNodeNamePath), 0755); err != nil {
297+
return fmt.Errorf("error while creating directory for host node name file %s: %w", hostNodeNamePath, err)
298+
}
299+
if err := os.WriteFile(hostNodeNamePath, []byte(hostName+"\n"), 0644); err != nil {
300+
return fmt.Errorf("error while writing host node name file %s: %w", hostNodeNamePath, err)
301+
}
302+
303+
bootstrapPath := p.BootstrapKubeconfigPath
304+
if bootstrapPath == "" {
305+
bootstrapPath = hostBootstrapKubeconfigPath
306+
}
307+
bootstrapPath = filepath.Join(p.FileSystemRoot, bootstrapPath)
308+
if err := os.MkdirAll(filepath.Dir(bootstrapPath), 0700); err != nil {
309+
return fmt.Errorf("error while creating directory for bootstrap kubeconfig %s: %w", bootstrapPath, err)
310+
}
311+
312+
bootstrapKubeconfig := fmt.Sprintf(`apiVersion: v1
313+
kind: Config
314+
clusters:
315+
- cluster:
316+
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
317+
server: %s
318+
name: host-cluster
319+
contexts:
320+
- context:
321+
cluster: host-cluster
322+
user: ovn-dpu-bootstrap
323+
name: ovn-dpu-bootstrap
324+
current-context: ovn-dpu-bootstrap
325+
users:
326+
- name: ovn-dpu-bootstrap
327+
user:
328+
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
329+
as: system:node:%s
330+
as-groups:
331+
- system:nodes
332+
- system:authenticated
333+
`, strings.TrimSpace(p.K8sAPIServer), hostName)
334+
335+
if err := os.WriteFile(bootstrapPath, []byte(bootstrapKubeconfig), 0600); err != nil {
336+
return fmt.Errorf("error while writing bootstrap kubeconfig %s: %w", bootstrapPath, err)
257337
}
258338
return nil
259339
}

helm/ovn-kubernetes-dpf/templates/dpu-manifests.yaml

Lines changed: 23 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -190,55 +190,6 @@ spec:
190190
automountServiceAccountToken: false
191191
# DPU CNI provisioner
192192
initContainers:
193-
{{- if $useSecretBootstrap }}
194-
- name: ovnkube-bootstrap-kubeconfig
195-
image: {{ .Values.dpuManifests.image.repository }}:{{ .Values.dpuManifests.image.tag }}
196-
imagePullPolicy: {{ .Values.dpuManifests.image.pullPolicy }}
197-
command:
198-
- /bin/sh
199-
- -ec
200-
- |
201-
cat <<EOF >/host-kubernetes/kubelet.conf
202-
apiVersion: v1
203-
kind: Config
204-
clusters:
205-
- cluster:
206-
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
207-
server: ${K8S_APISERVER}
208-
name: host-cluster
209-
contexts:
210-
- context:
211-
cluster: host-cluster
212-
user: ovn-dpu-bootstrap
213-
name: ovn-dpu-bootstrap
214-
current-context: ovn-dpu-bootstrap
215-
users:
216-
- name: ovn-dpu-bootstrap
217-
user:
218-
tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
219-
as: system:node:${K8S_NODE_DPU%%-mt*}
220-
as-groups:
221-
- system:nodes
222-
- system:authenticated
223-
EOF
224-
chmod 0600 /host-kubernetes/kubelet.conf
225-
env:
226-
- name: K8S_NODE_DPU
227-
valueFrom:
228-
fieldRef:
229-
fieldPath: spec.nodeName
230-
- name: K8S_APISERVER
231-
valueFrom:
232-
configMapKeyRef:
233-
name: {{ include "ovn-kubernetes.fullname" . }}-config
234-
key: k8s_apiserver
235-
volumeMounts:
236-
- mountPath: /host-kubernetes
237-
name: host-kubeconfig
238-
- mountPath: /var/run/secrets/kubernetes.io/serviceaccount
239-
name: tenant-cluster-access-secret
240-
readOnly: true
241-
{{- end }}
242193
{{- if not .Values.dpuManifests.externalDHCP }}
243194
- name: ipallocator
244195
image: {{ .Values.dpuManifests.imagedpf.repository }}:{{ .Values.dpuManifests.imagedpf.tag }}
@@ -337,6 +288,13 @@ spec:
337288
valueFrom:
338289
fieldRef:
339290
fieldPath: spec.nodeName
291+
{{- if $useSecretBootstrap }}
292+
- name: K8S_APISERVER
293+
valueFrom:
294+
configMapKeyRef:
295+
name: {{ include "ovn-kubernetes.fullname" . }}-config
296+
key: k8s_apiserver
297+
{{- end }}
340298
{{- if .Values.dpuManifests.externalDHCP }}
341299
# Needed so that systemctl can run inside the container
342300
- name: SYSTEMCTL_FORCE_BUS
@@ -390,6 +348,12 @@ spec:
390348
readOnly: true
391349
- mountPath: /var/run/openvswitch/
392350
name: host-var-run-ovs
351+
- mountPath: /var/run/ovn-kubernetes
352+
name: host-var-run-ovn-kubernetes
353+
{{- if $useSecretBootstrap }}
354+
- mountPath: /host-kubernetes
355+
name: host-kubeconfig
356+
{{- end }}
393357
containers:
394358
- name: nb-ovsdb
395359
image: {{ .Values.dpuManifests.image.repository }}:{{ .Values.dpuManifests.image.tag }}
@@ -568,7 +532,10 @@ spec:
568532
- /bin/sh
569533
- -ec
570534
- |
571-
export K8S_NODE_DPU="${K8S_NODE_DPU%%-mt*}"
535+
host_node_name_file=/var/run/ovn-kubernetes/host-node-name
536+
if [ -s "${host_node_name_file}" ]; then
537+
export K8S_NODE_DPU="$(tr -d '[:space:]' < "${host_node_name_file}")"
538+
fi
572539
exec /root/ovnkube.sh ovnkube-controller-with-node
573540
securityContext:
574541
runAsUser: 0
@@ -802,7 +769,10 @@ spec:
802769
- /bin/sh
803770
- -ec
804771
- |
805-
export K8S_NODE_DPU="${K8S_NODE_DPU%%-mt*}"
772+
host_node_name_file=/var/run/ovn-kubernetes/host-node-name
773+
if [ -s "${host_node_name_file}" ]; then
774+
export K8S_NODE_DPU="$(tr -d '[:space:]' < "${host_node_name_file}")"
775+
fi
806776
exec /root/ovnkube.sh ovn-controller
807777
securityContext:
808778
runAsUser: 0
@@ -821,6 +791,8 @@ spec:
821791
name: host-var-run-ovs
822792
- mountPath: /var/run/ovn/
823793
name: host-var-run-ovs
794+
- mountPath: /var/run/ovn-kubernetes
795+
name: host-var-run-ovn-kubernetes
824796
- mountPath: /ovn-cert
825797
name: host-ovn-cert
826798
readOnly: true

0 commit comments

Comments
 (0)