Skip to content

Commit b3559e7

Browse files
committed
feat: add control-plane load balancer scheme patch
1 parent d070314 commit b3559e7

File tree

8 files changed

+349
-3
lines changed

8 files changed

+349
-3
lines changed

api/v1alpha1/aws_clusterconfig_types.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ package v1alpha1
55

66
import (
77
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
8+
9+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/variables"
10+
capav1 "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
811
)
912

1013
type AWSSpec struct {
@@ -13,6 +16,8 @@ type AWSSpec struct {
1316
Region *Region `json:"region,omitempty"`
1417
// +optional
1518
Network *AWSNetwork `json:"network,omitempty"`
19+
// +optional
20+
ControlPlaneLoadBalancer *AWSLoadBalancerSpec `json:"controlPlaneLoadBalancer,omitempty"`
1621
}
1722

1823
func (AWSSpec) VariableSchema() clusterv1.VariableSchema {
@@ -21,8 +26,9 @@ func (AWSSpec) VariableSchema() clusterv1.VariableSchema {
2126
Description: "AWS cluster configuration",
2227
Type: "object",
2328
Properties: map[string]clusterv1.JSONSchemaProps{
24-
"region": Region("").VariableSchema().OpenAPIV3Schema,
25-
"network": AWSNetwork{}.VariableSchema().OpenAPIV3Schema,
29+
"region": Region("").VariableSchema().OpenAPIV3Schema,
30+
"network": AWSNetwork{}.VariableSchema().OpenAPIV3Schema,
31+
"controlPlaneLoadBalancer": AWSLoadBalancerSpec{}.VariableSchema().OpenAPIV3Schema,
2632
},
2733
},
2834
}
@@ -114,3 +120,30 @@ func (SubnetSpec) VariableSchema() clusterv1.VariableSchema {
114120
},
115121
}
116122
}
123+
124+
// AWSLoadBalancerSpec configures an AWS control-plane LoadBalancer.
125+
type AWSLoadBalancerSpec struct {
126+
// Scheme sets the scheme of the load balancer (defaults to internet-facing)
127+
// +kubebuilder:default=internet-facing
128+
// +kubebuilder:validation:Enum=internet-facing;internal
129+
// +optional
130+
Scheme *capav1.ELBScheme `json:"scheme,omitempty"`
131+
}
132+
133+
func (AWSLoadBalancerSpec) VariableSchema() clusterv1.VariableSchema {
134+
supportedScheme := []capav1.ELBScheme{capav1.ELBSchemeInternetFacing, capav1.ELBSchemeInternal}
135+
136+
return clusterv1.VariableSchema{
137+
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
138+
Description: "AWS control-plane LoadBalancer configuration",
139+
Type: "object",
140+
Properties: map[string]clusterv1.JSONSchemaProps{
141+
"scheme": {
142+
Description: "Scheme sets the scheme of the load balancer (defaults to internet-facing)",
143+
Type: "string",
144+
Enum: variables.MustMarshalValuesToEnumJSON(supportedScheme...),
145+
},
146+
},
147+
},
148+
}
149+
}

api/v1alpha1/zz_generated.deepcopy.go

