Skip to content

Commit de0ed1e

Browse files
authored
Merge pull request #8785 from alexander-demicev/capdloadbalancer
✨ Allow adding custom HA proxy config for CAPD load balancer
2 parents 6762aed + 6ac336a commit de0ed1e

File tree

11 files changed

+384
-49
lines changed

11 files changed

+384
-49
lines changed

test/infrastructure/docker/api/v1alpha3/conversion.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@ func (src *DockerCluster) ConvertTo(dstRaw conversion.Hub) error {
4545
dst.Spec.LoadBalancer.ImageTag = restored.Spec.LoadBalancer.ImageTag
4646
}
4747

48+
if restored.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef != nil {
49+
dst.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef = restored.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef
50+
}
51+
4852
return nil
4953
}
5054

test/infrastructure/docker/api/v1alpha4/conversion.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,35 @@ import (
2727
func (src *DockerCluster) ConvertTo(dstRaw conversion.Hub) error {
2828
dst := dstRaw.(*infrav1.DockerCluster)
2929

30-
return Convert_v1alpha4_DockerCluster_To_v1beta1_DockerCluster(src, dst, nil)
30+
if err := Convert_v1alpha4_DockerCluster_To_v1beta1_DockerCluster(src, dst, nil); err != nil {
31+
return err
32+
}
33+
34+
// Manually restore data.
35+
restored := &infrav1.DockerCluster{}
36+
if ok, err := utilconversion.UnmarshalData(src, restored); err != nil || !ok {
37+
return err
38+
}
39+
40+
if restored.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef != nil {
41+
dst.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef = restored.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef
42+
}
43+
44+
return nil
3145
}
3246

3347
func (dst *DockerCluster) ConvertFrom(srcRaw conversion.Hub) error {
3448
src := srcRaw.(*infrav1.DockerCluster)
3549

36-
return Convert_v1beta1_DockerCluster_To_v1alpha4_DockerCluster(src, dst, nil)
50+
if err := Convert_v1beta1_DockerCluster_To_v1alpha4_DockerCluster(src, dst, nil); err != nil {
51+
return err
52+
}
53+
54+
if err := utilconversion.MarshalData(src, dst); err != nil {
55+
return err
56+
}
57+
58+
return nil
3759
}
3860

3961
func (src *DockerClusterList) ConvertTo(dstRaw conversion.Hub) error {
@@ -63,6 +85,10 @@ func (src *DockerClusterTemplate) ConvertTo(dstRaw conversion.Hub) error {
6385

6486
dst.Spec.Template.ObjectMeta = restored.Spec.Template.ObjectMeta
6587

88+
if restored.Spec.Template.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef != nil {
89+
dst.Spec.Template.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef = restored.Spec.Template.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef
90+
}
91+
6692
return nil
6793
}
6894

@@ -171,3 +197,7 @@ func Convert_v1beta1_DockerMachineTemplateResource_To_v1alpha4_DockerMachineTemp
171197
// NOTE: custom conversion func is required because spec.template.metadata has been added in v1beta1.
172198
return autoConvert_v1beta1_DockerMachineTemplateResource_To_v1alpha4_DockerMachineTemplateResource(in, out, s)
173199
}
200+
201+
func Convert_v1beta1_DockerLoadBalancer_To_v1alpha4_DockerLoadBalancer(in *infrav1.DockerLoadBalancer, out *DockerLoadBalancer, s apiconversion.Scope) error {
202+
return autoConvert_v1beta1_DockerLoadBalancer_To_v1alpha4_DockerLoadBalancer(in, out, s)
203+
}

test/infrastructure/docker/api/v1alpha4/zz_generated.conversion.go

Lines changed: 6 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/infrastructure/docker/api/v1beta1/dockercluster_types.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package v1beta1
1818

1919
import (
20+
corev1 "k8s.io/api/core/v1"
2021
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2122

2223
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
@@ -53,6 +54,17 @@ type DockerClusterSpec struct {
5354
type DockerLoadBalancer struct {
5455
// ImageMeta allows customizing the image used for the cluster load balancer.
5556
ImageMeta `json:",inline"`
57+
58+
// CustomHAProxyConfigTemplateRef allows you to replace the default HAProxy config file.
59+
// This field is a reference to a config map that contains the configuration template. The key of the config map should be equal to 'value'.
60+
// The content of the config map will be processed and will replace the default HAProxy config file. Please use it with caution, as there are
61+
// no checks to ensure the validity of the configuration. This template will support the following variables that will be passed by the controller:
62+
// $IPv6 (bool) indicates if the cluster is IPv6, $FrontendControlPlanePort (string) indicates the frontend control plane port,
63+
// $BackendControlPlanePort (string) indicates the backend control plane port, $BackendServers (map[string]string) indicates the backend server
64+
// where the key is the server name and the value is the address. This map is dynamic and is updated every time a new control plane
65+
// node is added or removed. The template will also support the JoinHostPort function to join the host and port of the backend server.
66+
// +optional
67+
CustomHAProxyConfigTemplateRef *corev1.LocalObjectReference `json:"customHAProxyConfigTemplateRef,omitempty"`
5668
}
5769

5870
// ImageMeta allows customizing the image used for components that are not

test/infrastructure/docker/api/v1beta1/zz_generated.deepcopy.go

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclusters.yaml

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/infrastructure/docker/config/crd/bases/infrastructure.cluster.x-k8s.io_dockerclustertemplates.yaml

Lines changed: 28 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/infrastructure/docker/internal/controllers/dockermachine_controller.go

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"github.com/pkg/errors"
2626
corev1 "k8s.io/api/core/v1"
2727
apierrors "k8s.io/apimachinery/pkg/api/errors"
28+
"k8s.io/apimachinery/pkg/types"
2829
"k8s.io/klog/v2"
2930
ctrl "sigs.k8s.io/controller-runtime"
3031
"sigs.k8s.io/controller-runtime/pkg/builder"
@@ -167,11 +168,11 @@ func (r *DockerMachineReconciler) Reconcile(ctx context.Context, req ctrl.Reques
167168

168169
// Handle deleted machines
169170
if !dockerMachine.ObjectMeta.DeletionTimestamp.IsZero() {
170-
return ctrl.Result{}, r.reconcileDelete(ctx, machine, dockerMachine, externalMachine, externalLoadBalancer)
171+
return ctrl.Result{}, r.reconcileDelete(ctx, dockerCluster, machine, dockerMachine, externalMachine, externalLoadBalancer)
171172
}
172173

173174
// Handle non-deleted machines
174-
res, err := r.reconcileNormal(ctx, cluster, machine, dockerMachine, externalMachine, externalLoadBalancer)
175+
res, err := r.reconcileNormal(ctx, cluster, dockerCluster, machine, dockerMachine, externalMachine, externalLoadBalancer)
175176
// Requeue if the reconcile failed because the ClusterCacheTracker was locked for
176177
// the current cluster because of concurrent access.
177178
if errors.Is(err, remote.ErrClusterLocked) {
@@ -204,7 +205,7 @@ func patchDockerMachine(ctx context.Context, patchHelper *patch.Helper, dockerMa
204205
)
205206
}
206207

207-
func (r *DockerMachineReconciler) reconcileNormal(ctx context.Context, cluster *clusterv1.Cluster, machine *clusterv1.Machine, dockerMachine *infrav1.DockerMachine, externalMachine *docker.Machine, externalLoadBalancer *docker.LoadBalancer) (res ctrl.Result, retErr error) {
208+
func (r *DockerMachineReconciler) reconcileNormal(ctx context.Context, cluster *clusterv1.Cluster, dockerCluster *infrav1.DockerCluster, machine *clusterv1.Machine, dockerMachine *infrav1.DockerMachine, externalMachine *docker.Machine, externalLoadBalancer *docker.LoadBalancer) (res ctrl.Result, retErr error) {
208209
log := ctrl.LoggerFrom(ctx)
209210

210211
// Check if the infrastructure is ready, otherwise return and wait for the cluster object to be updated
@@ -271,7 +272,11 @@ func (r *DockerMachineReconciler) reconcileNormal(ctx context.Context, cluster *
271272
// we should only do this once, as reconfiguration more or less ensures
272273
// node ref setting fails
273274
if util.IsControlPlaneMachine(machine) && !dockerMachine.Status.LoadBalancerConfigured {
274-
if err := externalLoadBalancer.UpdateConfiguration(ctx); err != nil {
275+
unsafeLoadBalancerConfigTemplate, err := r.getUnsafeLoadBalancerConfigTemplate(ctx, dockerCluster)
276+
if err != nil {
277+
return ctrl.Result{}, errors.Wrap(err, "failed to retrieve HAProxy configuration from CustomHAProxyConfigTemplateRef")
278+
}
279+
if err := externalLoadBalancer.UpdateConfiguration(ctx, unsafeLoadBalancerConfigTemplate); err != nil {
275280
return ctrl.Result{}, errors.Wrap(err, "failed to update DockerCluster.loadbalancer configuration")
276281
}
277282
dockerMachine.Status.LoadBalancerConfigured = true
@@ -390,7 +395,7 @@ func (r *DockerMachineReconciler) reconcileNormal(ctx context.Context, cluster *
390395
return ctrl.Result{}, nil
391396
}
392397

393-
func (r *DockerMachineReconciler) reconcileDelete(ctx context.Context, machine *clusterv1.Machine, dockerMachine *infrav1.DockerMachine, externalMachine *docker.Machine, externalLoadBalancer *docker.LoadBalancer) error {
398+
func (r *DockerMachineReconciler) reconcileDelete(ctx context.Context, dockerCluster *infrav1.DockerCluster, machine *clusterv1.Machine, dockerMachine *infrav1.DockerMachine, externalMachine *docker.Machine, externalLoadBalancer *docker.LoadBalancer) error {
394399
// Set the ContainerProvisionedCondition reporting delete is started, and issue a patch in order to make
395400
// this visible to the users.
396401
// NB. The operation in docker is fast, so there is the chance the user will not notice the status change;
@@ -411,7 +416,11 @@ func (r *DockerMachineReconciler) reconcileDelete(ctx context.Context, machine *
411416

412417
// if the deleted machine is a control-plane node, remove it from the load balancer configuration;
413418
if util.IsControlPlaneMachine(machine) {
414-
if err := externalLoadBalancer.UpdateConfiguration(ctx); err != nil {
419+
unsafeLoadBalancerConfigTemplate, err := r.getUnsafeLoadBalancerConfigTemplate(ctx, dockerCluster)
420+
if err != nil {
421+
return errors.Wrap(err, "failed to retrieve HAProxy configuration from CustomHAProxyConfigTemplateRef")
422+
}
423+
if err := externalLoadBalancer.UpdateConfiguration(ctx, unsafeLoadBalancerConfigTemplate); err != nil {
415424
return errors.Wrap(err, "failed to update DockerCluster.loadbalancer configuration")
416425
}
417426
}
@@ -510,6 +519,25 @@ func (r *DockerMachineReconciler) getBootstrapData(ctx context.Context, machine
510519
return base64.StdEncoding.EncodeToString(value), bootstrapv1.Format(format), nil
511520
}
512521

522+
func (r *DockerMachineReconciler) getUnsafeLoadBalancerConfigTemplate(ctx context.Context, dockerCluster *infrav1.DockerCluster) (string, error) {
523+
if dockerCluster.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef == nil {
524+
return "", nil
525+
}
526+
var cm *corev1.ConfigMap
527+
key := types.NamespacedName{
528+
Name: dockerCluster.Spec.LoadBalancer.CustomHAProxyConfigTemplateRef.Name,
529+
Namespace: dockerCluster.Namespace,
530+
}
531+
if err := r.Get(ctx, key, cm); err != nil {
532+
return "", errors.Wrapf(err, "failed to retrieve custom HAProxy configuration ConfigMap %s", key)
533+
}
534+
template, ok := cm.Data["value"]
535+
if !ok {
536+
return "", fmt.Errorf("expected key \"value\" to exist in ConfigMap %s", key)
537+
}
538+
return template, nil
539+
}
540+
513541
// setMachineAddress gets the address from the container corresponding to a docker node and sets it on the Machine object.
514542
func setMachineAddress(ctx context.Context, dockerMachine *infrav1.DockerMachine, externalMachine *docker.Machine) error {
515543
machineAddresses, err := externalMachine.Address(ctx)

0 commit comments

Comments
 (0)