Skip to content

Commit 774190b

Browse files
authored
Reconciler to monitor the changes in AWS FSxN resources
1 parent c2d2372 commit 774190b

File tree

14 files changed

+662
-469
lines changed

14 files changed

+662
-469
lines changed

helm/trident-operator/templates/clusterrole.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,7 @@ rules:
144144
- volumesnapshotclasses
145145
verbs:
146146
- create
147+
- delete
147148
- apiGroups:
148149
- snapshot.storage.k8s.io
149150
resources:

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

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

mocks/mock_storage_drivers/mock_ontap/mock_awsapi.go

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

operator/clients/trident_crd.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ func (tc *TridentCRDClient) PatchTridentBackendConfig(name, namespace string, pa
4141
func (tc *TridentCRDClient) DeleteTridentBackendConfig(name, namespace string) error {
4242
return tc.client.TridentV1().TridentBackendConfigs(namespace).Delete(ctx, name, deleteOpts)
4343
}
44+
45+
func (tc *TridentCRDClient) ListTridentBackend(namespace string) (*tridentV1.TridentBackendList, error) {
46+
return tc.client.TridentV1().TridentBackends(namespace).List(ctx, listOpts)
47+
}

operator/clients/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type OperatorCRDClientInterface interface {
3838
type TridentCRDClientInterface interface {
3939
CheckTridentBackendConfigExists(name, namespace string) (bool, error)
4040
GetTridentBackendConfig(name, namespace string) (*tridentV1.TridentBackendConfig, error)
41+
ListTridentBackend(namespace string) (*tridentV1.TridentBackendList, error)
4142
PatchTridentBackendConfig(name, namespace string, patchBytes []byte, patchType types.PatchType) error
4243
DeleteTridentBackendConfig(name, namespace string) error
4344
}

operator/controllers/configurator/clients/configurator.go

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func (c *ConfiguratorClient) CreateOrPatchObject(objType ObjectType, objName, ob
6565
Log().Errorf("Patch failed for %s %s: %v", objName, objType, err)
6666
}
6767

68-
if err := c.deleteObject(objType, objName, objNamespace); err != nil {
68+
if err := c.DeleteObject(objType, objName, objNamespace); err != nil {
6969
return err
7070
}
7171

@@ -166,7 +166,8 @@ func (c *ConfiguratorClient) patchObject(objType ObjectType, objName, objNamespa
166166
return fmt.Errorf("unsupported object %s of type %s", objName, objType)
167167
}
168168

169-
func (c *ConfiguratorClient) deleteObject(objType ObjectType, objName, objNamespace string) error {
169+
// DeleteObject deletes the object of the given type and name.
170+
func (c *ConfiguratorClient) DeleteObject(objType ObjectType, objName, objNamespace string) error {
170171
switch objType {
171172
case OCRD:
172173
return c.kClient.DeleteCRD(objName)
@@ -181,6 +182,19 @@ func (c *ConfiguratorClient) deleteObject(objType ObjectType, objName, objNamesp
181182
return fmt.Errorf("unsupported object %s of type %s", objName, objType)
182183
}
183184

185+
// ListObjects lists the objects of the given type.
186+
func (c *ConfiguratorClient) ListObjects(objType ObjectType, objNamespace string) (interface{}, error) {
187+
switch objType {
188+
case OCRD:
189+
case OBackend:
190+
return c.tClient.ListTridentBackend(objNamespace)
191+
case OStorageClass:
192+
case OSnapshotClass:
193+
}
194+
195+
return nil, fmt.Errorf("unsupported object type %s", objType)
196+
}
197+
184198
func (c *ConfiguratorClient) GetControllingTorcCR() (*operatorV1.TridentOrchestrator, error) {
185199
return c.oClient.GetControllingTorcCR()
186200
}

operator/controllers/configurator/clients/types.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ type ConfiguratorClientInterface interface {
4747
GetControllingTorcCR() (*operatorV1.TridentOrchestrator, error)
4848
GetTconfCR(name string) (*operatorV1.TridentConfigurator, error)
4949
GetANFSecrets(secretName string) (string, string, error)
50+
DeleteObject(objType ObjectType, objName, objNamespace string) error
51+
ListObjects(objType ObjectType, objNamespace string) (interface{}, error)
5052
}
5153

5254
type ExtendedK8sClientInterface interface {

operator/controllers/configurator/controller.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,20 +394,20 @@ func (c *Controller) reconcile(keyItem string) error {
394394
return err
395395
}
396396
case config.OntapNASStorageDriverName, config.OntapSANStorageDriverName:
397-
isAwsFsxn, err := tconfCR.IsAwsFsxnTconf()
397+
isAwsFSxN, err := tconfCR.IsAWSFSxNTconf()
398398
if err != nil {
399399
Log().Error("Failed to check if tconf is for AWS FSxN: ", err)
400400
return err
401401
}
402-
if isAwsFsxn {
402+
if isAwsFSxN {
403403
Log().Debugf("Tconf indicates auto-backend config is for AWS FSxN")
404-
fsxn, err := storage_drivers.NewFsxnInstance(torcCR, tconfCR, c.Clients)
404+
fsxn, err := storage_drivers.NewFSxNInstance(torcCR, tconfCR, c.Clients)
405405
if err != nil {
406406
Log().Info("Failed to create FsxN backend instance: ", err)
407407
return err
408408
}
409409
if err := c.ProcessBackend(fsxn, tconfCR); err != nil {
410-
Log().Error("Failed to process FsxN backend: ", err)
410+
Log().Error("Failed to process FSxN backend: ", err)
411411
return err
412412
}
413413
}

operator/controllers/configurator/storage_drivers/anf.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,18 @@ func (a *ANF) GetCloudProvider() string {
222222
return "None"
223223
}
224224

225+
func (a *ANF) DeleteBackend(map[string]interface{}) error {
226+
return nil
227+
}
228+
229+
func (a *ANF) DeleteStorageClass(map[string]interface{}) error {
230+
return nil
231+
}
232+
233+
func (a *ANF) DeleteSnapshotClass() error {
234+
return nil
235+
}
236+
225237
func (a *ANF) populateAndValidateAZResources() error {
226238
a.FilteredCapacityPoolMap = a.AZClient.FilteredCapacityPoolMap(context.TODO(), a.ResourceGroups,
227239
a.NetappAccounts, a.CapacityPools)

operator/controllers/configurator/storage_drivers/fsx.go

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@ import (
1717
. "github.com/netapp/trident/logging"
1818
confClients "github.com/netapp/trident/operator/controllers/configurator/clients"
1919
operatorV1 "github.com/netapp/trident/operator/crd/apis/netapp/v1"
20+
tridentV1 "github.com/netapp/trident/persistent_store/crd/apis/netapp/v1"
2021
sa "github.com/netapp/trident/storage_attribute"
2122
"github.com/netapp/trident/storage_drivers/ontap/awsapi"
2223
"github.com/netapp/trident/utils"
24+
"github.com/netapp/trident/utils/errors"
2325
)
2426

2527
const (
@@ -60,8 +62,8 @@ type SVM struct {
6062
ManagementLIF string `json:"managementLIF"`
6163
}
6264

63-
// NewFsxnInstance creates a new instance of the AWS struct and populates it with the provided CRs and client
64-
func NewFsxnInstance(
65+
// NewFSxNInstance creates a new instance of the AWS struct and populates it with the provided CRs and client
66+
func NewFSxNInstance(
6567
torcCR *operatorV1.TridentOrchestrator, configuratorCR *operatorV1.TridentConfigurator,
6668
client confClients.ConfiguratorClientInterface,
6769
) (*AWS, error) {
@@ -70,7 +72,7 @@ func NewFsxnInstance(
7072
}
7173

7274
if configuratorCR == nil {
73-
return nil, fmt.Errorf("empty AWSFsxN configurator CR")
75+
return nil, fmt.Errorf("empty AWS FSxN configurator CR")
7476
}
7577

7678
if client == nil {
@@ -117,33 +119,39 @@ func (aws *AWS) Validate() error {
117119
aws.AwsClient = api
118120

119121
for key, fsxnInstance := range aws.SVMs {
120-
if err := aws.processFsxnInstance(context.Background(), key, fsxnInstance); err != nil {
122+
if err := aws.processFSxNInstance(context.Background(), key, fsxnInstance); err != nil {
121123
return err
122124
}
123125
}
124126

125127
return nil
126128
}
127129

128-
// processFsxnInstance processes the auto-backend configuration for the FSxN instance.
130+
// processFSxNInstance processes the auto-backend configuration for the FSxN instance.
129131
// It creates the SVM if it does not exist and creates the secret for the SVM.
130-
func (aws *AWS) processFsxnInstance(ctx context.Context, key int, svm SVM) error {
132+
func (aws *AWS) processFSxNInstance(ctx context.Context, key int, svm SVM) error {
131133
var (
132-
svmName string
133-
secretName string
134-
secretARN string
135-
svmExists bool
134+
svmName string
135+
secretName string
136+
secretARN string
137+
svmExists bool
138+
ErrStatusCode = "StatusCode: 400"
136139
)
137140
svmName = svm.SvmName
138141
if svmName == "" {
139142
svmName = fmt.Sprintf(SvmNamePattern, svm.FsxnID)
143+
svm.SvmName = svmName
140144
}
141145
_, err := aws.AwsClient.GetFilesystemByID(ctx, svm.FsxnID)
142-
if err != nil {
146+
if errors.IsNotFoundError(err) || (err != nil && strings.Contains(err.Error(), ErrStatusCode)) {
147+
err = aws.cleanUpFSxNRelatedObjects(svm, svm.Protocols)
148+
if err != nil {
149+
Log().Error(err)
150+
}
143151
return fmt.Errorf("error occurred while getting fsxn id: %v : %v", svm.FsxnID, err)
144152
}
145153
Log().Debugf("Filesystem ID: %s exists", svm.FsxnID)
146-
secretName = fmt.Sprintf(TridentSecretPattern, strings.TrimPrefix(svmName, "trident-"))
154+
secretName = getAWSSecretName(svmName)
147155
// Get the secret if it already exists or create a new one
148156
secret, _ := aws.AwsClient.GetSecret(ctx, secretName)
149157
if secret != nil {
@@ -245,7 +253,7 @@ func (aws *AWS) Create() ([]string, error) {
245253
)
246254
for _, svm := range aws.SVMs {
247255
for _, protocol := range svm.Protocols {
248-
backendName = getFsxnBackendName(svm.FsxnID, protocol)
256+
backendName = getFSxNBackendName(svm.FsxnID, protocol)
249257
backendYAML := getFsxnTBCYaml(svm, aws.TridentNamespace, backendName, protocol)
250258
if err := aws.ConfClient.CreateOrPatchObject(confClients.OBackend, backendName,
251259
aws.TridentNamespace, backendYAML); err != nil {
@@ -262,7 +270,7 @@ func (aws *AWS) CreateStorageClass() error {
262270
var driver string
263271
for _, svm := range aws.SVMs {
264272
for _, protocol := range svm.Protocols {
265-
name := getFsxnStorageClassName(svm.FsxnID, protocol)
273+
name := getFSxNStorageClassName(svm.FsxnID, protocol)
266274
if protocol == sa.NFS {
267275
driver = config.OntapNASStorageDriverName
268276
} else if protocol == sa.ISCSI {
@@ -290,12 +298,95 @@ func (aws *AWS) GetCloudProvider() string {
290298
return k8sclient.CloudProviderAWS
291299
}
292300

293-
// getFsxnTBCYaml returns the FsxN Trident backend config name
294-
func getFsxnBackendName(fsxnId, protocolType string) string {
301+
// DeleteBackend deletes the backend if the FSxN instance is deleted
302+
func (aws *AWS) DeleteBackend(request map[string]interface{}) error {
303+
protocols := request["protocols"].([]string)
304+
fsxnId := request["FSxNID"].(string)
305+
for _, protocol := range protocols {
306+
backendName := getFSxNBackendName(fsxnId, protocol)
307+
if err := aws.ConfClient.DeleteObject(confClients.OBackend, backendName, aws.TridentNamespace); err != nil {
308+
return fmt.Errorf("error occurred while deleting backend: %w", err)
309+
}
310+
}
311+
return nil
312+
}
313+
314+
// DeleteStorageClass deletes the storage class if the FSxN instance is deleted
315+
func (aws *AWS) DeleteStorageClass(request map[string]interface{}) error {
316+
protocols := request["protocols"].([]string)
317+
fsxnId := request["FSxNID"].(string)
318+
for _, protocol := range protocols {
319+
name := getFSxNStorageClassName(fsxnId, protocol)
320+
if err := aws.ConfClient.DeleteObject(confClients.OStorageClass, name, aws.TridentNamespace); err != nil {
321+
return fmt.Errorf("error occurred while deleting storage class: %w", err)
322+
}
323+
}
324+
return nil
325+
}
326+
327+
// DeleteSnapshotClass deletes the snapshot class if the FSxN instance is deleted
328+
func (aws *AWS) DeleteSnapshotClass() error {
329+
tbcList, err := aws.ConfClient.ListObjects(confClients.OBackend, "")
330+
if err != nil {
331+
return fmt.Errorf("error occurred while listing TBC objects: %w", err)
332+
}
333+
if len(tbcList.(*tridentV1.TridentBackendList).Items) == 0 {
334+
if err := aws.ConfClient.DeleteObject(confClients.OSnapshotClass, NetAppSnapshotClassName, ""); err != nil {
335+
return fmt.Errorf("error occurred while deleting snapshot class: %w", err)
336+
}
337+
}
338+
339+
return nil
340+
}
341+
342+
// cleanUpFSxNRelatedObjects cleans up the FSxN instance related objects like storage class, backend, and AWS secret
343+
func (aws *AWS) cleanUpFSxNRelatedObjects(svm SVM, protocols []string) (err error) {
344+
cleanupRequest := map[string]interface{}{
345+
"FSxNID": svm.FsxnID,
346+
"protocols": protocols,
347+
}
348+
349+
// Delete the storage class
350+
if deleteErr := aws.DeleteStorageClass(cleanupRequest); err != nil {
351+
err = fmt.Errorf("failed to delete VolumeSnapshotClass: %w", deleteErr)
352+
}
353+
354+
// Delete the backend
355+
if deleteErr := aws.DeleteBackend(cleanupRequest); err != nil {
356+
err = fmt.Errorf("failed to delete backend: %w", deleteErr)
357+
}
358+
359+
// Delete the AWS secret
360+
if deleteErr := deleteSecret(context.Background(), aws, getAWSSecretName(svm.SvmName)); err != nil {
361+
err = fmt.Errorf("failed to delete AWS secret: %w", deleteErr)
362+
}
363+
364+
// Delete the VolumeSnapshotClass if no backend is present
365+
if deleteErr := aws.DeleteSnapshotClass(); err != nil {
366+
err = fmt.Errorf("failed to delete VolumeSnapshotClass: %w", deleteErr)
367+
}
368+
369+
return
370+
}
371+
372+
func deleteSecret(ctx context.Context, aws *AWS, secretName string) error {
373+
if err := aws.AwsClient.DeleteSecret(ctx, secretName); err != nil {
374+
return fmt.Errorf("error occurred while deleting secret: %w", err)
375+
}
376+
return nil
377+
}
378+
379+
// getFSxNBackendName returns the FsxN Trident backend config name
380+
func getFSxNBackendName(fsxnId, protocolType string) string {
295381
return fmt.Sprintf(BackendNamePattern, fsxnId, protocolType)
296382
}
297383

298-
// getFsxnStorageClassName returns the storage class name for the FSxN backend
299-
func getFsxnStorageClassName(fsxnId, protocolType string) string {
384+
// getFSxNStorageClassName returns the storage class name for the FSxN backend
385+
func getFSxNStorageClassName(fsxnId, protocolType string) string {
300386
return fmt.Sprintf(StorageClassNamePattern, fsxnId, protocolType)
301387
}
388+
389+
// getAWSSecretName returns the AWS secret name for the FSxN backend
390+
func getAWSSecretName(svmName string) string {
391+
return fmt.Sprintf(TridentSecretPattern, strings.TrimPrefix(svmName, "trident-"))
392+
}

0 commit comments

Comments
 (0)