Skip to content

Commit 09b4650

Browse files
committed
feat: add Multus CNI integration with socket-based readiness
Implement Multus CNI as an internal addon that automatically deploys alongside primary CNI providers (Cilium/Calico) on supported cloud providers (EKS/Nutanix). - Add socket-based readiness detection using CNI socket paths - Implement template function following CAREN standard pattern - Register Multus handler in lifecycle hooks - Add values template with Go template syntax for socket configuration - Deploy Multus using HelmAddon strategy with readinessIndicatorFile Multus is not exposed in the API and deploys automatically based on cloud provider and CNI selection.
1 parent 525d099 commit 09b4650

File tree

16 files changed

+565
-1
lines changed

16 files changed

+565
-1
lines changed

charts/cluster-api-runtime-extensions-nutanix/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ A Helm chart for cluster-api-runtime-extensions-nutanix
7878
| hooks.cni.cilium.crsStrategy.defaultCiliumConfigMap.name | string | `"cilium"` | |
7979
| hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | |
8080
| hooks.cni.cilium.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-cilium-cni-helm-values-template"` | |
81+
| hooks.cni.multus.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | |
82+
| hooks.cni.multus.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-multus-values-template"` | |
8183
| hooks.cosi.controller.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | |
8284
| hooks.cosi.controller.helmAddonStrategy.defaultValueTemplateConfigMap.name | string | `"default-cosi-controller-helm-values-template"` | |
8385
| hooks.csi.aws-ebs.helmAddonStrategy.defaultValueTemplateConfigMap.create | bool | `true` | |
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Default values for multus.
2+
# This is a YAML-formatted file.
3+
# Declare variables to be passed into your templates.
4+
5+
# Image configuration
6+
image:
7+
repository: ghcr.io/k8snetworkplumbingwg/multus-cni
8+
tag: "" # If empty, will use Chart.AppVersion + suffix
9+
suffix: "-thick" # Default suffix (can be overridden)
10+
pullPolicy: IfNotPresent
11+
12+
# Image pull secrets
13+
imagePullSecrets: []
14+
15+
# Service account configuration
16+
serviceAccount:
17+
create: true
18+
name: multus
19+
annotations: {}
20+
21+
# Pod security context
22+
podSecurityContext:
23+
privileged: true
24+
25+
# Container security context
26+
securityContext:
27+
privileged: true
28+
capabilities:
29+
add:
30+
- NET_ADMIN
31+
- SYS_ADMIN
32+
33+
# Priority class
34+
priorityClassName: system-node-critical
35+
36+
# Pod network configuration
37+
hostNetwork: true
38+
hostPID: true
39+
40+
# Pod lifecycle configuration
41+
terminationGracePeriodSeconds: 10
42+
43+
# Update strategy
44+
updateStrategy:
45+
type: RollingUpdate
46+
rollingUpdate:
47+
maxUnavailable: 1
48+
49+
# Tolerations
50+
tolerations:
51+
- operator: Exists
52+
effect: NoSchedule
53+
- operator: Exists
54+
effect: NoExecute
55+
56+
# Node selector
57+
nodeSelector: {}
58+
59+
# Affinity
60+
affinity: {}
61+
62+
# Pod annotations
63+
podAnnotations: {}
64+
65+
# Pod labels
66+
podLabels: {}
67+
68+
# Resource limits and requests
69+
resources:
70+
limits:
71+
cpu: 100m
72+
memory: 128Mi
73+
requests:
74+
cpu: 100m
75+
memory: 128Mi
76+
77+
# Multus daemon configuration
78+
daemonConfig:
79+
chrootDir: "/hostroot"
80+
cniVersion: "0.3.1"
81+
logLevel: "verbose"
82+
logToStderr: true
83+
readinessIndicatorFile: "{{ .ReadinessSocketPath }}"
84+
cniConfigDir: "/host/etc/cni/net.d"
85+
multusAutoconfigDir: "/host/etc/cni/net.d"
86+
multusConfigFile: "auto"
87+
socketDir: "/host/run/multus/"
88+
89+
{{- if .ReadinessSocketPath }}
90+
# Volumes for CNI readiness socket
91+
volumes:
92+
- name: {{ .SocketVolumeName }}
93+
hostPath:
94+
path: "{{ .ReadinessSocketPath }}"
95+
type: Socket
96+
97+
# Volume mounts for CNI readiness socket
98+
volumeMounts:
99+
- name: {{ .SocketVolumeName }}
100+
mountPath: "{{ .ReadinessSocketPath }}"
101+
readOnly: true
102+
{{- end }}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright 2024 Nutanix. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
{{- if .Values.hooks.cni.multus.helmAddonStrategy.defaultValueTemplateConfigMap.create }}
5+
apiVersion: v1
6+
kind: ConfigMap
7+
metadata:
8+
name: '{{ .Values.hooks.cni.multus.helmAddonStrategy.defaultValueTemplateConfigMap.name }}'
9+
data:
10+
values.yaml: |-
11+
{{- .Files.Get "addons/cni/multus/values-template.yaml" | nindent 4 }}
12+
{{- end -}}

