Skip to content

Commit 571fd86

Browse files
authored
Merge pull request #6171 from killianmuldoon/variables/net-builtins
🌱 Add network builtins to topology controller
2 parents 1fecf7c + cc46204 commit 571fd86

File tree

6 files changed

+248
-6
lines changed

6 files changed

+248
-6
lines changed

docs/book/src/tasks/experimental-features/cluster-class/write-clusterclass.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,7 @@ In addition to variables specified in the ClusterClass, the following builtin va
382382
referenced in patches:
383383
- `builtin.cluster.{name,namespace}`
384384
- `builtin.cluster.topology.{version,class}`
385+
- `builtin.cluster.network.{serviceDomain,services,pods,ipFamily}`
385386
- `builtin.controlPlane.{replicas,version,name}`
386387
- Please note, these variables are only available when patching control plane or control plane
387388
machine templates.

docs/proposals/202105256-cluster-class-and-managed-topologies.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,7 @@ Note: Builtin variables are defined in [Builtin variables](#builtin-variables) b
649649
It’s also possible to use so-called builtin variables in addition to user-defined variables. The following builtin variables are available:
650650
- `builtin.cluster.{name,namespace}`
651651
- `builtin.cluster.topology.{version,class}`
652+
- `builtin.cluster.network.{serviceDomain,services,pods,ipFamily}`
652653
- `builtin.controlPlane.{replicas,version,name}`
653654
- **Note**: these variables are only available when patching control plane or control plane machine templates.
654655
- `builtin.controlPlane.machineTemplate.infrastructureRef.name`

internal/controllers/topology/cluster/patches/engine_test.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,19 @@ func setupTestObjects() (*scope.ClusterBlueprint, *scope.ClusterState) {
476476
Namespace: metav1.NamespaceDefault,
477477
},
478478
Spec: clusterv1.ClusterSpec{
479+
Paused: false,
480+
ClusterNetwork: &clusterv1.ClusterNetwork{
481+
APIServerPort: pointer.Int32(8),
482+
Services: &clusterv1.NetworkRanges{
483+
CIDRBlocks: []string{"10.10.10.1/24"},
484+
},
485+
Pods: &clusterv1.NetworkRanges{
486+
CIDRBlocks: []string{"11.10.10.1/24"},
487+
},
488+
ServiceDomain: "lark",
489+
},
490+
ControlPlaneRef: nil,
491+
InfrastructureRef: nil,
479492
Topology: &clusterv1.Topology{
480493
Version: "v1.21.2",
481494
Class: clusterClass.Name,

internal/controllers/topology/cluster/patches/variables/variables.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ type ClusterBuiltins struct {
5151

5252
// Topology represents the cluster topology variables.
5353
Topology *ClusterTopologyBuiltins `json:"topology,omitempty"`
54+
55+
// Network represents the cluster network variables.
56+
Network *ClusterNetworkBuiltins `json:"network,omitempty"`
5457
}
5558

5659
// ClusterTopologyBuiltins represents builtin cluster topology variables.
@@ -64,6 +67,18 @@ type ClusterTopologyBuiltins struct {
6467
Class string `json:"class,omitempty"`
6568
}
6669

70+
// ClusterNetworkBuiltins represents builtin cluster network variables.
71+
type ClusterNetworkBuiltins struct {
72+
// ServiceDomain is the domain name for services.
73+
ServiceDomain *string `json:"serviceDomain,omitempty"`
74+
// Services is the network ranges from which service VIPs are allocated.
75+
Services []string `json:"services,omitempty"`
76+
// Pods is the network ranges from which Pod networks are allocated.
77+
Pods []string `json:"pods,omitempty"`
78+
// IPFamily is the IPFamily the Cluster is operating in. One of Invalid, IPv4, IPv6, DualStack.
79+
IPFamily string `json:"ipFamily,omitempty"`
80+
}
81+
6782
// ControlPlaneBuiltins represents builtin ControlPlane variables.
6883
// NOTE: These variables are only set for templates belonging to the ControlPlane object.
6984
type ControlPlaneBuiltins struct {
@@ -176,6 +191,24 @@ func Global(clusterTopology *clusterv1.Topology, cluster *clusterv1.Cluster) (Va
176191
},
177192
},
178193
}
194+
if cluster.Spec.ClusterNetwork != nil {
195+
clusterNetworkIPFamily, err := cluster.GetIPFamily()
196+
if err != nil {
197+
return nil, err
198+
}
199+
builtin.Cluster.Network = &ClusterNetworkBuiltins{
200+
IPFamily: ipFamilyToString(clusterNetworkIPFamily),
201+
}
202+
if cluster.Spec.ClusterNetwork.ServiceDomain != "" {
203+
builtin.Cluster.Network.ServiceDomain = &cluster.Spec.ClusterNetwork.ServiceDomain
204+
}
205+
if cluster.Spec.ClusterNetwork.Services != nil && cluster.Spec.ClusterNetwork.Services.CIDRBlocks != nil {
206+
builtin.Cluster.Network.Services = cluster.Spec.ClusterNetwork.Services.CIDRBlocks
207+
}
208+
if cluster.Spec.ClusterNetwork.Pods != nil && cluster.Spec.ClusterNetwork.Pods.CIDRBlocks != nil {
209+
builtin.Cluster.Network.Pods = cluster.Spec.ClusterNetwork.Pods.CIDRBlocks
210+
}
211+
}
179212

180213
// Add builtin variables derived from the cluster object.
181214
if err := setVariable(variables, BuiltinsName, builtin); err != nil {
@@ -284,3 +317,16 @@ func setVariable(variables VariableMap, name string, value interface{}) error {
284317
variables[name] = apiextensionsv1.JSON{Raw: marshalledValue}
285318
return nil
286319
}
320+
321+
func ipFamilyToString(ipFamily clusterv1.ClusterIPFamily) string {
322+
switch ipFamily {
323+
case clusterv1.DualStackIPFamily:
324+
return "DualStack"
325+
case clusterv1.IPv4IPFamily:
326+
return "IPv4"
327+
case clusterv1.IPv6IPFamily:
328+
return "IPv6"
329+
default:
330+
return "Invalid"
331+
}
332+
}

internal/controllers/topology/cluster/patches/variables/variables_test.go

Lines changed: 180 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,15 @@ func TestGlobal(t *testing.T) {
6868
Class: "clusterClass1",
6969
Version: "v1.21.1",
7070
},
71+
ClusterNetwork: &clusterv1.ClusterNetwork{
72+
Services: &clusterv1.NetworkRanges{
73+
CIDRBlocks: []string{"10.10.10.1/24"},
74+
},
75+
Pods: &clusterv1.NetworkRanges{
76+
CIDRBlocks: []string{"11.10.10.1/24"},
77+
},
78+
ServiceDomain: "cluster.local",
79+
},
7180
},
7281
},
7382
want: VariableMap{
@@ -76,11 +85,177 @@ func TestGlobal(t *testing.T) {
7685
BuiltinsName: toJSONCompact(`{
7786
"cluster":{
7887
"name": "cluster1",
79-
"namespace": "default",
80-
"topology":{
81-
"version": "v1.21.1",
82-
"class": "clusterClass1"
83-
}
88+
"namespace": "default",
89+
"topology":{
90+
"version": "v1.21.1",
91+
"class": "clusterClass1"
92+
},
93+
"network":{
94+
"serviceDomain":"cluster.local",
95+
"services":["10.10.10.1/24"],
96+
"pods":["11.10.10.1/24"],
97+
"ipFamily": "IPv4"
98+
}}}`,
99+
),
100+
},
101+
},
102+
{
103+
name: "Should calculate when serviceDomain is not set",
104+
clusterTopology: &clusterv1.Topology{
105+
Variables: []clusterv1.ClusterVariable{
106+
{
107+
Name: "location",
108+
Value: toJSON("\"us-central\""),
109+
},
110+
{
111+
Name: "cpu",
112+
Value: toJSON("8"),
113+
},
114+
{
115+
// This is blocked by a webhook, but let's make sure that the user-defined
116+
// variable is overwritten by the builtin variable anyway.
117+
Name: "builtin",
118+
Value: toJSON("8"),
119+
},
120+
},
121+
},
122+
cluster: &clusterv1.Cluster{
123+
ObjectMeta: metav1.ObjectMeta{
124+
Name: "cluster1",
125+
Namespace: metav1.NamespaceDefault,
126+
},
127+
Spec: clusterv1.ClusterSpec{
128+
Topology: &clusterv1.Topology{
129+
Class: "clusterClass1",
130+
Version: "v1.21.1",
131+
},
132+
ClusterNetwork: &clusterv1.ClusterNetwork{
133+
Services: &clusterv1.NetworkRanges{
134+
CIDRBlocks: []string{"10.10.10.1/24"},
135+
},
136+
Pods: &clusterv1.NetworkRanges{
137+
CIDRBlocks: []string{"11.10.10.1/24"},
138+
},
139+
},
140+
},
141+
},
142+
want: VariableMap{
143+
"location": toJSON("\"us-central\""),
144+
"cpu": toJSON("8"),
145+
BuiltinsName: toJSONCompact(`{
146+
"cluster":{
147+
"name": "cluster1",
148+
"namespace": "default",
149+
"topology":{
150+
"version": "v1.21.1",
151+
"class": "clusterClass1"
152+
},
153+
"network":{
154+
"services":["10.10.10.1/24"],
155+
"pods":["11.10.10.1/24"],
156+
"ipFamily": "IPv4"
157+
}}}`,
158+
),
159+
},
160+
},
161+
{
162+
name: "Should calculate where some variables are nil",
163+
clusterTopology: &clusterv1.Topology{
164+
Variables: []clusterv1.ClusterVariable{
165+
{
166+
Name: "location",
167+
Value: toJSON("\"us-central\""),
168+
},
169+
{
170+
Name: "cpu",
171+
Value: toJSON("8"),
172+
},
173+
{
174+
// This is blocked by a webhook, but let's make sure that the user-defined
175+
// variable is overwritten by the builtin variable anyway.
176+
Name: "builtin",
177+
Value: toJSON("8"),
178+
},
179+
},
180+
},
181+
cluster: &clusterv1.Cluster{
182+
ObjectMeta: metav1.ObjectMeta{
183+
Name: "cluster1",
184+
Namespace: metav1.NamespaceDefault,
185+
},
186+
Spec: clusterv1.ClusterSpec{
187+
Topology: &clusterv1.Topology{
188+
Class: "clusterClass1",
189+
Version: "v1.21.1",
190+
},
191+
ClusterNetwork: &clusterv1.ClusterNetwork{
192+
Services: nil,
193+
Pods: &clusterv1.NetworkRanges{},
194+
ServiceDomain: "cluster.local",
195+
},
196+
},
197+
},
198+
want: VariableMap{
199+
"location": toJSON("\"us-central\""),
200+
"cpu": toJSON("8"),
201+
BuiltinsName: toJSONCompact(`{
202+
"cluster":{
203+
"name": "cluster1",
204+
"namespace": "default",
205+
"topology":{
206+
"version": "v1.21.1",
207+
"class": "clusterClass1"
208+
},
209+
"network":{
210+
"serviceDomain":"cluster.local",
211+
"ipFamily": "IPv4"
212+
}}}`),
213+
},
214+
},
215+
{
216+
name: "Should calculate where ClusterNetwork is nil",
217+
clusterTopology: &clusterv1.Topology{
218+
Variables: []clusterv1.ClusterVariable{
219+
{
220+
Name: "location",
221+
Value: toJSON("\"us-central\""),
222+
},
223+
{
224+
Name: "cpu",
225+
Value: toJSON("8"),
226+
},
227+
{
228+
// This is blocked by a webhook, but let's make sure that the user-defined
229+
// variable is overwritten by the builtin variable anyway.
230+
Name: "builtin",
231+
Value: toJSON("8"),
232+
},
233+
},
234+
},
235+
cluster: &clusterv1.Cluster{
236+
ObjectMeta: metav1.ObjectMeta{
237+
Name: "cluster1",
238+
Namespace: metav1.NamespaceDefault,
239+
},
240+
Spec: clusterv1.ClusterSpec{
241+
Topology: &clusterv1.Topology{
242+
Class: "clusterClass1",
243+
Version: "v1.21.1",
244+
},
245+
ClusterNetwork: nil,
246+
},
247+
},
248+
want: VariableMap{
249+
"location": toJSON("\"us-central\""),
250+
"cpu": toJSON("8"),
251+
BuiltinsName: toJSONCompact(`{
252+
"cluster":{
253+
"name": "cluster1",
254+
"namespace": "default",
255+
"topology":{
256+
"version": "v1.21.1",
257+
"class": "clusterClass1"
258+
}
84259
}}`),
85260
},
86261
},
@@ -417,7 +592,6 @@ func toJSON(value string) apiextensionsv1.JSON {
417592
return apiextensionsv1.JSON{Raw: []byte(value)}
418593
}
419594

420-
// toJSONCompact is used to be able to write JSON values in a readable manner.
421595
func toJSONCompact(value string) apiextensionsv1.JSON {
422596
var compactValue bytes.Buffer
423597
if err := json.Compact(&compactValue, []byte(value)); err != nil {

internal/webhooks/patch_validation.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,13 @@ var builtinVariables = sets.NewString(
336336
"builtin.cluster.topology.class",
337337
"builtin.cluster.topology.version",
338338

339+
// ClusterNetwork builtins
340+
"builtin.cluster.network",
341+
"builtin.cluster.network.serviceDomain",
342+
"builtin.cluster.network.services",
343+
"builtin.cluster.network.pods",
344+
"builtin.cluster.network.ipFamily",
345+
339346
// ControlPlane builtins.
340347
"builtin.controlPlane",
341348
"builtin.controlPlane.name",

0 commit comments

Comments
 (0)