-
Notifications
You must be signed in to change notification settings - Fork 8
feat: add Multus CNI integration with socket-based readiness #1367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 2 commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
charts/cluster-api-runtime-extensions-nutanix/addons/cni/multus/values-template.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| # Multus daemon configuration overrides | ||
| daemonConfig: | ||
| readinessIndicatorFile: "{{ .SocketPath }}" | ||
|
|
||
| {{- if .SocketPath }} | ||
| # Volumes for CNI readiness socket | ||
| volumes: | ||
| - name: cni-readiness-sock | ||
| hostPath: | ||
| path: "{{ .SocketPath }}" | ||
| type: Socket | ||
|
|
||
| # Volume mounts for CNI readiness socket | ||
| volumeMounts: | ||
| - name: cni-readiness-sock | ||
| mountPath: "{{ .SocketPath }}" | ||
| readOnly: true | ||
| {{- end }} | ||
12 changes: 12 additions & 0 deletions
12
...pi-runtime-extensions-nutanix/templates/cni/multus/manifests/helm-addon-installation.yaml
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| # Copyright 2024 Nutanix. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| {{- if .Values.hooks.cni.multus.helmAddonStrategy.defaultValueTemplateConfigMap.create }} | ||
| apiVersion: v1 | ||
| kind: ConfigMap | ||
| metadata: | ||
| name: '{{ .Values.hooks.cni.multus.helmAddonStrategy.defaultValueTemplateConfigMap.name }}' | ||
| data: | ||
| values.yaml: |- | ||
| {{- .Files.Get "addons/cni/multus/values-template.yaml" | nindent 4 }} | ||
| {{- end -}} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| # Copyright 2024 Nutanix. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| apiVersion: kustomize.config.k8s.io/v1beta1 | ||
| kind: Kustomization | ||
|
|
||
| metadata: | ||
| name: multus | ||
|
|
||
| sortOptions: | ||
| order: fifo | ||
|
|
||
| helmCharts: | ||
| - name: multus | ||
| namespace: kube-system | ||
| repo: https://mesosphere.github.io/charts/stable/ | ||
| releaseName: multus | ||
| version: 0.1.0 | ||
| includeCRDs: true | ||
| skipTests: true |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // Copyright 2024 Nutanix. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| // Package multus provides a standalone lifecycle handler for Multus CNI that automatically | ||
| // deploys Multus when: | ||
| // - The cluster is on a supported cloud provider (EKS or Nutanix) | ||
| // - A supported CNI provider is configured (Cilium or Calico) | ||
| // | ||
| // MultusHandler implements the cluster lifecycle hooks and: | ||
| // - Detects the cloud provider from the cluster infrastructure | ||
| // - Reads CNI configuration from cluster variables | ||
| // - Gets the socket path for the configured CNI (via cni.SocketPath) | ||
| // - Automatically deploys Multus with socket-based configuration | ||
| // | ||
| // helmAddonStrategy is the internal strategy that handles: | ||
| // - Templating Helm values with the CNI socket path | ||
| // - Deploying Multus using HelmAddon strategy with Go template-based values | ||
| // | ||
| // Multus relies on the readinessIndicatorFile configuration to wait for the primary CNI | ||
| // to be ready, eliminating the need for explicit wait logic in the strategy. | ||
| // | ||
| // This package does NOT expose Multus in the API - it's an internal addon | ||
| // that deploys automatically based on cloud provider and CNI selection. | ||
| package multus |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,190 @@ | ||
| // Copyright 2024 Nutanix. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package multus | ||
|
|
||
| import ( | ||
| "context" | ||
| "fmt" | ||
|
|
||
| "github.com/spf13/pflag" | ||
| metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
| clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" | ||
| runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1" | ||
| ctrl "sigs.k8s.io/controller-runtime" | ||
| ctrlclient "sigs.k8s.io/controller-runtime/pkg/client" | ||
|
|
||
| "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1" | ||
| commonhandlers "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers" | ||
| "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle" | ||
| "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/variables" | ||
| capiutils "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/utils" | ||
| "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/addons" | ||
| "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/cni" | ||
| "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/config" | ||
| "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options" | ||
| ) | ||
|
|
||
| const ( | ||
| defaultMultusReleaseName = "multus" | ||
| defaultMultusNamespace = metav1.NamespaceSystem | ||
| ) | ||
|
|
||
| type MultusConfig struct { | ||
| *options.GlobalOptions | ||
|
|
||
| helmAddonConfig *addons.HelmAddonConfig | ||
| } | ||
|
|
||
| func NewMultusConfig(globalOptions *options.GlobalOptions) *MultusConfig { | ||
| return &MultusConfig{ | ||
| GlobalOptions: globalOptions, | ||
| helmAddonConfig: addons.NewHelmAddonConfig( | ||
| "default-multus-values-template", | ||
| defaultMultusNamespace, | ||
| defaultMultusReleaseName, | ||
| ), | ||
| } | ||
| } | ||
|
|
||
| func (m *MultusConfig) AddFlags(prefix string, flags *pflag.FlagSet) { | ||
| m.helmAddonConfig.AddFlags(prefix+".helm-addon", flags) | ||
| } | ||
|
|
||
| type MultusHandler struct { | ||
| client ctrlclient.Client | ||
| config *MultusConfig | ||
| helmChartInfoGetter *config.HelmChartGetter | ||
| } | ||
|
|
||
| var ( | ||
| _ commonhandlers.Named = &MultusHandler{} | ||
| _ lifecycle.AfterControlPlaneInitialized = &MultusHandler{} | ||
| _ lifecycle.BeforeClusterUpgrade = &MultusHandler{} | ||
| ) | ||
|
|
||
| func New( | ||
| c ctrlclient.Client, | ||
| cfg *MultusConfig, | ||
| helmChartInfoGetter *config.HelmChartGetter, | ||
| ) *MultusHandler { | ||
| return &MultusHandler{ | ||
| client: c, | ||
| config: cfg, | ||
| helmChartInfoGetter: helmChartInfoGetter, | ||
| } | ||
| } | ||
|
|
||
| func (m *MultusHandler) Name() string { | ||
| return "MultusHandler" | ||
| } | ||
|
|
||
| func (m *MultusHandler) AfterControlPlaneInitialized( | ||
| ctx context.Context, | ||
| req *runtimehooksv1.AfterControlPlaneInitializedRequest, | ||
| resp *runtimehooksv1.AfterControlPlaneInitializedResponse, | ||
| ) { | ||
| commonResponse := &runtimehooksv1.CommonResponse{} | ||
| m.apply(ctx, &req.Cluster, commonResponse) | ||
| resp.Status = commonResponse.GetStatus() | ||
| resp.Message = commonResponse.GetMessage() | ||
| } | ||
|
|
||
| func (m *MultusHandler) BeforeClusterUpgrade( | ||
| ctx context.Context, | ||
| req *runtimehooksv1.BeforeClusterUpgradeRequest, | ||
| resp *runtimehooksv1.BeforeClusterUpgradeResponse, | ||
| ) { | ||
| commonResponse := &runtimehooksv1.CommonResponse{} | ||
| m.apply(ctx, &req.Cluster, commonResponse) | ||
| resp.Status = commonResponse.GetStatus() | ||
| resp.Message = commonResponse.GetMessage() | ||
| } | ||
|
|
||
| func (m *MultusHandler) apply( | ||
| ctx context.Context, | ||
| cluster *clusterv1.Cluster, | ||
| resp *runtimehooksv1.CommonResponse, | ||
| ) { | ||
| clusterKey := ctrlclient.ObjectKeyFromObject(cluster) | ||
|
|
||
| log := ctrl.LoggerFrom(ctx).WithValues( | ||
| "cluster", | ||
| clusterKey, | ||
| ) | ||
|
|
||
| // Check if Multus is supported for this cloud provider | ||
| provider := capiutils.GetProvider(cluster) | ||
| if provider != "eks" && provider != "nutanix" { | ||
dkoshkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| log.V(5).Info( | ||
| "Multus is not supported for this cloud provider. Skipping Multus deployment.", | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| log.Info(fmt.Sprintf("Cluster is %s. Checking CNI configuration for Multus deployment.", provider)) | ||
|
|
||
| // Read CNI configuration to detect which CNI is deployed | ||
| varMap := variables.ClusterVariablesToVariablesMap(cluster.Spec.Topology.Variables) | ||
|
|
||
| cniVar, err := variables.Get[v1alpha1.CNI]( | ||
| varMap, | ||
| v1alpha1.ClusterConfigVariableName, | ||
| []string{"addons", v1alpha1.CNIVariableName}...) | ||
| if err != nil { | ||
| if variables.IsNotFoundError(err) { | ||
| log.V(5).Info("No CNI specified in cluster config. Skipping Multus deployment.") | ||
| return | ||
| } | ||
| log.Error(err, "failed to read CNI configuration from cluster definition") | ||
| resp.SetStatus(runtimehooksv1.ResponseStatusFailure) | ||
| resp.SetMessage(fmt.Sprintf("failed to read CNI configuration: %v", err)) | ||
| return | ||
| } | ||
|
|
||
| // Get socket path for the CNI provider | ||
| socketPath, err := cni.SocketPath(cniVar.Provider) | ||
dkoshkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| if err != nil { | ||
| log.V(5). | ||
| Info(fmt.Sprintf("Multus does not support CNI provider: %s. Skipping Multus deployment.", cniVar.Provider)) | ||
| return | ||
| } | ||
|
|
||
| log.Info(fmt.Sprintf("Auto-deploying Multus for %s cluster with %s CNI", provider, cniVar.Provider)) | ||
|
|
||
| // Get helm chart configuration | ||
| helmChart, err := m.helmChartInfoGetter.For(ctx, log, config.Multus) | ||
| if err != nil { | ||
| log.Error( | ||
| err, | ||
| "failed to get configmap with helm settings", | ||
| ) | ||
| resp.SetStatus(runtimehooksv1.ResponseStatusFailure) | ||
| resp.SetMessage( | ||
| fmt.Sprintf("failed to get configuration to create helm addon: %v", | ||
| err, | ||
| ), | ||
| ) | ||
| return | ||
| } | ||
|
|
||
| // Create and apply helm addon using existing addons package | ||
| targetNamespace := m.config.DefaultsNamespace() | ||
| strategy := addons.NewHelmAddonApplier( | ||
| m.config.helmAddonConfig, | ||
| m.client, | ||
| helmChart, | ||
| ). | ||
| WithValueTemplater(templateValuesFunc(socketPath)). | ||
| WithDefaultWaiter() | ||
|
|
||
| if err := strategy.Apply(ctx, cluster, targetNamespace, log); err != nil { | ||
| log.Error(err, "failed to deploy Multus") | ||
| resp.SetStatus(runtimehooksv1.ResponseStatusFailure) | ||
| resp.SetMessage(fmt.Sprintf("failed to deploy Multus: %v", err)) | ||
| return | ||
| } | ||
|
|
||
| resp.SetStatus(runtimehooksv1.ResponseStatusSuccess) | ||
| resp.SetMessage("Multus deployed successfully") | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // Copyright 2024 Nutanix. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| package multus | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "fmt" | ||
| "text/template" | ||
|
|
||
| clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" | ||
| ) | ||
|
|
||
| // templateValuesFunc returns a template function that parses the Multus values template | ||
| // and replaces socket-related placeholders with the provided socket path. | ||
| func templateValuesFunc(socketPath string) func(*clusterv1.Cluster, string) (string, error) { | ||
dkoshkin marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return func(_ *clusterv1.Cluster, valuesTemplate string) (string, error) { | ||
| t, err := template.New("").Parse(valuesTemplate) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to parse Multus values template: %w", err) | ||
| } | ||
|
|
||
| type input struct { | ||
| SocketPath string | ||
| } | ||
|
|
||
| templateInput := input{ | ||
| SocketPath: socketPath, | ||
| } | ||
|
|
||
| var b bytes.Buffer | ||
| err = t.Execute(&b, templateInput) | ||
| if err != nil { | ||
| return "", fmt.Errorf("failed to template Multus values: %w", err) | ||
| } | ||
|
|
||
| return b.String(), nil | ||
| } | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.