Lines changed: 27 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
+++
2+
title = "Control Plane Load Balancer"
3+
+++
4+
5+
The control-plane load balancer customization allows the user
6+
to modify the load balancer configuration for the control-plane's API server.
7+
8+
This customization will be available when the
9+
[provider-specific cluster configuration patch]({{< ref "..">}}) is included in the `ClusterClass`.
10+
11+
## Example
12+
13+
To use an internal ELB scheme, use the following configuration:
14+
15+
```yaml
16+
apiVersion: cluster.x-k8s.io/v1beta1
17+
kind: Cluster
18+
metadata:
19+
name: <NAME>
20+
spec:
21+
topology:
22+
variables:
23+
- name: clusterConfig
24+
value:
25+
aws:
26+
controlPlaneLoadBalancer:
27+
scheme: internal
28+
```
29+
30+
Applying this configuration will result in the following value being set:
31+
32+
- `AWSClusterTemplate`:
33+
34+
- ```yaml
35+
spec:
36+
controlPlaneLoadBalancer:
37+
scheme: internal
38+
```
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package controlplaneloadbalancer
5+
6+
import (
7+
"context"
8+
_ "embed"
9+
10+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
11+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
12+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
13+
ctrl "sigs.k8s.io/controller-runtime"
14+
"sigs.k8s.io/controller-runtime/pkg/client"
15+
16+
"github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1"
17+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/patches"
18+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/patches/selectors"
19+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/variables"
20+
capav1 "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
21+
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/clusterconfig"
22+
)
23+
24+
const (
25+
// VariableName is the external patch variable name.
26+
VariableName = "controlPlaneLoadBalancer"
27+
)
28+
29+
type awsControlPlaneLoadBalancer struct {
30+
variableName string
31+
variableFieldPath []string
32+
}
33+
34+
func NewPatch() *awsControlPlaneLoadBalancer {
35+
return newAWSControlPlaneLoadBalancer(
36+
clusterconfig.MetaVariableName,
37+
v1alpha1.AWSVariableName,
38+
VariableName,
39+
)
40+
}
41+
42+
func newAWSControlPlaneLoadBalancer(
43+
variableName string,
44+
variableFieldPath ...string,
45+
) *awsControlPlaneLoadBalancer {
46+
return &awsControlPlaneLoadBalancer{
47+
variableName: variableName,
48+
variableFieldPath: variableFieldPath,
49+
}
50+
}
51+
52+
func (h *awsControlPlaneLoadBalancer) Mutate(
53+
ctx context.Context,
54+
obj *unstructured.Unstructured,
55+
vars map[string]apiextensionsv1.JSON,
56+
holderRef runtimehooksv1.HolderReference,
57+
_ client.ObjectKey,
58+
) error {
59+
log := ctrl.LoggerFrom(ctx).WithValues(
60+
"holderRef", holderRef,
61+
)
62+
63+
controlPlaneLoadBalancerVar, found, err := variables.Get[v1alpha1.AWSLoadBalancerSpec](
64+
vars,
65+
h.variableName,
66+
h.variableFieldPath...,
67+
)
68+
if err != nil {
69+
return err
70+
}
71+
if !found {
72+
log.V(5).Info("AWS ControlPlaneLoadBalancer variable not defined")
73+
return nil
74+
}
75+
76+
log = log.WithValues(
77+
"variableName",
78+
h.variableName,
79+
"variableFieldPath",
80+
h.variableFieldPath,
81+
"variableValue",
82+
controlPlaneLoadBalancerVar,
83+
)
84+
85+
return patches.MutateIfApplicable(
86+
obj,
87+
vars,
88+
&holderRef,
89+
selectors.InfrastructureCluster(capav1.GroupVersion.Version, "AWSClusterTemplate"),
90+
log,
91+
func(obj *capav1.AWSClusterTemplate) error {
92+
log.WithValues(
93+
"patchedObjectKind", obj.GetObjectKind().GroupVersionKind().String(),
94+
"patchedObjectName", client.ObjectKeyFromObject(obj),
95+
).Info("setting ControlPlaneLoadBalancer in AWSCluster spec")
96+
97+
controlPlaneLoadBalancer := obj.Spec.Template.Spec.ControlPlaneLoadBalancer
98+
if controlPlaneLoadBalancer == nil {
99+
obj.Spec.Template.Spec.ControlPlaneLoadBalancer = &capav1.AWSLoadBalancerSpec{}
100+
}
101+
obj.Spec.Template.Spec.ControlPlaneLoadBalancer.Scheme = controlPlaneLoadBalancerVar.Scheme
102+
103+
return nil
104+
},
105+
)
106+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package tests
5+
6+
import (
7+
"testing"
8+
9+
"github.com/onsi/gomega"
10+
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
11+
12+
"github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1"
13+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/mutation"
14+
capav1 "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
15+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest"
16+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest/request"
17+
)
18+
19+
func TestGeneratePatches(
20+
t *testing.T,
21+
generatorFunc func() mutation.GeneratePatches,
22+
variableName string,
23+
variablePath ...string,
24+
) {
25+
t.Helper()
26+
27+
capitest.ValidateGeneratePatches(
28+
t,
29+
generatorFunc,
30+
capitest.PatchTestDef{
31+
Name: "unset variable",
32+
},
33+
capitest.PatchTestDef{
34+
Name: "ControlPlaneLoadbalancer scheme set to internet-facing",
35+
Vars: []runtimehooksv1.Variable{
36+
capitest.VariableWithValue(
37+
variableName,
38+
v1alpha1.AWSLoadBalancerSpec{
39+
Scheme: &capav1.ELBSchemeInternetFacing,
40+
},
41+
variablePath...,
42+
),
43+
},
44+
RequestItem: request.NewAWSClusterTemplateRequestItem("1234"),
45+
ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{
46+
Operation: "add",
47+
Path: "/spec/template/spec/controlPlaneLoadBalancer",
48+
ValueMatcher: gomega.HaveKeyWithValue(
49+
"scheme", "internet-facing",
50+
),
51+
}},
52+
},
53+
capitest.PatchTestDef{
54+
Name: "ControlPlaneLoadbalancer scheme set to internal",
55+
Vars: []runtimehooksv1.Variable{
56+
capitest.VariableWithValue(
57+
variableName,
58+
v1alpha1.AWSLoadBalancerSpec{
59+
Scheme: &capav1.ELBSchemeInternal,
60+
},
61+
variablePath...,
62+
),
63+
},
64+
RequestItem: request.NewAWSClusterTemplateRequestItem("1234"),
65+
ExpectedPatchMatchers: []capitest.JSONPatchMatcher{{
66+
Operation: "add",
67+
Path: "/spec/template/spec/controlPlaneLoadBalancer",
68+
ValueMatcher: gomega.HaveKeyWithValue(
69+
"scheme", "internal",
70+
),
71+
}},
72+
},
73+
)
74+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package controlplaneloadbalancer
5+
6+
import (
7+
"testing"
8+
9+
"k8s.io/utils/ptr"
10+
11+
"github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1"
12+
capav1 "github.com/d2iq-labs/capi-runtime-extensions/common/pkg/external/sigs.k8s.io/cluster-api-provider-aws/v2/api/v1beta2"
13+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/testutils/capitest"
14+
awsclusterconfig "github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/aws/clusterconfig"
15+
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/generic/clusterconfig"
16+
)
17+
18+
func TestVariableValidation(t *testing.T) {
19+
capitest.ValidateDiscoverVariables(
20+
t,
21+
clusterconfig.MetaVariableName,
22+
ptr.To(v1alpha1.ClusterConfigSpec{AWS: &v1alpha1.AWSSpec{}}.VariableSchema()),
23+
true,
24+
awsclusterconfig.NewVariable,
25+
capitest.VariableTestDef{
26+
Name: "specified internet-facing scheme",
27+
Vals: v1alpha1.ClusterConfigSpec{
28+
AWS: &v1alpha1.AWSSpec{
29+
ControlPlaneLoadBalancer: &v1alpha1.AWSLoadBalancerSpec{
30+
Scheme: &capav1.ELBSchemeInternetFacing,
31+
},
32+
},
33+
},
34+
},
35+
capitest.VariableTestDef{
36+
Name: "specified internal scheme",
37+
Vals: v1alpha1.ClusterConfigSpec{
38+
AWS: &v1alpha1.AWSSpec{
39+
ControlPlaneLoadBalancer: &v1alpha1.AWSLoadBalancerSpec{
40+
Scheme: &capav1.ELBSchemeInternal,
41+
},
42+
},
43+
},
44+
},
45+
capitest.VariableTestDef{
46+
Name: "specified invalid scheme",
47+
Vals: v1alpha1.ClusterConfigSpec{
48+
AWS: &v1alpha1.AWSSpec{
49+
ControlPlaneLoadBalancer: &v1alpha1.AWSLoadBalancerSpec{
50+
Scheme: ptr.To(capav1.ELBScheme("invalid")),
51+
},
52+
},
53+
},
54+
ExpectError: true,
55+
},
56+
)
57+
}

0 commit comments

Comments
 (0)