Skip to content

Commit 9b68190

Browse files
authored
Implement Trident resource monitor for auto configuring backends
1 parent 2c66f55 commit 9b68190

File tree

24 files changed

+3275
-124
lines changed

24 files changed

+3275
-124
lines changed

frontend/csi/controller_helpers/kubernetes/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,11 @@ const (
7070
AnnLUKSEncryption = prefix + "/luksEncryption" // import only
7171
AnnSkipRecoveryQueue = prefix + "/skipRecoveryQueue"
7272
AnnSelector = prefix + "/selector"
73+
AnnAdditionalStoragePools = prefix + "/additionalStoragePools"
7374
AnnSMBShareAdUserPermission = prefix + "/smbShareAdUserPermission"
7475
AnnSMBShareAdUser = prefix + "/smbShareAdUser"
7576
AnnSMBShareAccessControl = prefix + "/smbShareAccessControl"
77+
AnnConfiguratorStatus = prefix + "/configuratorStatus"
7678

7779
// Pod remediation policy annotation and values
7880
AnnPodRemediationPolicyAnnotation = prefix + "/podRemediationPolicy"

frontend/csi/controller_helpers/kubernetes/plugin.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,14 @@ func (h *helper) processStorageClass(ctx context.Context, sc *k8sstoragev1.Stora
10061006
scConfig.Name = sc.Name
10071007
scConfig.Attributes = make(map[string]storageattribute.Request)
10081008

1009+
// Check if configuratorStatus annotation is present. It suggests the SC is managed by a TridentConfigurator.
1010+
// We might encounter initial unknown parameters errors but once we see the configuratorStatus annotation,
1011+
// we know the SC is managed by a TridentConfigurator and we can ignore the unknown parameters.
1012+
ignoreUnknownParamErrors := false
1013+
if _, exists := sc.ObjectMeta.Annotations[AnnConfiguratorStatus]; exists {
1014+
ignoreUnknownParamErrors = true
1015+
}
1016+
10091017
// Populate storage class config attributes and backend storage pools
10101018
for k, v := range sc.Parameters {
10111019

@@ -1048,6 +1056,9 @@ func (h *helper) processStorageClass(ctx context.Context, sc *k8sstoragev1.Stora
10481056
// format: attribute: "value"
10491057
req, err := storageattribute.CreateAttributeRequestFromAttributeValue(newKey, v)
10501058
if err != nil {
1059+
if ignoreUnknownParamErrors {
1060+
continue
1061+
}
10511062
Logc(ctx).WithFields(logFields).WithError(err).Errorf(
10521063
"K8S helper could not process the storage class attribute %s", newKey)
10531064
return
@@ -1057,6 +1068,7 @@ func (h *helper) processStorageClass(ctx context.Context, sc *k8sstoragev1.Stora
10571068
}
10581069

10591070
// To allow for atomic selector updates, replace selector with an annotation if it exists
1071+
// Also allow additionalStoragePools to be overridden via annotation
10601072
for k, v := range sc.ObjectMeta.Annotations {
10611073
if k == AnnSelector {
10621074
req, err := storageattribute.CreateAttributeRequestFromAttributeValue("selector", v)
@@ -1067,6 +1079,18 @@ func (h *helper) processStorageClass(ctx context.Context, sc *k8sstoragev1.Stora
10671079
}
10681080
scConfig.Attributes["selector"] = req
10691081
}
1082+
if k == AnnAdditionalStoragePools {
1083+
// Override additionalStoragePools parameter with annotation value
1084+
additionalPools, err := storageattribute.CreateBackendStoragePoolsMapFromEncodedString(v)
1085+
if err != nil {
1086+
Logc(ctx).WithFields(logFields).WithField(k, v).WithError(err).Errorf(
1087+
"K8S helper could not process the storage class annotation %s.", k)
1088+
continue
1089+
}
1090+
scConfig.AdditionalPools = additionalPools
1091+
Logc(ctx).WithFields(logFields).WithField("additionalStoragePools", v).
1092+
Debug("Using additionalStoragePools from annotation to override parameter")
1093+
}
10701094
}
10711095

10721096
if update {

mocks/mock_operator/mock_clients/mock_api.go

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

mocks/mock_operator/mock_controllers/mock_configurator/mock_clients/mock_api.go

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

operator/clients/operator_crd.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,10 @@ func (oc *OperatorCRDClient) UpdateTridentConfiguratorStatus(
6666

6767
return newTconfCR, true, nil
6868
}
69+
70+
// UpdateTridentConfigurator updates the TridentConfigurator CR (metadata/spec, not status)
71+
func (oc *OperatorCRDClient) UpdateTridentConfigurator(tconfCR *operatorV1.TridentConfigurator) error {
72+
_, err := oc.client.TridentV1().TridentConfigurators().Update(ctx, tconfCR, updateOpts)
73+
74+
return err
75+
}

operator/clients/trident_crd.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,23 @@ func (tc *TridentCRDClient) DeleteTridentBackendConfig(name, namespace string) e
4545
func (tc *TridentCRDClient) ListTridentBackend(namespace string) (*tridentV1.TridentBackendList, error) {
4646
return tc.client.TridentV1().TridentBackends(namespace).List(ctx, listOpts)
4747
}
48+
49+
// ListTridentBackendsByLabel lists TridentBackendConfigs with a specific label.
50+
// It is useful for cleaning up associated backends when a TridentConfigurator is deleted.
51+
func (tc *TridentCRDClient) ListTridentBackendsByLabel(namespace, labelKey, labelValue string) ([]*tridentV1.TridentBackendConfig, error) {
52+
labelSelector := metav1.LabelSelector{
53+
MatchLabels: map[string]string{
54+
labelKey: labelValue,
55+
},
56+
}
57+
listOptions := metav1.ListOptions{
58+
LabelSelector: metav1.FormatLabelSelector(&labelSelector),
59+
}
60+
61+
backendList, err := tc.client.TridentV1().TridentBackendConfigs(namespace).List(ctx, listOptions)
62+
if err != nil {
63+
return nil, err
64+
}
65+
66+
return backendList.Items, nil
67+
}

operator/clients/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ type OperatorCRDClientInterface interface {
3333
UpdateTridentConfiguratorStatus(
3434
tconfCR *operatorV1.TridentConfigurator, newStatus operatorV1.TridentConfiguratorStatus,
3535
) (*operatorV1.TridentConfigurator, bool, error)
36+
UpdateTridentConfigurator(tconfCR *operatorV1.TridentConfigurator) error
3637
}
3738

3839
type TridentCRDClientInterface interface {
3940
CheckTridentBackendConfigExists(name, namespace string) (bool, error)
4041
GetTridentBackendConfig(name, namespace string) (*tridentV1.TridentBackendConfig, error)
4142
ListTridentBackend(namespace string) (*tridentV1.TridentBackendList, error)
43+
ListTridentBackendsByLabel(namespace, labelKey, labelValue string) ([]*tridentV1.TridentBackendConfig, error)
4244
PatchTridentBackendConfig(name, namespace string, patchBytes []byte, patchType types.PatchType) error
4345
DeleteTridentBackendConfig(name, namespace string) error
4446
}

operator/controllers/configurator/clients/configurator.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,3 +229,27 @@ func (c *ConfiguratorClient) GetANFSecrets(secretName string) (string, string, e
229229

230230
return clientID, clientSecret, nil
231231
}
232+
233+
// UpdateTridentConfigurator updates the TridentConfigurator CR
234+
func (c *ConfiguratorClient) UpdateTridentConfigurator(tconfCR *operatorV1.TridentConfigurator) error {
235+
return c.oClient.UpdateTridentConfigurator(tconfCR)
236+
}
237+
238+
// ListTridentBackendsByLabel lists TridentBackends with a specific label
239+
func (c *ConfiguratorClient) ListTridentBackendsByLabel(namespace, labelKey, labelValue string) ([]*tridentV1.TridentBackendConfig, error) {
240+
return c.tClient.ListTridentBackendsByLabel(namespace, labelKey, labelValue)
241+
}
242+
243+
// ListStorageClassesByLabel lists StorageClasses with a specific label
244+
func (c *ConfiguratorClient) ListStorageClassesByLabel(labelKey, labelValue string) ([]string, error) {
245+
scList, err := c.kClient.ListStorageClassesByLabel(labelKey, labelValue)
246+
if err != nil {
247+
return nil, err
248+
}
249+
250+
names := make([]string, 0, len(scList.Items))
251+
for _, sc := range scList.Items {
252+
names = append(names, sc.Name)
253+
}
254+
return names, nil
255+
}

operator/controllers/configurator/clients/extended_k8s.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,10 @@ func (kc *K8sClient) PatchStorageClass(name string, patchBytes []byte, patchType
6969
func (kc *K8sClient) DeleteStorageClass(name string) error {
7070
return kc.KubeClient.StorageV1().StorageClasses().Delete(ctx, name, deleteOpts)
7171
}
72+
73+
func (kc *K8sClient) ListStorageClassesByLabel(labelKey, labelValue string) (*v1.StorageClassList, error) {
74+
labelSelector := fmt.Sprintf("%s=%s", labelKey, labelValue)
75+
return kc.KubeClient.StorageV1().StorageClasses().List(ctx, metav1.ListOptions{
76+
LabelSelector: labelSelector,
77+
})
78+
}

operator/controllers/configurator/clients/types.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212

1313
k8sclient "github.com/netapp/trident/cli/k8s_client"
1414
operatorV1 "github.com/netapp/trident/operator/crd/apis/netapp/v1"
15+
tridentV1 "github.com/netapp/trident/persistent_store/crd/apis/netapp/v1"
1516
)
1617

1718
//go:generate mockgen -destination=../../../../mocks/mock_operator/mock_controllers/mock_configurator/mock_clients/mock_api.go github.com/netapp/trident/operator/controllers/configurator/clients ConfiguratorClientInterface,ExtendedK8sClientInterface
@@ -44,11 +45,14 @@ type ConfiguratorClientInterface interface {
4445
UpdateTridentConfiguratorStatus(
4546
tconfCR *operatorV1.TridentConfigurator, newStatus operatorV1.TridentConfiguratorStatus,
4647
) (*operatorV1.TridentConfigurator, bool, error)
48+
UpdateTridentConfigurator(tconfCR *operatorV1.TridentConfigurator) error
4749
GetControllingTorcCR() (*operatorV1.TridentOrchestrator, error)
4850
GetTconfCR(name string) (*operatorV1.TridentConfigurator, error)
4951
GetANFSecrets(secretName string) (string, string, error)
5052
DeleteObject(objType ObjectType, objName, objNamespace string) error
5153
ListObjects(objType ObjectType, objNamespace string) (interface{}, error)
54+
ListTridentBackendsByLabel(namespace, labelKey, labelValue string) ([]*tridentV1.TridentBackendConfig, error)
55+
ListStorageClassesByLabel(labelKey, labelValue string) ([]string, error)
5256
}
5357

5458
type ExtendedK8sClientInterface interface {
@@ -58,4 +62,5 @@ type ExtendedK8sClientInterface interface {
5862
GetStorageClass(name string) (*v1.StorageClass, error)
5963
PatchStorageClass(name string, patchBytes []byte, patchType types.PatchType) error
6064
DeleteStorageClass(name string) error
65+
ListStorageClassesByLabel(labelKey, labelValue string) (*v1.StorageClassList, error)
6166
}

0 commit comments

Comments
 (0)