charts/cluster-api-runtime-extensions-nutanix/templates/helm-config.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ data:
4343
ChartName: metallb
4444
ChartVersion: 0.15.2
4545
RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://metallb.github.io/metallb{{ end }}'
46+
multus: |
47+
ChartName: multus
48+
ChartVersion: 0.1.0
49+
RepositoryURL: '{{ if .Values.helmRepository.enabled }}oci://helm-repository.{{ .Release.Namespace }}.svc/charts{{ else }}https://mesosphere.github.io/charts/stable/{{ end }}'
4650
nfd: |
4751
ChartName: node-feature-discovery
4852
ChartVersion: 0.18.1

charts/cluster-api-runtime-extensions-nutanix/values.schema.json

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -381,6 +381,27 @@
381381
}
382382
}
383383
}
384+
},
385+
"multus": {
386+
"type": "object",
387+
"properties": {
388+
"helmAddonStrategy": {
389+
"type": "object",
390+
"properties": {
391+
"defaultValueTemplateConfigMap": {
392+
"type": "object",
393+
"properties": {
394+
"create": {
395+
"type": "boolean"
396+
},
397+
"name": {
398+
"type": "string"
399+
}
400+
}
401+
}
402+
}
403+
}
404+
}
384405
}
385406
}
386407
},

charts/cluster-api-runtime-extensions-nutanix/values.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ hooks:
4343
defaultValueTemplateConfigMap:
4444
create: true
4545
name: default-cilium-cni-helm-values-template
46+
multus:
47+
helmAddonStrategy:
48+
defaultValueTemplateConfigMap:
49+
create: true
50+
name: default-multus-values-template
4651
csi:
4752
nutanix:
4853
helmAddonStrategy:

hack/addons/helm-chart-bundler/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
ARG MINDTHEGAP_VERSION=v1.24.0
1+
ARG MINDTHEGAP_VERSION=v1.17.0
22

33
FROM --platform=${BUILDPLATFORM} ghcr.io/mesosphere/mindthegap:${MINDTHEGAP_VERSION} as bundle_builder
44
# This gets called by goreleaser so the copy source has to be the path relative to the repo root.

