Skip to content
This repository was archived by the owner on Apr 11, 2024. It is now read-only.

Commit bb59ff1

Browse files
committed
refactor: deploy storage class as a cluster resource set
1 parent 478110f commit bb59ff1

File tree

5 files changed

+185
-52
lines changed

5 files changed

+185
-52
lines changed

api/v1alpha1/clusterconfig_types.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@ import (
1414
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/openapi/patterns"
1515
)
1616

17+
type StorageDriver string
18+
1719
const (
18-
CNIProviderCalico = "Calico"
19-
CNIProviderCilium = "Cilium"
20+
CNIProviderCalico = "Calico"
21+
CNIProviderCilium = "Cilium"
22+
AWSEBSDriver StorageDriver = "ebs.csi.aws.com"
23+
NutanixDriver StorageDriver = "csi.nutanix.com"
2024

2125
CSIProviderAWSEBS = "aws-ebs"
2226
CSIProviderNutanix = "nutanix"

pkg/handlers/generic/lifecycle/csi/aws-ebs/handler.go

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"github.com/spf13/pflag"
1111
corev1 "k8s.io/api/core/v1"
1212
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
13+
"k8s.io/apimachinery/pkg/runtime"
1314
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
1415
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
1516
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -20,10 +21,6 @@ import (
2021
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options"
2122
)
2223

23-
const (
24-
awsEBSProvisionerName = "ebs.csi.aws.com"
25-
)
26-
2724
type AWSEBSConfig struct {
2825
*options.GlobalOptions
2926
defaultAWSEBSConfigMapName string
@@ -83,23 +80,33 @@ func (a *AWSEBS) createStorageClasses(ctx context.Context,
8380
cluster *clusterv1.Cluster,
8481
defaultStorageConfig *v1alpha1.DefaultStorage,
8582
) error {
83+
allStorageClasses := make([]runtime.Object, 0, len(configs))
8684
for _, c := range configs {
8785
setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName &&
8886
v1alpha1.CSIProviderAWSEBS == defaultStorageConfig.ProviderName
89-
err := lifecycleutils.CreateStorageClass(
90-
ctx,
91-
a.client,
87+
allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass(
9288
c,
9389
cluster,
9490
a.config.GlobalOptions.DefaultsNamespace(),
95-
awsEBSProvisionerName,
91+
v1alpha1.CSIProviderAWSEBS,
9692
setAsDefault,
97-
)
98-
if err != nil {
99-
return fmt.Errorf("failed to create storageclass %w", err)
100-
}
93+
))
10194
}
102-
return nil
95+
cm, err := lifecycleutils.CreateConfigMapForCRS(
96+
"aws-storageclass-cm",
97+
a.config.DefaultsNamespace(),
98+
allStorageClasses...,
99+
)
100+
if err != nil {
101+
return err
102+
}
103+
return lifecycleutils.EnsureCRSForClusterFromConfigMaps(
104+
ctx,
105+
"aws-storageclass-crs",
106+
a.client,
107+
cluster,
108+
cm,
109+
)
103110
}
104111

105112
func (a *AWSEBS) handleCRSApply(ctx context.Context,

pkg/handlers/generic/lifecycle/csi/nutanix-csi/handler.go

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99

1010
"github.com/spf13/pflag"
1111
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/runtime"
1213
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
1314
runtimehooksv1 "sigs.k8s.io/cluster-api/exp/runtime/hooks/api/v1alpha1"
1415
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
@@ -17,7 +18,7 @@ import (
1718
caaphv1 "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/external/sigs.k8s.io/cluster-api-addon-provider-helm/api/v1alpha1"
1819
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/api/v1alpha1"
1920
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/common/pkg/k8s/client"
20-
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils"
21+
lifecycleutils "github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/generic/lifecycle/utils"
2122
"github.com/d2iq-labs/cluster-api-runtime-extensions-nutanix/pkg/handlers/options"
2223
)
2324

@@ -26,7 +27,6 @@ const (
2627
defaultHelmChartVersion = "v2.6.6"
2728
defaultHelmChartName = "nutanix-csi-storage"
2829
defaultHelmReleaseNameTemplate = "nutanix-csi-storage-%s"
29-
nutanixCSIProvisionerName = "csi.nutanix.com"
3030
)
3131

3232
type NutanixCSIConfig struct {
@@ -87,7 +87,7 @@ func (n *NutanixCSI) handleHelmAddonApply(
8787
ctx context.Context,
8888
req *runtimehooksv1.AfterControlPlaneInitializedRequest,
8989
) error {
90-
valuesTemplateConfigMap, err := utils.RetrieveValuesTemplateConfigMap(ctx,
90+
valuesTemplateConfigMap, err := lifecycleutils.RetrieveValuesTemplateConfigMap(ctx,
9191
n.client,
9292
n.config.defaultValuesTemplateConfigMapName,
9393
n.config.DefaultsNamespace())
@@ -140,21 +140,31 @@ func (n *NutanixCSI) createStorageClasses(ctx context.Context,
140140
cluster *clusterv1.Cluster,
141141
defaultStorageConfig *v1alpha1.DefaultStorage,
142142
) error {
143+
allStorageClasses := make([]runtime.Object, 0, len(configs))
143144
for _, c := range configs {
144145
setAsDefault := c.Name == defaultStorageConfig.StorageClassConfigName &&
145146
v1alpha1.CSIProviderNutanix == defaultStorageConfig.ProviderName
146-
err := utils.CreateStorageClass(
147-
ctx,
148-
n.client,
147+
allStorageClasses = append(allStorageClasses, lifecycleutils.CreateStorageClass(
149148
c,
150149
cluster,
151-
nutanixCSIProvisionerName,
152150
n.config.GlobalOptions.DefaultsNamespace(),
151+
v1alpha1.NutanixDriver,
153152
setAsDefault,
154-
)
155-
if err != nil {
156-
return fmt.Errorf("failed to create storageclass %w", err)
157-
}
153+
))
158154
}
159-
return nil
155+
cm, err := lifecycleutils.CreateConfigMapForCRS(
156+
"nutanix-storageclass-cm",
157+
n.config.DefaultsNamespace(),
158+
allStorageClasses...,
159+
)
160+
if err != nil {
161+
return err
162+
}
163+
return lifecycleutils.EnsureCRSForClusterFromConfigMaps(
164+
ctx,
165+
"nutanix-storageclass-crs",
166+
n.client,
167+
cluster,
168+
cm,
169+
)
160170
}

pkg/handlers/generic/lifecycle/utils/utils.go

Lines changed: 42 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,12 @@ import (
1111
corev1 "k8s.io/api/core/v1"
1212
storagev1 "k8s.io/api/storage/v1"
1313
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
14+
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
15+
"k8s.io/apimachinery/pkg/runtime"
1416
"k8s.io/utils/ptr"
1517
clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
16-
"sigs.k8s.io/cluster-api/controllers/remote"
1718
crsv1 "sigs.k8s.io/cluster-api/exp/addons/api/v1beta1"
18-
capiutil "sigs.k8s.io/cluster-api/util"
19+
utilyaml "sigs.k8s.io/cluster-api/util/yaml"
1920
ctrlclient "sigs.k8s.io/controller-runtime/pkg/client"
2021
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
2122

@@ -24,7 +25,8 @@ import (
2425
)
2526

2627
const (
27-
kindStorageClass = "StorageClass"
28+
kindStorageClass = "StorageClass"
29+
defaultCRSConfigMapKey = "custom-resources.yaml"
2830
)
2931

3032
var (
@@ -135,20 +137,17 @@ func RetrieveValuesTemplateConfigMap(
135137
}
136138

137139
func CreateStorageClass(
138-
ctx context.Context,
139-
cl ctrlclient.Client,
140140
storageConfig v1alpha1.StorageClassConfig,
141141
cluster *clusterv1.Cluster,
142-
defaultsNamespace,
143-
provisionerName string,
142+
defaultsNamespace string,
143+
provisionerName v1alpha1.StorageDriver,
144144
isDefault bool,
145-
) error {
145+
) *storagev1.StorageClass {
146146
var volumeBindingMode *storagev1.VolumeBindingMode
147147
switch storageConfig.VolumeBindingMode {
148148
case v1alpha1.VolumeBindingImmediate:
149149
volumeBindingMode = ptr.To(storagev1.VolumeBindingImmediate)
150150
case v1alpha1.VolumeBindingWaitForFirstConsumer:
151-
default:
152151
volumeBindingMode = ptr.To(storagev1.VolumeBindingWaitForFirstConsumer)
153152
}
154153
var reclaimPolicy *corev1.PersistentVolumeReclaimPolicy
@@ -173,29 +172,47 @@ func CreateStorageClass(
173172
Name: storageConfig.Name,
174173
Namespace: defaultsNamespace,
175174
},
176-
Provisioner: provisionerName,
175+
Provisioner: string(provisionerName),
177176
Parameters: params,
178177
VolumeBindingMode: volumeBindingMode,
179178
ReclaimPolicy: reclaimPolicy,
180179
}
181180
if isDefault {
182181
sc.ObjectMeta.Annotations = defaultStorageClassMap
183182
}
184-
workloadClient, err := remote.NewClusterClient(
185-
ctx,
186-
"",
187-
cl,
188-
capiutil.ObjectKey(cluster),
189-
)
190-
if err != nil {
191-
return err
192-
}
183+
return &sc
184+
}
193185

194-
if err := client.ServerSideApply(ctx, workloadClient, &sc); err != nil {
195-
return fmt.Errorf(
196-
"failed to create storage class %w",
197-
err,
198-
)
186+
func CreateConfigMapForCRS(configMapName, configMapNamespace string,
187+
objs ...runtime.Object,
188+
) (*corev1.ConfigMap, error) {
189+
cm := &corev1.ConfigMap{
190+
ObjectMeta: metav1.ObjectMeta{
191+
Name: configMapName,
192+
Namespace: configMapNamespace,
193+
},
194+
TypeMeta: metav1.TypeMeta{
195+
APIVersion: corev1.SchemeGroupVersion.String(),
196+
Kind: "ConfigMap",
197+
},
198+
Data: make(map[string]string),
199+
}
200+
l := make([][]byte, 0, len(objs))
201+
for _, v := range objs {
202+
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(v)
203+
if err != nil {
204+
return nil, err
205+
}
206+
objYaml, err := utilyaml.FromUnstructured([]unstructured.Unstructured{
207+
{
208+
Object: obj,
209+
},
210+
})
211+
if err != nil {
212+
return nil, err
213+
}
214+
l = append(l, objYaml)
199215
}
200-
return nil
216+
cm.Data[defaultCRSConfigMapKey] = fmt.Sprintf("|\n%s", string(utilyaml.JoinYaml(l...)))
217+
return cm, nil
201218
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2023 D2iQ, Inc. All rights reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
package utils
5+
6+
import (
7+
"testing"
8+
9+
corev1 "k8s.io/api/core/v1"
10+
storagev1 "k8s.io/api/storage/v1"
11+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
12+
"k8s.io/apimachinery/pkg/runtime"
13+
)
14+
15+
func TestCreateConfigMapForCRS(t *testing.T) {
16+
tests := []struct {
17+
name string
18+
testCMName string
19+
testNamespace string
20+
objs []runtime.Object
21+
expectedCM corev1.ConfigMap
22+
}{
23+
{
24+
name: "multiple storage class objects",
25+
testCMName: "test",
26+
testNamespace: "default",
27+
objs: []runtime.Object{
28+
&storagev1.StorageClass{
29+
TypeMeta: metav1.TypeMeta{
30+
Kind: kindStorageClass,
31+
APIVersion: storagev1.SchemeGroupVersion.String(),
32+
},
33+
ObjectMeta: metav1.ObjectMeta{
34+
Name: "test",
35+
Namespace: "default",
36+
},
37+
},
38+
&storagev1.StorageClass{
39+
TypeMeta: metav1.TypeMeta{
40+
Kind: kindStorageClass,
41+
APIVersion: storagev1.SchemeGroupVersion.String(),
42+
},
43+
ObjectMeta: metav1.ObjectMeta{
44+
Name: "test-2",
45+
Namespace: "default",
46+
},
47+
},
48+
},
49+
expectedCM: corev1.ConfigMap{
50+
ObjectMeta: metav1.ObjectMeta{
51+
Name: "test",
52+
Namespace: "default",
53+
},
54+
TypeMeta: metav1.TypeMeta{
55+
APIVersion: corev1.SchemeGroupVersion.String(),
56+
Kind: "ConfigMap",
57+
},
58+
Data: map[string]string{
59+
defaultCRSConfigMapKey: `|
60+
apiVersion: storage.k8s.io/v1
61+
kind: StorageClass
62+
metadata:
63+
creationTimestamp: null
64+
name: test
65+
namespace: default
66+
provisioner: ""
67+
---
68+
apiVersion: storage.k8s.io/v1
69+
kind: StorageClass
70+
metadata:
71+
creationTimestamp: null
72+
name: test-2
73+
namespace: default
74+
provisioner: ""`,
75+
},
76+
},
77+
},
78+
}
79+
for _, tt := range tests {
80+
t.Run(tt.name, func(t *testing.T) {
81+
cm, err := CreateConfigMapForCRS(tt.testCMName, tt.testNamespace, tt.objs...)
82+
if err != nil {
83+
t.Errorf("failed to create cm with error %v", err)
84+
}
85+
data, ok := cm.Data[defaultCRSConfigMapKey]
86+
if !ok {
87+
t.Errorf("expected %s to exist in cm.Data. got %v", defaultCRSConfigMapKey, cm.Data)
88+
}
89+
expected := tt.expectedCM.Data[defaultCRSConfigMapKey]
90+
if data != expected {
91+
t.Errorf("expected %s \n got %s", expected, data)
92+
}
93+
})
94+
}
95+
}

0 commit comments

Comments
 (0)