@@ -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
8994type 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
209224func (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}
0 commit comments