Skip to content

Commit dc6812d

Browse files
committed
feat: deploy AWS Load Balancer controller
1 parent 0bf652e commit dc6812d

File tree

4 files changed

+214
-40
lines changed

4 files changed

+214
-40
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Copyright 2025 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
// Package awsloadbalancercontroller provides lifecycle handlers for deploying the AWS Load Balancer Controller addon.
5+
//
6+
// The AWS Load Balancer Controller manages AWS Application Load Balancers (ALB) and Network Load Balancers (NLB)
7+
// for Kubernetes services and ingresses. This package provides handlers that deploy the controller using
8+
// the Cluster API Add-on Provider for Helm (CAAPH).
9+
//
10+
// The handler automatically installs the AWS Load Balancer Controller during the AfterControlPlaneInitialized
11+
// lifecycle phase, ensuring the controller is available for managing load balancer resources.
12+
package awsloadbalancercontroller
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
// Copyright 2025 Nutanix. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package awsloadbalancercontroller
5+
6+
import (
7+
"context"
8+
"fmt"
9+
10+
"github.com/spf13/pflag"
11+
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
12+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
13+
ctrl "sigs.k8s.io/controller-runtime"
14+
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
15+
16+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
17+
commonhandlers "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers"
18+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle"
19+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/utils"
20+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/addons"
21+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/config"
22+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/options"
23+
)
24+
25+
const (
26+
// Abbreviate name to be <63 characters with the UUID suffix
27+
defaultHelmReleaseName = "aws-lb-controller"
28+
defaultHelmReleaseNamespace = "kube-system"
29+
)
30+
31+
type ControllerConfig struct {
32+
*options.GlobalOptions
33+
34+
helmAddonConfig *addons.HelmAddonConfig
35+
}
36+
37+
func NewControllerConfig(globalOptions *options.GlobalOptions) *ControllerConfig {
38+
return &ControllerConfig{
39+
GlobalOptions: globalOptions,
40+
helmAddonConfig: addons.NewHelmAddonConfig(
41+
"default-aws-load-balancer-controller-helm-values-template",
42+
defaultHelmReleaseNamespace,
43+
defaultHelmReleaseName,
44+
),
45+
}
46+
}
47+
48+
func (c *ControllerConfig) AddFlags(prefix string, flags *pflag.FlagSet) {
49+
c.helmAddonConfig.AddFlags(prefix+".helm-addon", flags)
50+
}
51+
52+
type DefaultAWSLoadBalancerController struct {
53+
client ctrlclient.Client
54+
config *ControllerConfig
55+
helmChartInfoGetter *config.HelmChartGetter
56+
57+
variableName string // points to the global config variable
58+
variablePath []string // path of this variable on the global config variable
59+
}
60+
61+
var (
62+
_ commonhandlers.Named = &DefaultAWSLoadBalancerController{}
63+
_ lifecycle.AfterControlPlaneInitialized = &DefaultAWSLoadBalancerController{}
64+
_ lifecycle.BeforeClusterUpgrade = &DefaultAWSLoadBalancerController{}
65+
)
66+
67+
func New(
68+
c ctrlclient.Client,
69+
cfg *ControllerConfig,
70+
helmChartInfoGetter *config.HelmChartGetter,
71+
) *DefaultAWSLoadBalancerController {
72+
return &DefaultAWSLoadBalancerController{
73+
client: c,
74+
config: cfg,
75+
helmChartInfoGetter: helmChartInfoGetter,
76+
variableName: v1alpha1.ClusterConfigVariableName,
77+
variablePath: []string{"addons", "loadBalancerController"},
78+
}
79+
}
80+
81+
func (n *DefaultAWSLoadBalancerController) Name() string {
82+
return "AWSLoadBalancerControllerHandler"
83+
}
84+
85+
func (n *DefaultAWSLoadBalancerController) AfterControlPlaneInitialized(
86+
ctx context.Context,
87+
req *runtimehooksv1.AfterControlPlaneInitializedRequest,
88+
resp *runtimehooksv1.AfterControlPlaneInitializedResponse,
89+
) {
90+
commonResponse := &runtimehooksv1.CommonResponse{}
91+
n.apply(ctx, &req.Cluster, commonResponse)
92+
resp.Status = commonResponse.GetStatus()
93+
resp.Message = commonResponse.GetMessage()
94+
}
95+
96+
func (n *DefaultAWSLoadBalancerController) BeforeClusterUpgrade(
97+
ctx context.Context,
98+
req *runtimehooksv1.BeforeClusterUpgradeRequest,
99+
resp *runtimehooksv1.BeforeClusterUpgradeResponse,
100+
) {
101+
commonResponse := &runtimehooksv1.CommonResponse{}
102+
n.apply(ctx, &req.Cluster, commonResponse)
103+
resp.Status = commonResponse.GetStatus()
104+
resp.Message = commonResponse.GetMessage()
105+
}
106+
107+
func (n *DefaultAWSLoadBalancerController) apply(
108+
ctx context.Context,
109+
cluster *clusterv1.Cluster,
110+
resp *runtimehooksv1.CommonResponse,
111+
) {
112+
clusterKey := ctrlclient.ObjectKeyFromObject(cluster)
113+
114+
log := ctrl.LoggerFrom(ctx).WithValues(
115+
"cluster",
116+
clusterKey,
117+
)
118+
119+
// For now, always enable the AWS Load Balancer Controller
120+
// FIXME: Add proper variable checking when APIs are added
121+
if provider := utils.GetProvider(cluster); provider != "eks" {
122+
log.V(5).Info("Skipping AWS Load Balancer Controller handler,not an EKS cluster", provider)
123+
return
124+
}
125+
126+
log.Info("Installing AWS Load Balancer Controller addon")
127+
128+
helmChart, err := n.helmChartInfoGetter.For(ctx, log, config.AWSLoadBalancerController)
129+
if err != nil {
130+
log.Error(
131+
err,
132+
"failed to get configmap with helm settings",
133+
)
134+
resp.SetStatus(runtimehooksv1.ResponseStatusFailure)
135+
resp.SetMessage(
136+
fmt.Sprintf("failed to get configuration to create helm addon: %v",
137+
err,
138+
),
139+
)
140+
return
141+
}
142+
143+
strategy := addons.NewHelmAddonApplier(
144+
n.config.helmAddonConfig,
145+
n.client,
146+
helmChart,
147+
)
148+
149+
if err := strategy.Apply(ctx, cluster, n.config.DefaultsNamespace(), log); err != nil {
150+
err = fmt.Errorf("failed to apply AWS Load Balancer Controller addon: %w", err)
151+
resp.SetStatus(runtimehooksv1.ResponseStatusFailure)
152+
resp.SetMessage(err.Error())
153+
return
154+
}
155+
156+
resp.SetStatus(runtimehooksv1.ResponseStatusSuccess)
157+
}

