Skip to content

Commit 1033e29

Browse files
committed
feat: CNI provider deployment via variables instead of labels
1 parent db1bde1 commit 1033e29

File tree

9 files changed

+149
-41
lines changed

9 files changed

+149
-41
lines changed

api/v1alpha1/clusterconfig_types.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,14 @@ import (
77
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
88
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
99

10+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/variables"
1011
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/openapi/patterns"
1112
)
1213

14+
const (
15+
CNIProviderCalico = "calico"
16+
)
17+
1318
//+kubebuilder:object:root=true
1419

1520
// ClusterConfig is the Schema for the clusterconfigs API.
@@ -30,6 +35,9 @@ type ClusterConfigSpec struct {
3035

3136
// +optional
3237
ExtraAPIServerCertSANs ExtraAPIServerCertSANs `json:"extraAPIServerCertSANs,omitempty"`
38+
39+
// +optional
40+
CNI *CNI `json:"cni,omitempty"`
3341
}
3442

3543
func (ClusterConfigSpec) VariableSchema() clusterv1.VariableSchema {
@@ -40,6 +48,7 @@ func (ClusterConfigSpec) VariableSchema() clusterv1.VariableSchema {
4048
Properties: map[string]clusterv1.JSONSchemaProps{
4149
"proxy": HTTPProxy{}.VariableSchema().OpenAPIV3Schema,
4250
"extraAPIServerCertSANs": ExtraAPIServerCertSANs{}.VariableSchema().OpenAPIV3Schema,
51+
"cni": CNI{}.VariableSchema().OpenAPIV3Schema,
4352
},
4453
},
4554
}
@@ -105,6 +114,33 @@ func (ExtraAPIServerCertSANs) VariableSchema() clusterv1.VariableSchema {
105114
}
106115
}
107116