hack/addons/helm-chart-bundler/repos.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ repositories:
5151
charts:
5252
metallb:
5353
- 0.15.2
54+
multus:
55+
repoURL: https://mesosphere.github.io/charts/stable/
56+
charts:
57+
multus:
58+
- 0.1.0
5459
node-feature-discovery:
5560
repoURL: https://kubernetes-sigs.github.io/node-feature-discovery/charts
5661
charts:
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Copyright 2024 Nutanix. All rights reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
apiVersion: kustomize.config.k8s.io/v1beta1
5+
kind: Kustomization
6+
7+
metadata:
8+
name: multus
9+
10+
sortOptions:
11+
order: fifo
12+
13+
helmCharts:
14+
- name: multus
15+
namespace: kube-system
16+
repo: https://mesosphere.github.io/charts/stable/
17+
releaseName: multus
18+
version: 0.1.0
19+
includeCRDs: true
20+
skipTests: true
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
// Copyright 2024 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package multus
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"github.com/go-logr/logr"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
13+
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
14+
15+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/addons"
16+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/config"
17+
)
18+
19+
const (
20+
defaultMultusReleaseName = "multus"
21+
defaultMultusNamespace = metav1.NamespaceSystem
22+
)
23+
24+
type MultusDeployer struct {
25+
client ctrlclient.Client
26+
helmChartInfoGetter *config.HelmChartGetter
27+
}
28+
29+
func NewMultusDeployer(client ctrlclient.Client, helmChartInfoGetter *config.HelmChartGetter) *MultusDeployer {
30+
return &MultusDeployer{
31+
client: client,
32+
helmChartInfoGetter: helmChartInfoGetter,
33+
}
34+
}
35+
36+
func (m *MultusDeployer) Deploy(
37+
ctx context.Context,
38+
cluster *clusterv1.Cluster,
39+
readinessSocketPath string,
40+
targetNamespace string,
41+
log logr.Logger,
42+
) error {
43+
// Check if Multus deployment is supported for this cloud provider
44+
isSupported, providerName := m.isCloudProviderSupported(cluster)
45+
46+
// Currently, Multus is only supported for EKS and Nutanix clusters
47+
if !isSupported {
48+
log.Info("Multus deployment is only supported for EKS and Nutanix clusters. Skipping deployment.")
49+
return nil
50+
}
51+
52+
log.Info(fmt.Sprintf("Cluster is %s. Proceeding with Multus deployment.", providerName))
53+
54+
// Get Multus Helm chart info
55+
helmChart, err := m.helmChartInfoGetter.For(ctx, log, config.Multus)
56+
if err != nil {
57+
// For local testing, provide a placeholder chart info
58+
log.Info("Multus not found in helm-config.yaml, using placeholder chart info for local development")
59+
helmChart = &config.HelmChart{
60+
Name: "multus",
61+
Version: "dev",
62+
Repository: "",
63+
}
64+
}
65+
66+
// Deploy Multus using HelmAddonApplier with template function
67+
strategy := addons.NewHelmAddonApplier(
68+
addons.NewHelmAddonConfig(
69+
"default-multus-values-template",
70+
defaultMultusNamespace,
71+
defaultMultusReleaseName,
72+
),
73+
m.client,
74+
helmChart,
75+
).WithValueTemplater(templateValuesFunc(readinessSocketPath)).
76+
WithDefaultWaiter()
77+
78+
if err := strategy.Apply(ctx, cluster, targetNamespace, log); err != nil {
79+
return fmt.Errorf("failed to apply Multus deployment: %w", err)
80+
}
81+
82+
log.Info("Successfully deployed Multus")
83+
return nil
84+
}
85+
86+
// isCloudProviderSupported checks if the cluster is a supported cloud provider
87+
// by inspecting the infrastructure reference.
88+
func (m *MultusDeployer) isCloudProviderSupported(cluster *clusterv1.Cluster) (
89+
isSupported bool,
90+
providerName string,
91+
) {
92+
if cluster.Spec.InfrastructureRef == nil {
93+
return false, ""
94+
}
95+
96+
switch cluster.Spec.InfrastructureRef.Kind {
97+
case "AWSManagedCluster":
98+
return true, "EKS"
99+
case "NutanixCluster":
100+
return true, "Nutanix"
101+
default:
102+
return false, ""
103+
}
104+
}

0 commit comments

Comments
 (0)