pkg/handlers/lifecycle/config/cm.go

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,20 +17,21 @@ import (
1717
type Component string
1818

1919
const (
20-
Autoscaler Component = "cluster-autoscaler"
21-
Tigera Component = "tigera-operator"
22-
Cilium Component = "cilium"
23-
NFD Component = "nfd"
24-
NutanixStorageCSI Component = "nutanix-storage-csi"
25-
SnapshotController Component = "snapshot-controller"
26-
NutanixCCM Component = "nutanix-ccm"
27-
MetalLB Component = "metallb"
28-
LocalPathProvisionerCSI Component = "local-path-provisioner-csi"
29-
AWSEBSCSI Component = "aws-ebs-csi"
30-
AWSCCM Component = "aws-ccm"
31-
COSIController Component = "cosi-controller"
32-
CNCFDistributionRegistry Component = "cncf-distribution-registry"
33-
RegistrySyncer Component = "registry-syncer"
20+
Autoscaler Component = "cluster-autoscaler"
21+
Tigera Component = "tigera-operator"
22+
Cilium Component = "cilium"
23+
NFD Component = "nfd"
24+
NutanixStorageCSI Component = "nutanix-storage-csi"
25+
SnapshotController Component = "snapshot-controller"
26+
NutanixCCM Component = "nutanix-ccm"
27+
MetalLB Component = "metallb"
28+
LocalPathProvisionerCSI Component = "local-path-provisioner-csi"
29+
AWSEBSCSI Component = "aws-ebs-csi"
30+
AWSCCM Component = "aws-ccm"
31+
AWSLoadBalancerController Component = "aws-load-balancer-controller"
32+
COSIController Component = "cosi-controller"
33+
CNCFDistributionRegistry Component = "cncf-distribution-registry"
34+
RegistrySyncer Component = "registry-syncer"
3435
)
3536

3637
type HelmChartGetter struct {

pkg/handlers/lifecycle/handlers.go

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
1212
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers"
1313
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/common/pkg/capi/clustertopology/handlers/lifecycle"
14+
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/awsloadbalancercontroller"
1415
"github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm"
1516
awsccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm/aws"
1617
nutanixccm "github.com/nutanix-cloud-native/cluster-api-runtime-extensions-nutanix/pkg/handlers/lifecycle/ccm/nutanix"
@@ -34,20 +35,21 @@ import (
3435
)
3536

3637
type Handlers struct {
37-
globalOptions *options.GlobalOptions
38-
calicoCNIConfig *calico.CNIConfig
39-
ciliumCNIConfig *cilium.CNIConfig
40-
nfdConfig *nfd.Config
41-
clusterAutoscalerConfig *clusterautoscaler.Config
42-
ebsConfig *awsebs.Config
43-
nutanixCSIConfig *nutanixcsi.Config
44-
awsccmConfig *awsccm.AWSCCMConfig
45-
nutanixCCMConfig *nutanixccm.Config
46-
metalLBConfig *metallb.Config
47-
localPathCSIConfig *localpath.Config
48-
snapshotControllerConfig *snapshotcontroller.Config
49-
cosiControllerConfig *cosi.ControllerConfig
50-
distributionConfig *cncfdistribution.Config
38+
globalOptions *options.GlobalOptions
39+
calicoCNIConfig *calico.CNIConfig
40+
ciliumCNIConfig *cilium.CNIConfig
41+
nfdConfig *nfd.Config
42+
clusterAutoscalerConfig *clusterautoscaler.Config
43+
ebsConfig *awsebs.Config
44+
nutanixCSIConfig *nutanixcsi.Config
45+
awsccmConfig *awsccm.AWSCCMConfig
46+
nutanixCCMConfig *nutanixccm.Config
47+
metalLBConfig *metallb.Config
48+
localPathCSIConfig *localpath.Config
49+
snapshotControllerConfig *snapshotcontroller.Config
50+
cosiControllerConfig *cosi.ControllerConfig
51+
awsLoadBalancerControllerConfig *awsloadbalancercontroller.ControllerConfig
52+
distributionConfig *cncfdistribution.Config
5153
}
5254

5355
func New(
@@ -58,18 +60,19 @@ func New(
5860
calicoCNIConfig: &calico.CNIConfig{
5961
GlobalOptions: globalOptions,
6062
},
61-
ciliumCNIConfig: &cilium.CNIConfig{GlobalOptions: globalOptions},
62-
nfdConfig: nfd.NewConfig(globalOptions),
63-
clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions},
64-
ebsConfig: awsebs.NewConfig(globalOptions),
65-
awsccmConfig: awsccm.NewConfig(globalOptions),
66-
nutanixCSIConfig: nutanixcsi.NewConfig(globalOptions),
67-
nutanixCCMConfig: &nutanixccm.Config{GlobalOptions: globalOptions},
68-
metalLBConfig: &metallb.Config{GlobalOptions: globalOptions},
69-
localPathCSIConfig: localpath.NewConfig(globalOptions),
70-
snapshotControllerConfig: snapshotcontroller.NewConfig(globalOptions),
71-
cosiControllerConfig: cosi.NewControllerConfig(globalOptions),
72-
distributionConfig: &cncfdistribution.Config{GlobalOptions: globalOptions},
63+
ciliumCNIConfig: &cilium.CNIConfig{GlobalOptions: globalOptions},
64+
nfdConfig: nfd.NewConfig(globalOptions),
65+
clusterAutoscalerConfig: &clusterautoscaler.Config{GlobalOptions: globalOptions},
66+
ebsConfig: awsebs.NewConfig(globalOptions),
67+
awsccmConfig: awsccm.NewConfig(globalOptions),
68+
awsLoadBalancerControllerConfig: awsloadbalancercontroller.NewControllerConfig(globalOptions),
69+
nutanixCSIConfig: nutanixcsi.NewConfig(globalOptions),
70+
nutanixCCMConfig: &nutanixccm.Config{GlobalOptions: globalOptions},
71+
metalLBConfig: &metallb.Config{GlobalOptions: globalOptions},
72+
localPathCSIConfig: localpath.NewConfig(globalOptions),
73+
snapshotControllerConfig: snapshotcontroller.NewConfig(globalOptions),
74+
cosiControllerConfig: cosi.NewControllerConfig(globalOptions),
75+
distributionConfig: &cncfdistribution.Config{GlobalOptions: globalOptions},
7376
}
7477
}
7578

@@ -127,6 +130,7 @@ func (h *Handlers) AllHandlers(mgr manager.Manager) []handlers.Named {
127130
csi.New(mgr.GetClient(), csiHandlers),
128131
snapshotcontroller.New(mgr.GetClient(), h.snapshotControllerConfig, helmChartInfoGetter),
129132
cosi.New(mgr.GetClient(), h.cosiControllerConfig, helmChartInfoGetter),
133+
awsloadbalancercontroller.New(mgr.GetClient(), h.awsLoadBalancerControllerConfig, helmChartInfoGetter),
130134
servicelbgc.New(mgr.GetClient()),
131135
registry.New(mgr.GetClient(), registryHandlers),
132136
// The order of the handlers in the list is important and are called consecutively.

0 commit comments

Comments
 (0)