117+
// CNI required for providing CNI configuration.
118+
type CNI struct {
119+
Provider string `json:"provider,omitempty"`
120+
}
121+
122+
func (CNI) VariableSchema() clusterv1.VariableSchema {
123+
supportedCNIProviders := []string{CNIProviderCalico}
124+
125+
cniProviderEnumVals, err := variables.ValuesToEnumJSON(supportedCNIProviders...)
126+
if err != nil {
127+
panic(err)
128+
}
129+
130+
return clusterv1.VariableSchema{
131+
OpenAPIV3Schema: clusterv1.JSONSchemaProps{
132+
Type: "object",
133+
Properties: map[string]clusterv1.JSONSchemaProps{
134+
"provider": {
135+
Description: "CNI provider to deploy",
136+
Type: "string",
137+
Enum: cniProviderEnumVals,
138+
},
139+
},
140+
},
141+
}
142+
}
143+
108144
// +kubebuilder:object:root=true
109145
func init() {
110146
SchemeBuilder.Register(&ClusterConfig{})

api/v1alpha1/zz_generated.deepcopy.go

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

cmd/main.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ func main() {
115115

116116
servicelbgc.New(mgr.GetClient()),
117117

118-
calico.New(mgr.GetClient(), calicoCNIConfig),
118+
calico.New(mgr.GetClient(), calicoCNIConfig, clusterconfig.VariableName, "cni"),
119119

120120
httpproxy.NewVariable(),
121121
httpproxy.NewPatch(mgr.GetClient(), httpproxy.VariableName),
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package variables
5+
6+
import (
7+
"encoding/json"
8+
"fmt"
9+
10+
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
11+
)
12+
13+
func ValuesToEnumJSON[T any](vals ...T) ([]apiextensionsv1.JSON, error) {
14+
enumJSON := make([]apiextensionsv1.JSON, 0, len(vals))
15+
16+
for _, v := range vals {
17+
enumVal, err := json.Marshal(v)
18+
if err != nil {
19+
return nil, fmt.Errorf("failed to marshal enum value: %v", v)
20+
}
21+
enumJSON = append(enumJSON, apiextensionsv1.JSON{Raw: enumVal})
22+
}
23+
24+
return enumJSON, nil
25+
}

common/pkg/capi/clustertopology/variables/variable.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88

99
apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
1010
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
11+
"sigs.k8s.io/cluster-api/api/v1beta1"
1112
"sigs.k8s.io/cluster-api/exp/runtime/topologymutation"
1213
)
1314

@@ -45,3 +46,17 @@ func Get[T any](
4546
err = json.Unmarshal(jsonValue, &value)
4647
return value, err == nil, err
4748
}
49+
50+
// ClusterVariablesToVariablesMap converts a list of ClusterVariables to a map of JSON (name is the map key).
51+
// See: https://github.com/kubernetes-sigs/cluster-api/blob/v1.5.1/internal/controllers/topology/cluster/patches/variables/variables.go#L445
52+
//
53+
//nolint:lll // Long URLs in comments above. Adding nolint:lll here because it doesn't work in comment lines. See: https://github.com/golangci/golangci-lint/issues/3983
54+
func ClusterVariablesToVariablesMap(
55+
variables []v1beta1.ClusterVariable,
56+
) map[string]apiextensionsv1.JSON {
57+
variablesMap := map[string]apiextensionsv1.JSON{}
58+
for i := range variables {
59+
variablesMap[variables[i].Name] = variables[i].Value
60+
}
61+
return variablesMap
62+
}

examples/capi-quick-start/capd-cluster.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44
apiVersion: cluster.x-k8s.io/v1beta1
55
kind: Cluster
66
metadata:
7-
labels:
8-
capiext.labs.d2iq.io/cni: calico
97
name: capd-quick-start
108
spec:
119
clusterNetwork:
@@ -23,7 +21,9 @@ spec:
2321
replicas: 1
2422
variables:
2523
- name: clusterConfig
26-
value: {}
24+
value:
25+
cni:
26+
provider: calico
2727
version: v1.27.5
2828
workers:
2929
machineDeployments:

hack/examples/kustomization.yaml.tmpl

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,6 @@ patches:
8686
path: "/spec/topology/variables"
8787
value:
8888
- name: "clusterConfig"
89-
value: {}
90-
- op: "add"
91-
path: "/metadata/labels"
92-
value:
93-
capiext.labs.d2iq.io/cni: calico
89+
value:
90+
cni:
91+
provider: calico

pkg/handlers/cni/calico/handler.go

Lines changed: 46 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23,17 +23,15 @@ import (
2323
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
2424
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2525

26+
"github.com/d2iq-labs/capi-runtime-extensions/api/v1alpha1"
2627
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers"
2728
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/handlers/lifecycle"
29+
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/capi/clustertopology/variables"
2830
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/k8s/client"
2931
"github.com/d2iq-labs/capi-runtime-extensions/common/pkg/k8s/parser"
3032
"github.com/d2iq-labs/capi-runtime-extensions/pkg/handlers/cni"
3133
)
3234

33-
const (
34-
CNILabelValue = "calico"
35-
)
36-
3735
type CalicoCNIConfig struct {
3836
defaultsNamespace string
3937

@@ -68,6 +66,9 @@ func (c *CalicoCNIConfig) AddFlags(prefix string, flags *pflag.FlagSet) {
6866
type CalicoCNI struct {
6967
client ctrlclient.Client
7068
config *CalicoCNIConfig
69+
70+
variableName string
71+
variablePath []string
7172
}
7273

7374
var (
@@ -77,10 +78,17 @@ var (
7778
calicoInstallationGK = schema.GroupKind{Group: "operator.tigera.io", Kind: "Installation"}
7879
)
7980

80-
func New(c ctrlclient.Client, cfg *CalicoCNIConfig) *CalicoCNI {
81+
func New(
82+
c ctrlclient.Client,
83+
cfg *CalicoCNIConfig,
84+
variableName string,
85+
variablePath ...string,
86+
) *CalicoCNI {
8187
return &CalicoCNI{
82-
client: c,
83-
config: cfg,
88+
client: c,
89+
config: cfg,
90+
variableName: variableName,
91+
variablePath: variablePath,
8492
}
8593
}
8694

@@ -104,18 +112,34 @@ func (s *CalicoCNI) AfterControlPlaneInitialized(
104112
// will update for failure response properly.
105113
resp.SetStatus(runtimehooksv1.ResponseStatusSuccess)
106114

107-
if v, ok := req.Cluster.GetLabels()[cni.CNIProviderLabelKey]; !ok || v != CNILabelValue {
115+
varMap := variables.ClusterVariablesToVariablesMap(req.Cluster.Spec.Topology.Variables)
116+
117+
cniVar, found, err := variables.Get[v1alpha1.CNI](varMap, s.variableName, s.variablePath...)
118+
if err != nil {
119+
log.Error(
120+
err,
121+
"failed to read CNI provider from cluster definition",
122+
)
123+
resp.SetStatus(runtimehooksv1.ResponseStatusFailure)
124+
resp.SetMessage(
125+
fmt.Sprintf("failed to read CNI provider from cluster definition: %v",
126+
err,
127+
),
128+
)
129+
return
130+
}
131+
if !found || cniVar.Provider != v1alpha1.CNIProviderCalico {
108132
log.V(4).Info(
109133
fmt.Sprintf(
110-
"Skipping Calico CNI handler, cluster does not specify %q as value of CNI provider label %q",
111-
CNILabelValue,
112-
cni.CNIProviderLabelKey,
134+
"Skipping Calico CNI handler, cluster does not specify %q as value of CNI provider variable",
135+
v1alpha1.CNIProviderCalico,
113136
),
114137
)
115138
return
116139
}
117140

118-
defaultInstallationConfigMapName, ok := s.config.defaultProviderInstallationConfigMapNames[req.Cluster.Spec.InfrastructureRef.Kind] //nolint:lll // Just a long line...
141+
infraKind := req.Cluster.Spec.InfrastructureRef.Kind
142+
defaultInstallationConfigMapName, ok := s.config.defaultProviderInstallationConfigMapNames[infraKind]
119143
if !ok {
120144
log.V(4).Info(
121145
fmt.Sprintf(
@@ -136,7 +160,7 @@ func (s *CalicoCNI) AfterControlPlaneInitialized(
136160
defaultTigeraOperatorConfigMapObjName := ctrlclient.ObjectKeyFromObject(
137161
defaultTigeraOperatorConfigMap,
138162
)
139-
err := s.client.Get(ctx, defaultTigeraOperatorConfigMapObjName, defaultTigeraOperatorConfigMap)
163+
err = s.client.Get(ctx, defaultTigeraOperatorConfigMapObjName, defaultTigeraOperatorConfigMap)
140164
if err != nil {
141165
log.Error(
142166
err,
@@ -219,7 +243,7 @@ func generateTigeraOperatorCRS(
219243
Kind: "ConfigMap",
220244
},
221245
ObjectMeta: metav1.ObjectMeta{
222-
Namespace: cluster.GetNamespace(),
246+
Namespace: cluster.Namespace,
223247
Name: defaultTigeraOperatorConfigMap.Name,
224248
},
225249
Data: defaultTigeraOperatorConfigMap.Data,
@@ -232,17 +256,17 @@ func generateTigeraOperatorCRS(
232256
Kind: "ClusterResourceSet",
233257
},
234258
ObjectMeta: metav1.ObjectMeta{
235-
Namespace: cluster.GetNamespace(),
236-
Name: namespacedTigeraConfigMap.GetName(),
259+
Namespace: cluster.Namespace,
260+
Name: namespacedTigeraConfigMap.Name,
237261
},
238262
Spec: crsv1.ClusterResourceSetSpec{
239263
Resources: []crsv1.ResourceRef{{
240264
Kind: string(crsv1.ConfigMapClusterResourceSetResourceKind),
241-
Name: namespacedTigeraConfigMap.GetName(),
265+
Name: namespacedTigeraConfigMap.Name,
242266
}},
243267
Strategy: string(crsv1.ClusterResourceSetStrategyReconcile),
244268
ClusterSelector: metav1.LabelSelector{
245-
MatchLabels: map[string]string{cni.CNIProviderLabelKey: CNILabelValue},
269+
MatchLabels: map[string]string{capiv1.ClusterNameLabel: cluster.Name},
246270
},
247271
},
248272
}
@@ -343,17 +367,17 @@ func generateProviderCNICRS(
343367
Kind: "ClusterResourceSet",
344368
},
345369
ObjectMeta: metav1.ObjectMeta{
346-
Namespace: cluster.GetNamespace(),
347-
Name: cm.GetName(),
370+
Namespace: cluster.Namespace,
371+
Name: cm.Name,
348372
},
349373
Spec: crsv1.ClusterResourceSetSpec{
350374
Resources: []crsv1.ResourceRef{{
351375
Kind: string(crsv1.ConfigMapClusterResourceSetResourceKind),
352-
Name: cm.GetName(),
376+
Name: cm.Name,
353377
}},
354378
Strategy: string(crsv1.ClusterResourceSetStrategyReconcile),
355379
ClusterSelector: metav1.LabelSelector{
356-
MatchLabels: map[string]string{capiv1.ClusterNameLabel: cluster.GetName()},
380+
MatchLabels: map[string]string{capiv1.ClusterNameLabel: cluster.Name},
357381
},
358382
},
359383
}

pkg/handlers/cni/constants.go

Lines changed: 0 additions & 10 deletions
This file was deleted.

0 commit comments

Comments
 (0)