diff --git a/core/core_test.go b/core/core_test.go index d4ad03858..ae48639ed 100644 --- a/core/core_test.go +++ b/core/core_test.go @@ -10,6 +10,10 @@ import ( log "github.com/sirupsen/logrus" ) +// TestMain is the main entry point for tests +// It checks for a test config file and sets up the test environment +// +// -- Doc autogenerated on 2022-05-12 20:34:20.021163 -- func TestMain(m *testing.M) { // Disable any standard log output log.SetOutput(ioutil.Discard) diff --git a/core/orchestrator_core.go b/core/orchestrator_core.go index 378d92fd4..8bf902006 100644 --- a/core/orchestrator_core.go +++ b/core/orchestrator_core.go @@ -54,6 +54,17 @@ func recordTiming(operation string, err *error) func() { } } +// recordTransactionTiming records the time taken for a transaction to complete +// to a prometheus summary. +// Parameters: +// txn: the transaction to record +// err: the error returned by the transaction +// Returns: +// None +// Example: +// recordTransactionTiming(txn, &err) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func recordTransactionTiming(txn *storage.VolumeTransaction, err *error) { if txn == nil || txn.VolumeCreatingConfig == nil { // for unit tests, there will be no txn to record @@ -108,6 +119,20 @@ func NewTridentOrchestrator(client persistentstore.Client) *TridentOrchestrator } } +// transformPersistentState transforms the persistent state from the previous version to the current version. +// It returns an error if the transformation fails. +// Parameters: +// ctx - context.Context object +// Returns: +// error - error object +// Example: +// ctx := context.Background() +// err := o.transformPersistentState(ctx) +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) transformPersistentState(ctx context.Context) error { version, err := o.storeClient.GetVersion(ctx) if err != nil && persistentstore.MatchKeyNotFoundErr(err) { @@ -141,6 +166,17 @@ func (o *TridentOrchestrator) transformPersistentState(ctx context.Context) erro return nil } +// Bootstrap initializes the orchestrator +// It returns an error if the orchestrator cannot be bootstrapped +// Returns: +// error: error if the orchestrator cannot be bootstrapped +// Example: +// err := orc.Bootstrap() +// if err != nil { +// log.Error("Failed to bootstrap orchestrator: %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) Bootstrap() error { ctx := GenerateRequestContext(context.Background(), "", ContextSourceInternal) var err error @@ -170,6 +206,16 @@ func (o *TridentOrchestrator) Bootstrap() error { return nil } +// bootstrapBackends is called during startup to load all backends from the persistent store. +// It returns an error if any of the backends fail to initialize. +// Parameters: +// ctx - context for logging +// Returns: +// error - if any backends fail to initialize +// Example: +// err := o.bootstrapBackends(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) bootstrapBackends(ctx context.Context) error { persistentBackends, err := o.storeClient.GetBackends(ctx) if err != nil { @@ -261,6 +307,16 @@ func (o *TridentOrchestrator) bootstrapBackends(ctx context.Context) error { return nil } +// bootstrapStorageClasses loads the storage classes from the backend store. +// It returns an error if the storage classes cannot be loaded. +// Parameters: +// ctx - context for logging +// Returns: +// error - error if the storage classes cannot be loaded +// Example: +// err := o.bootstrapStorageClasses(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) bootstrapStorageClasses(ctx context.Context) error { persistentStorageClasses, err := o.storeClient.GetStorageClasses(ctx) if err != nil { @@ -283,6 +339,16 @@ func (o *TridentOrchestrator) bootstrapStorageClasses(ctx context.Context) error // Updates the o.volumes cache with the latest backend data. This function should only edit o.volumes in place to avoid // briefly losing track of volumes that do exist. +// bootstrapVolumes reads the volumes from the store and adds them to the orchestrator. +// It returns an error if the store is not available. +// Parameters: +// ctx - context for logging +// Returns: +// error - if the store is not available +// Example: +// err := o.bootstrapVolumes(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) bootstrapVolumes(ctx context.Context) error { volumes, err := o.storeClient.GetVolumes(ctx) if err != nil { @@ -335,6 +401,16 @@ func (o *TridentOrchestrator) bootstrapVolumes(ctx context.Context) error { return nil } +// bootstrapSnapshots loads existing snapshots from the backend store. +// It returns an error if the store is unavailable. +// Parameters: +// ctx - context +// Returns: +// error - error if the store is unavailable +// Example: +// error := o.bootstrapSnapshots(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) bootstrapSnapshots(ctx context.Context) error { snapshots, err := o.storeClient.GetSnapshots(ctx) if err != nil { @@ -369,6 +445,19 @@ func (o *TridentOrchestrator) bootstrapSnapshots(ctx context.Context) error { return nil } +// bootstrapVolTxns handles any volume transactions that were in progress when the orchestrator was last stopped. +// It returns an error if any of the transactions could not be handled. +// Parameters: +// ctx - context +// Returns: +// error - any error encountered +// Example: +// err := o.bootstrapVolTxns(ctx) +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) bootstrapVolTxns(ctx context.Context) error { volTxns, err := o.storeClient.GetVolumeTransactions(ctx) if err != nil && !persistentstore.MatchKeyNotFoundErr(err) { @@ -385,6 +474,17 @@ func (o *TridentOrchestrator) bootstrapVolTxns(ctx context.Context) error { return nil } +// bootstrapNodes is called during startup to load any existing nodes from the backend +// into the orchestrator. +// It returns an error if the operation fails. +// Parameters: +// ctx - context for the operation +// Returns: +// error - any error encountered +// Example: +// err := o.bootstrapNodes(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) bootstrapNodes(ctx context.Context) error { // Don't bootstrap nodes if we're not CSI if config.CurrentDriverContext != config.ContextCSI { @@ -409,6 +509,16 @@ func (o *TridentOrchestrator) bootstrapNodes(ctx context.Context) error { return nil } +// bootstrapVolumePublications bootstraps the orchestrator with existing volume publications +// It returns an error if it fails to read the volume publications from the store +// Parameters: +// ctx - context for logging +// Returns: +// error - if the volume publications cannot be read from the store +// Example: +// err := bootstrapVolumePublications(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) bootstrapVolumePublications(ctx context.Context) error { // Don't bootstrap volume publications if we're not CSI if config.CurrentDriverContext != config.ContextCSI { @@ -430,6 +540,15 @@ func (o *TridentOrchestrator) bootstrapVolumePublications(ctx context.Context) e return nil } +// addVolumePublicationToCache adds the volume publication to the cache +// Parameters: +// vp - volume publication to add to the cache +// Returns: +// none +// Example: +// o.addVolumePublicationToCache(vp) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) addVolumePublicationToCache(vp *utils.VolumePublication) { // If the volume has no entry we need to initialize the inner map if o.volumePublications[vp.VolumeName] == nil { @@ -438,6 +557,20 @@ func (o *TridentOrchestrator) addVolumePublicationToCache(vp *utils.VolumePublic o.volumePublications[vp.VolumeName][vp.NodeName] = vp } +// bootstrap loads the state of the orchestrator from persistent storage. +// It is called once at startup. +// It returns an error if the bootstrap fails. +// Parameters: +// ctx - context for the operation +// Returns: +// error - if the bootstrap fails +// Example: +// err := o.bootstrap(ctx) +// if err != nil { +// log.Fatalf("Bootstrap failed: %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) bootstrap(ctx context.Context) error { // Fetching backend information @@ -548,6 +681,32 @@ func (o *TridentOrchestrator) updateMetrics() { } } +// handleFailedTransaction attempts to roll back a failed transaction. +// +// The transaction log is a record of operations that have been performed on +// the backend, but have not yet been persisted to the store. If the +// orchestrator crashes before the transaction is persisted, the transaction +// log will be used to roll back the operation. +// +// The transaction log is a record of operations that have been performed on +// the backend, but have not yet been persisted to the store. If the +// orchestrator crashes before the transaction is persisted, the transaction +// log will be used to roll back the operation. +// +// The transaction log is a record of operations that have been performed on +// the backend, but have not yet been persisted to the store. If the +// orchestrator crashes before the transaction is persisted, the transaction +// log will be used to roll back the operation. +// It returns an error if the rollback fails. +// Parameters: +// ctx - context for logging +// v - the transaction to roll back +// Returns: +// error - an error if the rollback fails +// Example: +// err := handleFailedTransaction(ctx, v) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) handleFailedTransaction(ctx context.Context, v *storage.VolumeTransaction) error { switch v.Op { case storage.AddVolume, storage.DeleteVolume, @@ -785,6 +944,19 @@ func (o *TridentOrchestrator) handleFailedTransaction(ctx context.Context, v *st return nil } +// resetImportedVolumeName attempts to rename the volume back to its original name. +// It returns an error if the volume is not found. +// Parameters: +// volume: the volume to rename +// Returns: +// error: nil if the volume was found and renamed, or an error if the volume was not found +// Example: +// err := o.resetImportedVolumeName(ctx, volume) +// if err != nil { +// return fmt.Errorf("failed to reset name for imported volume %s: %v", volume.Config.Name, err) +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) resetImportedVolumeName(ctx context.Context, volume *storage.VolumeConfig) error { // The volume could be renamed (notManaged = false) without being persisted. // If the volume wasn't added to the persistent store, we attempt to rename @@ -801,6 +973,15 @@ func (o *TridentOrchestrator) resetImportedVolumeName(ctx context.Context, volum return nil } +// AddFrontend adds a frontend to the orchestrator +// Parameters: +// f - frontend to add +// Returns: +// none +// Example: +// orchestrator.AddFrontend(frontend.NewKubernetes()) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) AddFrontend(f frontend.Plugin) { name := f.GetName() if _, ok := o.frontends[name]; ok { @@ -811,6 +992,20 @@ func (o *TridentOrchestrator) AddFrontend(f frontend.Plugin) { o.frontends[name] = f } +// GetFrontend returns a frontend plugin by name +// Parameters: +// ctx - context +// name - name of the frontend plugin +// Returns: +// frontend.Plugin - the frontend plugin +// error - error if any +// Example: +// frontend, err := tridentOrchestrator.GetFrontend(context.Background(), "ontap-nas") +// if err != nil { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetFrontend(ctx context.Context, name string) (frontend.Plugin, error) { if fe, ok := o.frontends[name]; !ok { err := fmt.Errorf("requested frontend %s does not exist", name) @@ -821,6 +1016,17 @@ func (o *TridentOrchestrator) GetFrontend(ctx context.Context, name string) (fro } } +// validateBackendUpdate validates that the backend update is valid. +// It returns an error if the backend update is invalid. +// Parameters: +// oldBackend - the current backend +// newBackend - the backend to be updated +// Returns: +// error - an error if the backend update is invalid +// Example: +// err := o.validateBackendUpdate(oldBackend, newBackend) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) validateBackendUpdate(oldBackend, newBackend storage.Backend) error { // Validate that backend type isn't being changed as backend type has // implications for the internal volume names. @@ -833,6 +1039,19 @@ func (o *TridentOrchestrator) validateBackendUpdate(oldBackend, newBackend stora return nil } +// GetVersion returns the version of the orchestrator +// Parameters: +// context - context for the request +// Returns: +// version - version of the orchestrator +// error - any error encountered +// Example: +// version, err := orchestrator.GetVersion(context) +// if err != nil { +// log.Errorf("%v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetVersion(context.Context) (string, error) { return config.OrchestratorVersion.String(), o.bootstrapError } @@ -1363,6 +1582,16 @@ func (o *TridentOrchestrator) updateBackendState( return backend.ConstructExternal(ctx), o.storeClient.UpdateBackend(ctx, backend) } +// getBackendUUIDByBackendName returns the backend UUID for a given backend name +// Parameters: +// backendName - name of the backend +// Returns: +// backendUUID - UUID of the backend +// error - error if any +// Example: +// backendUUID, err := getBackendUUIDByBackendName("backend1") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) getBackendUUIDByBackendName(backendName string) (string, error) { backendUUID := "" for _, b := range o.backends { @@ -1374,6 +1603,19 @@ func (o *TridentOrchestrator) getBackendUUIDByBackendName(backendName string) (s return "", utils.NotFoundError(fmt.Sprintf("backend %v was not found", backendName)) } +// getBackendByBackendName returns a backend by name +// Parameters: +// backendName - the name of the backend to return +// Returns: +// storage.Backend - the backend object +// error - an error if one occurred +// Example: +// backend, err := o.getBackendByBackendName(backendName) +// if err != nil { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) getBackendByBackendName(backendName string) (storage.Backend, error) { for _, b := range o.backends { if b.Name() == backendName { @@ -1383,6 +1625,16 @@ func (o *TridentOrchestrator) getBackendByBackendName(backendName string) (stora return nil, utils.NotFoundError(fmt.Sprintf("backend %v was not found", backendName)) } +// getBackendByConfigRef returns the backend based on the configRef +// Parameters: +// configRef string +// Returns: +// storage.Backend +// error +// Example: +// backend, err := o.getBackendByConfigRef(configRef) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) getBackendByConfigRef(configRef string) (storage.Backend, error) { for _, b := range o.backends { if b.ConfigRef() == configRef { @@ -1392,6 +1644,16 @@ func (o *TridentOrchestrator) getBackendByConfigRef(configRef string) (storage.B return nil, utils.NotFoundError(fmt.Sprintf("backend based on configRef '%v' was not found", configRef)) } +// getBackendByBackendUUID returns a backend by its UUID +// Parameters: +// backendUUID - the UUID of the backend to return +// Returns: +// storage.Backend - the backend with the specified UUID +// error - any error encountered +// Example: +// backend, err := o.getBackendByBackendUUID(backendUUID) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) getBackendByBackendUUID(backendUUID string) (storage.Backend, error) { backend := o.backends[backendUUID] if backend != nil { @@ -1400,6 +1662,17 @@ func (o *TridentOrchestrator) getBackendByBackendUUID(backendUUID string) (stora return nil, utils.NotFoundError(fmt.Sprintf("backend uuid %v was not found", backendUUID)) } +// GetBackend returns the backend object for the specified backend name +// Parameters: +// ctx - context for logging +// backendName - name of the backend +// Returns: +// backendExternal - backend object +// err - error object +// Example: +// backendExternal, err := o.GetBackend(ctx, backendName) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetBackend( ctx context.Context, backendName string, ) (backendExternal *storage.BackendExternal, err error) { @@ -1431,6 +1704,17 @@ func (o *TridentOrchestrator) GetBackend( return backendExternal, nil } +// GetBackendByBackendUUID returns the backend object for the given backend UUID +// Parameters: +// ctx - context for logging +// backendUUID - UUID of the backend to retrieve +// Returns: +// *storage.BackendExternal - the backend object +// error - any error encountered +// Example: +// backendExternal, err := orchestrator.GetBackendByBackendUUID(ctx, "backend-uuid") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetBackendByBackendUUID( ctx context.Context, backendUUID string, ) (backendExternal *storage.BackendExternal, err error) { @@ -1459,6 +1743,16 @@ func (o *TridentOrchestrator) GetBackendByBackendUUID( return backendExternal, nil } +// ListBackends returns the list of backends known to the orchestrator. +// Parameters: +// ctx - context for the request +// Returns: +// backends - list of backends known to the orchestrator +// err - error object, if any +// Example: +// backends, err := o.ListBackends(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ListBackends( ctx context.Context, ) (backendExternals []*storage.BackendExternal, err error) { @@ -1482,6 +1776,16 @@ func (o *TridentOrchestrator) ListBackends( return backends, nil } +// DeleteBackend deletes a backend from the orchestrator +// It returns an error if the backend does not exist +// Parameters: +// backendName - the name of the backend to delete +// Returns: +// error - nil if successful, otherwise an error +// Example: +// err := orchestrator.DeleteBackend("myBackend") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) DeleteBackend(ctx context.Context, backendName string) (err error) { if o.bootstrapError != nil { Logc(ctx).WithFields(log.Fields{ @@ -1503,6 +1807,17 @@ func (o *TridentOrchestrator) DeleteBackend(ctx context.Context, backendName str return o.deleteBackendByBackendUUID(ctx, backendName, backendUUID) } +// DeleteBackendByBackendUUID deletes a backend by backendUUID +// It returns an error if the backend does not exist. +// Parameters: +// backendName: Name of the backend to delete +// backendUUID: UUID of the backend to delete +// Returns: +// error: nil if successful, otherwise reason for failure +// Example: +// err := orchestrator.DeleteBackendByBackendUUID(ctx, "myBackend", "12345678-1234-1234-1234-1234567890ab") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) DeleteBackendByBackendUUID( ctx context.Context, backendName, backendUUID string, ) (err error) { @@ -1522,6 +1837,18 @@ func (o *TridentOrchestrator) DeleteBackendByBackendUUID( return o.deleteBackendByBackendUUID(ctx, backendName, backendUUID) } +// deleteBackendByBackendUUID deletes a backend by backendUUID +// It returns an error if the backend is not found. +// Parameters: +// ctx - context +// backendName - name of the backend +// backendUUID - UUID of the backend +// Returns: +// error - error if the backend is not found +// Example: +// err := o.deleteBackendByBackendUUID(ctx, "my-backend", "12345678-1234-1234-1234-123456789012") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) deleteBackendByBackendUUID(ctx context.Context, backendName, backendUUID string) error { Logc(ctx).WithFields(log.Fields{ "backendName": backendName, @@ -1600,6 +1927,18 @@ func (o *TridentOrchestrator) RemoveBackendConfigRef(ctx context.Context, backen return o.storeClient.UpdateBackend(ctx, b) } +// AddVolume creates a new volume +// It returns the external volume object and an error if any +// Parameters: +// volumeConfig - configuration for the new volume +// backendUUID - UUID of the backend to create the volume on +// Returns: +// externalVol - external volume object +// err - error if any +// Example: +// externalVol, err := orchestrator.AddVolume(ctx, volumeConfig, backendUUID) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) AddVolume( ctx context.Context, volumeConfig *storage.VolumeConfig, ) (externalVol *storage.VolumeExternal, err error) { @@ -1853,6 +2192,18 @@ func (o *TridentOrchestrator) addVolumeFinish( return externalVol, nil } +// CloneVolume clones a volume +// It returns the volume object and an error +// Parameters: +// ctx - context for logging +// volumeConfig - volume config +// Returns: +// *storage.VolumeExternal - volume object +// error - error, if any +// Example: +// volume, err := o.CloneVolume(ctx, volumeConfig) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) CloneVolume( ctx context.Context, volumeConfig *storage.VolumeConfig, ) (externalVol *storage.VolumeExternal, err error) { @@ -1884,6 +2235,18 @@ func (o *TridentOrchestrator) CloneVolume( return o.cloneVolumeInitial(ctx, volumeConfig) } +// cloneVolumeInitial clones a volume +// It returns the volume and an error if one occurred +// Parameters: +// ctx - context +// volumeConfig - volume config +// Returns: +// volume - volume +// error - error +// Example: +// volume, err := orchestrator.cloneVolumeInitial(ctx, volumeConfig) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) cloneVolumeInitial( ctx context.Context, volumeConfig *storage.VolumeConfig, ) (externalVol *storage.VolumeExternal, err error) { @@ -2025,6 +2388,19 @@ func (o *TridentOrchestrator) cloneVolumeInitial( return o.addVolumeFinish(ctx, txn, vol, backend, pool) } +// cloneVolumeRetry attempts to create a clone of the specified volume on the specified backend. +// If successful, it returns the volume and backend. If not, it returns an error. +// It returns the volume and backend even if an error is returned. +// Parameters: +// ctx - context +// txn - the volume transaction +// Returns: +// externalVol - the volume +// err - any error encountered +// Example: +// externalVol, err := o.cloneVolumeRetry(ctx, txn) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) cloneVolumeRetry( ctx context.Context, txn *storage.VolumeTransaction, ) (externalVol *storage.VolumeExternal, err error) { @@ -2154,6 +2530,16 @@ func (o *TridentOrchestrator) GetVolumeByInternalName( return "", utils.NotFoundError(fmt.Sprintf("volume %s not found", volumeInternal)) } +// validateImportVolume validates the volume +// It returns an error if the volume is not valid +// Parameters: +// volumeConfig: volume configuration +// Returns: +// error: error if the volume is not valid +// Example: +// err := o.validateImportVolume(ctx, volumeConfig) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) validateImportVolume(ctx context.Context, volumeConfig *storage.VolumeConfig) error { backend, err := o.getBackendByBackendUUID(volumeConfig.ImportBackendUUID) if err != nil { @@ -2215,6 +2601,20 @@ func (o *TridentOrchestrator) validateImportVolume(ctx context.Context, volumeCo return nil } +// LegacyImportVolume imports a volume from a backend. +// It returns a VolumeExternal object. +// Parameters: +// volumeConfig: VolumeConfig object +// backendName: Name of the backend +// notManaged: If true, the volume is not managed by Trident +// createPVandPVC: Callback function to create PV and PVC for the volume +// Returns: +// VolumeExternal object +// error +// Example: +// importVol, err := orchestrator.LegacyImportVolume(volumeConfig, backendName, notManaged, createPVandPVC) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) LegacyImportVolume( ctx context.Context, volumeConfig *storage.VolumeConfig, backendName string, notManaged bool, createPVandPVC VolumeCallback, @@ -2305,6 +2705,25 @@ func (o *TridentOrchestrator) LegacyImportVolume( return volExternal, nil } +// ImportVolume imports a volume into Trident. +// It returns the volume's external representation. +// Parameters: +// volumeConfig - the volume's configuration +// backendUUID - the UUID of the backend where the volume is located +// originalName - the original name of the volume +// Returns: +// *storage.VolumeExternal - the volume's external representation +// error - any error encountered +// Example: +// volumeConfig := &storage.VolumeConfig{ +// Name: "testvol", +// Size: "1GiB", +// } +// externalVol, err := orchestrator.ImportVolume(ctx, volumeConfig, "backend1", "testvol") +// if err != nil { +// log.Fatal("Failed to +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ImportVolume( ctx context.Context, volumeConfig *storage.VolumeConfig, ) (externalVol *storage.VolumeExternal, err error) { @@ -2435,6 +2854,18 @@ func (o *TridentOrchestrator) AddVolumeTransaction(ctx context.Context, volTxn * return o.storeClient.AddVolumeTransaction(ctx, volTxn) } +// GetVolumeCreatingTransaction returns a VolumeTransaction with the specified +// VolumeConfig if one exists. +// Parameters: +// ctx - context +// config - volume config +// Returns: +// *storage.VolumeTransaction - volume transaction +// error - error +// Example: +// txn, err := GetVolumeCreatingTransaction(ctx, config) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetVolumeCreatingTransaction( ctx context.Context, config *storage.VolumeConfig, ) (*storage.VolumeTransaction, error) { @@ -2454,6 +2885,20 @@ func (o *TridentOrchestrator) GetVolumeCreatingTransaction( } } +// GetVolumeTransaction retrieves a volume transaction from the persistent store +// It returns a volume transaction and an error if one occurred +// Parameters: +// ctx - context for the request +// volTxn - the volume transaction to retrieve +// Returns: +// *storage.VolumeTransaction - the retrieved volume transaction +// error - an error if one occurred +// Example: +// volTxn, err := o.GetVolumeTransaction(ctx, &storage.VolumeTransaction{ +// TransactionID: "abc123", +// }) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetVolumeTransaction( ctx context.Context, volTxn *storage.VolumeTransaction, ) (*storage.VolumeTransaction, error) { @@ -2578,6 +3023,22 @@ func (o *TridentOrchestrator) addVolumeRetryCleanup( return err } +// importVolumeCleanup is called when an +// It returns an error if it was unable to clean up the volume. +// Parameters: +// err: the error that caused the cleanup to be called +// volumeConfig: the volume config for the volume being imported +// volTxn: the volume transaction for the volume being imported +// Returns: +// error: any error encountered during cleanup +// Example: +// err := o.importVolumeCleanup(ctx, err, volumeConfig, volTxn) +// if err != nil { +// Logc(ctx).Warnf("Unable to clean up artifacts of volume import: %v. Repeat importing the volume %v.", +// err, volumeConfig.ImportOriginalName) +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) importVolumeCleanup( ctx context.Context, err error, volumeConfig *storage.VolumeConfig, volTxn *storage.VolumeTransaction, ) error { @@ -2632,6 +3093,16 @@ func (o *TridentOrchestrator) importVolumeCleanup( return err } +// GetVolume returns a volume +// Parameters: +// volume - the name of the volume +// Returns: +// *storage.VolumeExternal - the volume object +// error - any error encountered +// Example: +// volume, err := orchestrator.GetVolume("volume-123") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetVolume( ctx context.Context, volume string, ) (volExternal *storage.VolumeExternal, err error) { @@ -2647,6 +3118,19 @@ func (o *TridentOrchestrator) GetVolume( return o.getVolume(ctx, volume) } +// getVolume returns a volume by name +// Parameters: +// volume - name of the volume to retrieve +// Returns: +// *storage.VolumeExternal - volume object +// error - error, if any +// Example: +// vol, err := trident.getVolume(ctx, "vol1") +// if err != nil { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) getVolume( _ context.Context, volume string, ) (volExternal *storage.VolumeExternal, err error) { @@ -2657,6 +3141,16 @@ func (o *TridentOrchestrator) getVolume( return vol.ConstructExternal(), nil } +// GetDriverTypeForVolume returns the driver +// Parameters: +// vol - the volume to query +// Returns: +// driver type +// error +// Example: +// driverType, err := o.GetDriverTypeForVolume(vol) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetDriverTypeForVolume(_ context.Context, vol *storage.VolumeExternal) (string, error) { if o.bootstrapError != nil { return config.UnknownDriver, o.bootstrapError @@ -2679,6 +3173,16 @@ func (o *TridentOrchestrator) getDriverTypeForVolume(backendUUID string) (string return config.UnknownDriver, nil } +// GetVolumeType returns the volume +// Parameters: +// vol *storage.VolumeExternal +// Returns: +// volumeType config.VolumeType +// err error +// Example: +// volumeType, err := o.GetVolumeType(vol) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetVolumeType( _ context.Context, vol *storage.VolumeExternal, ) (volumeType config.VolumeType, err error) { @@ -2712,6 +3216,17 @@ func (o *TridentOrchestrator) GetVolumeType( return } +// ListVolumes returns a list of volumes. +// Parameters: +// context - context for the call +// options - options for the call +// Returns: +// volumes - list of volumes +// err - error object +// Example: +// volumes, err := orchestrator.ListVolumes(context, options) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ListVolumes(context.Context) (volumes []*storage.VolumeExternal, err error) { if o.bootstrapError != nil { return nil, o.bootstrapError @@ -2829,6 +3344,18 @@ func (o *TridentOrchestrator) deleteVolume(ctx context.Context, volumeName strin return nil } +// deleteVolumeFromPersistentStoreIgnoreError deletes a volume from the persistent store, ignoring +// errors if the volume is not found. +// It returns an error if the volume is found but cannot be deleted. +// Parameters: +// ctx - context for logging +// volume - volume to delete +// Returns: +// error - error if the volume is found but cannot be deleted +// Example: +// err := o.deleteVolumeFromPersistentStoreIgnoreError(ctx, volume) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) deleteVolumeFromPersistentStoreIgnoreError( ctx context.Context, volume *storage.Volume, ) error { @@ -2902,6 +3429,17 @@ func (o *TridentOrchestrator) DeleteVolume(ctx context.Context, volumeName strin return o.deleteVolume(ctx, volumeName) } +// ListVolumesByPlugin returns all volumes managed by the specified plugin. +// Parameters: +// pluginName - name of the plugin +// Return: +// volumes - list of volumes managed by the plugin +// err - error if any +// Example: +// List of volumes managed by the ontap-nas plugin +// volumes, err := orchestrator.ListVolumesByPlugin(context.Background(), "ontap-nas") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ListVolumesByPlugin( _ context.Context, pluginName string, ) (volumes []*storage.VolumeExternal, err error) { @@ -2926,6 +3464,17 @@ func (o *TridentOrchestrator) ListVolumesByPlugin( return volumes, nil } +// PublishVolume publishes a volume to a node +// It returns an error if the volume is not found or is being deleted +// Parameters: +// volumeName - the name of the volume to publish +// publishInfo - the information about the node to publish to +// Return: +// error - nil if successful +// Example: +// err := orchestrator.PublishVolume("volume1", &utils.VolumePublishInfo{NodeID: "node1"}) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) PublishVolume( ctx context.Context, volumeName string, publishInfo *utils.VolumePublishInfo, ) (err error) { @@ -2977,6 +3526,17 @@ func (o *TridentOrchestrator) PublishVolume( return nil } +// UnpublishVolume unpublishes a volume from a node. +// It returns an error if the volume is not found or if the node is not found. +// Parameters: +// volumeName - the name of the volume to be unpublished +// nodeName - the name of the node from which to unpublish the volume +// Returns: +// error - any error encountered +// Example: +// err := c.UnpublishVolume("vol0", "node0") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) UnpublishVolume(ctx context.Context, volumeName, nodeName string) (err error) { if o.bootstrapError != nil { return o.bootstrapError @@ -3341,6 +3901,18 @@ func (o *TridentOrchestrator) addSnapshotCleanup( return err } +// GetSnapshot returns a snapshot object +// Parameters: +// ctx - context for logging +// volumeName - name of the volume +// snapshotName - name of the snapshot +// Returns: +// snapshotExternal - snapshot object +// err - error object +// Example: +// snapshotExternal, err := orchestrator.GetSnapshot(ctx, "volume1", "snapshot1") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetSnapshot( ctx context.Context, volumeName, snapshotName string, ) (snapshotExternal *storage.SnapshotExternal, err error) { @@ -3356,6 +3928,20 @@ func (o *TridentOrchestrator) GetSnapshot( return o.getSnapshot(ctx, volumeName, snapshotName) } +// getSnapshot returns the snapshot with the given name +// Parameters: +// volumeName - name of the volume the snapshot is associated with +// snapshotName - name of the snapshot to retrieve +// Returns: +// *storage.SnapshotExternal - the snapshot with the given name +// error - any error encountered +// Example: +// snapshot, err := o.getSnapshot(ctx, "vol1", "snap1") +// if err != nil { +// return nil, err +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) getSnapshot( ctx context.Context, volumeName, snapshotName string, ) (*storage.SnapshotExternal, error) { @@ -3374,6 +3960,18 @@ func (o *TridentOrchestrator) getSnapshot( } } +// updateSnapshot updates the snapshot state from the backend +// It returns the updated snapshot and an error +// Parameters: +// ctx - context +// snapshot - the snapshot to update +// Returns: +// *storage.Snapshot - the updated snapshot +// error - any error encountered +// Example: +// updatedSnapshot, err := o.updateSnapshot(ctx, snapshot) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) updateSnapshot( ctx context.Context, snapshot *storage.Snapshot, ) (*storage.Snapshot, error) { @@ -3471,6 +4069,18 @@ func (o *TridentOrchestrator) deleteSnapshot(ctx context.Context, snapshotConfig return nil } +// deleteSnapshotFromPersistentStoreIgnoreError deletes a snapshot from the persistent store, +// ignoring errors if the snapshot is not found. +// It returns an error if the snapshot is found but cannot be deleted. +// Parameters: +// ctx - context +// snapshot - snapshot to be deleted +// Returns: +// error - error if the snapshot is found but cannot be deleted +// Example: +// err := o.deleteSnapshotFromPersistentStoreIgnoreError(ctx, snapshot) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) deleteSnapshotFromPersistentStoreIgnoreError( ctx context.Context, snapshot *storage.Snapshot, ) error { @@ -3587,6 +4197,23 @@ func (o *TridentOrchestrator) DeleteSnapshot(ctx context.Context, volumeName, sn return o.deleteSnapshot(ctx, snapshot.Config) } +// ListSnapshots returns a list of snapshots +// Parameters: +// context - context for logging +// filter - a filter to apply to the list of snapshots +// Returns: +// a list of snapshots +// an error if the operation fails +// Example: +// snapshots, err := c.ListSnapshots(context.Background(), nil) +// if err != nil { +// return err +// } +// for _, snapshot := range snapshots { +// fmt.Printf("%s\n", snapshot.Config.Name) +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ListSnapshots(context.Context) (snapshots []*storage.SnapshotExternal, err error) { if o.bootstrapError != nil { return nil, o.bootstrapError @@ -3605,6 +4232,20 @@ func (o *TridentOrchestrator) ListSnapshots(context.Context) (snapshots []*stora return snapshots, nil } +// ListSnapshotsByName returns a list of snapshots that match the given name. +// Parameters: +// snapshotName - the name of the snapshot to match +// volumeID - the ID of the volume to match +// volumeName - the name of the volume to match +// volume - the volume to match +// all - if true, return all snapshots, otherwise only return snapshots that are not deleted +// Returns: +// a list of snapshots that match the given name +// an error, if any +// Example: +// snapshots, err := orchestrator.ListSnapshotsByName(context.Background(), "mysnapshot") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ListSnapshotsByName( _ context.Context, snapshotName string, ) (snapshots []*storage.SnapshotExternal, err error) { @@ -3627,6 +4268,15 @@ func (o *TridentOrchestrator) ListSnapshotsByName( return snapshots, nil } +// ListSnapshotsForVolume returns a list of snapshots for a given volume. +// Parameters: +// volumeName (string) - the name of the volume +// Returns: +// ([]*storage.SnapshotExternal, error) - a list of snapshots and an error if one occurred +// Example: +// snapshots, err := orchestrator.ListSnapshotsForVolume("vol1") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ListSnapshotsForVolume( _ context.Context, volumeName string, ) (snapshots []*storage.SnapshotExternal, err error) { @@ -3653,6 +4303,17 @@ func (o *TridentOrchestrator) ListSnapshotsForVolume( return snapshots, nil } +// ReadSnapshotsForVolume reads all snapshots for a given volume +// It returns a list of SnapshotExternal objects +// Parameters: +// volumeName: the name of the volume +// Returns: +// a list of SnapshotExternal objects +// an error, if any +// Example: +// snapshots, err := orchestrator.ReadSnapshotsForVolume("vol1") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ReadSnapshotsForVolume( ctx context.Context, volumeName string, ) (externalSnapshots []*storage.SnapshotExternal, err error) { @@ -3680,6 +4341,16 @@ func (o *TridentOrchestrator) ReadSnapshotsForVolume( return externalSnapshots, nil } +// ReloadVolumes reloads all volumes from the backend +// It returns an error if the reload fails +// Parameters: +// ctx - context +// Returns: +// error - error if the reload fails +// Example: +// err := o.ReloadVolumes(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ReloadVolumes(ctx context.Context) (err error) { if o.bootstrapError != nil { return o.bootstrapError @@ -3938,6 +4609,18 @@ func (o *TridentOrchestrator) getProtocol( return res.protocol, res.err } +// AddStorageClass adds a storage class to the orchestrator +// It returns the storage class that was added +// Parameters: +// ctx - context for logging +// scConfig - storage class configuration +// Returns: +// *storageclass.External - storage class that was added +// error - error if any +// Example: +// sc, err := o.AddStorageClass(ctx, scConfig) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) AddStorageClass( ctx context.Context, scConfig *storageclass.Config, ) (scExternal *storageclass.External, err error) { @@ -3976,6 +4659,16 @@ func (o *TridentOrchestrator) AddStorageClass( return sc.ConstructExternal(ctx), nil } +// GetStorageClass returns the storage class with the given name +// Parameters: +// scName - name of the storage class to retrieve +// Returns: +// *storageclass.External - the storage class with the given name +// error - nil if no error occurred +// Example: +// storageclass, err := o.GetStorageClass("my-storage-class") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetStorageClass( ctx context.Context, scName string, ) (scExternal *storageclass.External, err error) { @@ -3997,6 +4690,19 @@ func (o *TridentOrchestrator) GetStorageClass( return sc.ConstructExternal(ctx), nil } +// ListStorageClasses returns a list of all storage classes +// Parameters: +// ctx - context for logging +// Returns: +// []*storageclass.External - a list of storage classes +// error - any error encountered +// Example: +// storageClasses, err := o.ListStorageClasses(context.Background()) +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ListStorageClasses(ctx context.Context) ( scExternals []*storageclass.External, err error, ) { @@ -4016,6 +4722,20 @@ func (o *TridentOrchestrator) ListStorageClasses(ctx context.Context) ( return storageClasses, nil } +// DeleteStorageClass deletes a storage class +// It returns an error if the storage class is not found +// Parameters: +// scName - name of the storage class to delete +// ctx - context for the request +// Returns: +// error - if the storage class is not found +// Example: +// err := orchestrator.DeleteStorageClass(ctx, "mystorageclass") +// if err != nil { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) DeleteStorageClass(ctx context.Context, scName string) (err error) { if o.bootstrapError != nil { return o.bootstrapError @@ -4047,6 +4767,20 @@ func (o *TridentOrchestrator) DeleteStorageClass(ctx context.Context, scName str return nil } +// reconcileNodeAccessOnAllBackends reconciles node access on all backends. +// It returns an error if any of the backends fail to reconcile. +// Parameters: +// ctx - context +// Returns: +// error - if any of the backends fail to reconcile +// Example: +// ctx := context.Background() +// err := o.reconcileNodeAccessOnAllBackends(ctx) +// if err != nil { +// ... +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) reconcileNodeAccessOnAllBackends(ctx context.Context) error { if config.CurrentDriverContext != config.ContextCSI { return nil @@ -4067,6 +4801,20 @@ func (o *TridentOrchestrator) reconcileNodeAccessOnAllBackends(ctx context.Conte return nil } +// reconcileNodeAccessOnBackend reconciles the node access on the backend +// It returns an error if the operation fails +// Parameters: +// ctx - context +// b - backend +// Returns: +// error - error if the operation fails +// Example: +// err := o.reconcileNodeAccessOnBackend(ctx, b) +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) reconcileNodeAccessOnBackend(ctx context.Context, b storage.Backend) error { if config.CurrentDriverContext != config.ContextCSI { return nil @@ -4124,6 +4872,18 @@ func (o *TridentOrchestrator) PeriodicallyReconcileNodeAccessOnBackends() { } } +// AddNode adds a node to the orchestrator +// It returns an error if the node already exists +// Parameters: +// ctx - context +// node - the node to add +// nodeEventCallback - callback function to invoke when a node event occurs +// Returns: +// error - any error encountered +// Example: +// err := o.AddNode(ctx, node) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) AddNode( ctx context.Context, node *utils.Node, nodeEventCallback NodeEventCallback, ) (err error) { @@ -4166,12 +4926,31 @@ func (o *TridentOrchestrator) AddNode( return nil } +// invalidateAllBackendNodeAccess invalidates the node access for all backends +// Returns: +// none +// Example: +// orchestrator.invalidateAllBackendNodeAccess() +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) invalidateAllBackendNodeAccess() { for _, backend := range o.backends { backend.InvalidateNodeAccess() } } +// handleUpdatedNodePrep handles the node prep status for a node that has been updated. +// Parameters: +// ctx - context for logging +// protocol - the protocol for which node prep is being reported +// node - the node object +// nodeEventCallback - a callback function to be called to report an event +// Returns: +// none +// Example: +// o.handleUpdatedNodePrep(ctx, "NFS", node, nodeEventCallback) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) handleUpdatedNodePrep( ctx context.Context, protocol string, node *utils.Node, nodeEventCallback NodeEventCallback, ) { @@ -4213,6 +4992,20 @@ func (o *TridentOrchestrator) handleUpdatedNodePrep( } } +// GetNode returns the node object for the specified node name. +// Parameters: +// ctx - context for logging +// nName - name of the node +// Returns: +// *utils.Node - node object +// error - error object +// Example: +// node, err := o.GetNode(ctx, "node01") +// if err != nil { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetNode(ctx context.Context, nName string) (node *utils.Node, err error) { if o.bootstrapError != nil { return nil, o.bootstrapError @@ -4233,6 +5026,16 @@ func (o *TridentOrchestrator) GetNode(ctx context.Context, nName string) (node * return node, nil } +// ListNodes returns a list of all nodes known to the orchestrator. +// Parameters: +// ctx - context for the request +// Returns: +// []*utils.Node - list of nodes +// error - non-nil if an error occurred +// Example: +// nodes, err := api.ListNodes(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) ListNodes(context.Context) (nodes []*utils.Node, err error) { if o.bootstrapError != nil { return nil, o.bootstrapError @@ -4250,6 +5053,16 @@ func (o *TridentOrchestrator) ListNodes(context.Context) (nodes []*utils.Node, e return nodes, nil } +// DeleteNode removes a node from the orchestrator. +// It returns an error if the node is not found. +// Parameters: +// nodeName - the name of the node to delete +// Returns: +// error - any error encountered +// Example: +// err := orchestrator.DeleteNode("mynode") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) DeleteNode(ctx context.Context, nodeName string) (err error) { if o.bootstrapError != nil { return o.bootstrapError @@ -4294,6 +5107,17 @@ func (o *TridentOrchestrator) DeleteNode(ctx context.Context, nodeName string) ( return nil } +// deleteNode deletes a node from the orchestrator +// It returns an error if the node is not found, or if the node is in use +// Parameters: +// ctx - context for the request +// nodeName - name of the node to delete +// Return: +// error - if the node is not found, or if the node is in use +// Example: +// err := o.deleteNode(ctx, "node1") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) deleteNode(ctx context.Context, nodeName string) (err error) { node, found := o.nodes[nodeName] if !found { @@ -4391,6 +5215,15 @@ func (o *TridentOrchestrator) ListVolumePublicationsForVolume( return } +// listVolumePublicationsForVolume returns the list of volume publications for a given volume +// Parameters: +// volumeName - name of the volume +// Returns: +// list of volume publications for the given volume +// Example: +// publications := o.listVolumePublicationsForVolume(ctx, "foo") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) listVolumePublicationsForVolume( _ context.Context, volumeName string, ) (publications []*utils.VolumePublication) { @@ -4418,6 +5251,15 @@ func (o *TridentOrchestrator) ListVolumePublicationsForNode( return } +// listVolumePublicationsForNode returns the list of volume publications for the given node +// Parameters: +// nodeName - the name of the node +// Returns: +// []*utils.VolumePublication - the list of volume publications for the node +// Example: +// publications := o.listVolumePublicationsForNode(nodeName) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) listVolumePublicationsForNode( _ context.Context, nodeName string, ) (publications []*utils.VolumePublication) { @@ -4456,6 +5298,16 @@ func (o *TridentOrchestrator) DeleteVolumePublication(ctx context.Context, volum return nil } +// removeVolumePublicationFromCache removes the volume publication from the cache +// Parameters: +// volumeID: the volume ID +// nodeID: the node ID +// Returns: +// None +// Example: +// removeVolumePublicationFromCache(volumeID, nodeID) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) removeVolumePublicationFromCache(volumeID, nodeID string) { delete(o.volumePublications[volumeID], nodeID) // If there are no more nodes for this volume, remove the volume's entry @@ -4464,6 +5316,21 @@ func (o *TridentOrchestrator) removeVolumePublicationFromCache(volumeID, nodeID } } +// updateBackendOnPersistentStore updates the backend information on the persistent store +// It returns an error if the update fails. +// Parameters: +// ctx - context +// backend - backend to update +// newBackend - true if this is a new backend +// Returns: +// error - error if the update fails +// Example: +// err := o.updateBackendOnPersistentStore(ctx, backend, true) +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) updateBackendOnPersistentStore( ctx context.Context, backend storage.Backend, newBackend bool, ) error { @@ -4487,6 +5354,21 @@ func (o *TridentOrchestrator) updateBackendOnPersistentStore( return nil } +// updateVolumeOnPersistentStore updates the volume information in persistent store +// It returns an error if the volume cannot be updated. +// Parameters: +// ctx - context for logging +// vol - volume to be updated +// Returns: +// error - error if the volume cannot be updated +// Example: +// err := orchestrator.updateVolumeOnPersistentStore(ctx, vol) +// if err != nil { +// log.Errorf("Could not update volume %s on persistent store: %v", +// vol.Config.Name, err) +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) updateVolumeOnPersistentStore(ctx context.Context, vol *storage.Volume) error { // Update the volume information in persistent store Logc(ctx).WithFields(log.Fields{ @@ -4498,6 +5380,20 @@ func (o *TridentOrchestrator) updateVolumeOnPersistentStore(ctx context.Context, return o.storeClient.UpdateVolume(ctx, vol) } +// replaceBackendAndUpdateVolumesOnPersistentStore updates both backend and volume information in persistent store +// It returns an error if the backend or volume information cannot be updated. +// Parameters: +// origBackend - the original backend +// newBackend - the new backend +// Returns: +// error - if the backend or volume information cannot be updated +// Example: +// err := o.replaceBackendAndUpdateVolumesOnPersistentStore(ctx, origBackend, newBackend) +// if err != nil { +// Logc(ctx).Errorf("Error updating backend %s and volumes: %v", newBackend.Name(), err) +// } +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) replaceBackendAndUpdateVolumesOnPersistentStore( ctx context.Context, origBackend, newBackend storage.Backend, ) error { @@ -4509,6 +5405,16 @@ func (o *TridentOrchestrator) replaceBackendAndUpdateVolumesOnPersistentStore( return o.storeClient.ReplaceBackendAndUpdateVolumes(ctx, origBackend, newBackend) } +// isCRDContext returns true if the context is from a CRD request +// Parameters: +// ctx - the context +// Returns: +// true if the context is from a CRD request +// Example: +// ctx := context.WithValue(context.Background(), ContextKeyRequestSource, ContextSourceCRD) +// core.isCRDContext(ctx) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) isCRDContext(ctx context.Context) bool { ctxSource := ctx.Value(ContextKeyRequestSource) return ctxSource != nil && ctxSource == ContextSourceCRD @@ -4606,6 +5512,16 @@ func (o *TridentOrchestrator) GetMirrorStatus( return mirrorBackend.GetMirrorStatus(ctx, localVolumeHandle, remoteVolumeHandle) } +// CanBackendMirror returns true if the backend is capable of mirroring +// Parameters: +// backendUUID - the backend UUID +// Returns: +// capable - true if the backend is capable of mirroring +// err - any error encountered +// Example: +// capable, err := tridentcore.CanBackendMirror(backendUUID) +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) CanBackendMirror(_ context.Context, backendUUID string) (capable bool, err error) { if o.bootstrapError != nil { return false, o.bootstrapError @@ -4645,6 +5561,17 @@ func (o *TridentOrchestrator) ReleaseMirror( return mirrorBackend.ReleaseMirror(ctx, localVolumeHandle) } +// GetCHAP returns CHAP information for a volume +// Parameters: +// volumeName - Name of the volume +// nodeName - Name of the node +// Returns: +// chapInfo - CHAP information for the volume +// err - error object +// Example: +// chapInfo, err := orchestrator.GetCHAP(ctx, "vol1", "node1") +// +// -- Doc autogenerated on 2022-05-12 19:51:03.426932 -- func (o *TridentOrchestrator) GetCHAP( ctx context.Context, volumeName, nodeName string, ) (chapInfo *utils.IscsiChapInfo, err error) { diff --git a/core/orchestrator_core_test.go b/core/orchestrator_core_test.go index 3cc7ecf2a..83ffdee7d 100644 --- a/core/orchestrator_core_test.go +++ b/core/orchestrator_core_test.go @@ -61,6 +61,16 @@ type recoveryTest struct { expectDestroy bool } +// cleanup cleans up the persistent store and the in-memory client. +// Parameters: +// t: the test object +// o: the orchestrator +// Returns: +// None +// Example: +// cleanup(t, o) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func cleanup(t *testing.T, o *TridentOrchestrator) { err := o.storeClient.DeleteBackends(ctx()) if err != nil && !persistentstore.MatchKeyNotFoundErr(err) { @@ -94,6 +104,28 @@ func cleanup(t *testing.T, o *TridentOrchestrator) { } } +// diffConfig compares two structs of the same +// It returns a list of differences +// Parameters: +// expected: the expected struct +// got: the actual struct +// fieldToSkip: a field to skip when comparing +// Returns: +// a list of differences +// Example: +// expected := &Config{ +// Debug: true, +// LogFile: "/tmp/log", +// } +// got := &Config{ +// Debug: false, +// LogFile: "/tmp/log", +// } +// diffs := diffConfig(expected, got, "") +// fmt.Println(diffs) +// // Output: [Debug: expected true, got false] +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func diffConfig(expected, got interface{}, fieldToSkip string) []string { diffs := make([]string, 0) expectedStruct := reflect.Indirect(reflect.ValueOf(expected)) @@ -120,6 +152,20 @@ func diffConfig(expected, got interface{}, fieldToSkip string) []string { } // To be called after reflect.DeepEqual has failed. +// diffExternalBackends compares two external backends and returns a list of differences +// Parameters: +// t: test object +// expected: expected backend +// got: actual backend +// Returns: +// diffs: list of differences +// Example: +// diffs := diffExternalBackends(t, expected, got) +// if len(diffs) > 0 { +// t.Errorf("External backends differ:\n\t%s", strings.Join(diffs, "\n\t")) +// } +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func diffExternalBackends(t *testing.T, expected, got *storage.BackendExternal) { diffs := make([]string, 0) @@ -210,6 +256,19 @@ func diffExternalBackends(t *testing.T, expected, got *storage.BackendExternal) } } +// runDeleteTest runs a single test for the DeleteVolume method. +// Parameters: +// t: The test object +// d: The test definition +// orchestrator: The orchestrator object +// Returns: +// Nothing +// Example: +// runDeleteTest(t, &deleteTest{ +// "myvol1", true, +// }, orchestrator) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func runDeleteTest( t *testing.T, d *deleteTest, orchestrator *TridentOrchestrator, ) { @@ -267,6 +326,16 @@ type storageClassTest struct { expected []*tu.PoolMatch } +// getOrchestrator returns a new TridentOrchestrator instance with a new +// in-memory persistent store. +// Parameters: +// t *testing.T - the test object +// Returns: +// *TridentOrchestrator - the new orchestrator +// Example: +// o := getOrchestrator(t) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func getOrchestrator(t *testing.T) *TridentOrchestrator { var ( storeClient persistentstore.Client @@ -284,6 +353,21 @@ func getOrchestrator(t *testing.T) *TridentOrchestrator { return o } +// validateStorageClass validates that the storage class matches the expected pools. +// Parameters: +// t: Test object +// o: Orchestrator +// name: Name of the storage class +// expected: List of expected pool matches +// Returns: +// None +// Example: +// validateStorageClass(t, o, "sc1", []*tu.PoolMatch{ +// &tu.PoolMatch{Backend: "mock1", Pool: "gold"}, +// &tu.PoolMatch{Backend: "mock2", Pool: "platinum"}, +// }) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func validateStorageClass( t *testing.T, o *TridentOrchestrator, @@ -821,6 +905,11 @@ func TestAddStorageClassVolumes(t *testing.T) { // This test is modeled after TestAddStorageClassVolumes, but we don't need all the // tests around storage class deletion, etc. +// TestCloneVolumes tests the clone volume functionality. +// It checks that the clone is placed in the same backend as the source volume. +// It also checks that the clone is stored in the persistent store. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestCloneVolumes(t *testing.T) { mockPools := tu.GetFakePools() orchestrator := getOrchestrator(t) @@ -1092,6 +1181,18 @@ func TestCloneVolumes(t *testing.T) { cleanup(t, orchestrator) } +// addBackend adds a backend to the orchestrator. +// Parameters: +// t: test object +// orchestrator: orchestrator object +// backendName: name of the backend to add +// backendProtocol: protocol of the backend to add +// Returns: +// None +// Example: +// addBackend(t, orchestrator, "fakeBackend", config.File) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func addBackend( t *testing.T, orchestrator *TridentOrchestrator, backendName string, backendProtocol config.Protocol, ) { @@ -1150,6 +1251,19 @@ func addBackendStorageClass( } } +// captureOutput captures the output of the given function and returns it as a string +// It returns an empty string if the function does not produce any output +// Parameters: +// f: the function to capture the output of +// Returns: +// the output of the function as a string +// Example: +// output := captureOutput(func() { +// log.Println("Hello, World!") +// }) +// // output = "Hello, World!" +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func captureOutput(f func()) string { var buf bytes.Buffer log.SetOutput(&buf) @@ -1158,6 +1272,15 @@ func captureOutput(f func()) string { return buf.String() } +// TestBackendUpdateAndDelete tests the update and delete functionality of the +// orchestrator. +// It checks that the orchestrator can update a backend, that the storage class +// is updated to point to the new backend, and that the volume points to the +// right storage pool. +// It also checks that the orchestrator can offline a backend, and that the +// storage class is updated to remove the backend. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestBackendUpdateAndDelete(t *testing.T) { const ( backendName = "updateBackend" @@ -1469,6 +1592,17 @@ func TestBackendUpdateAndDelete(t *testing.T) { cleanup(t, orchestrator) } +// backendPasswordsInLogsHelper is a helper function that checks if the backend config +// is suppressed in the logs. +// Parameters: +// t: test object +// debugTraceFlags: debug trace flags +// Returns: +// None +// Example: +// backendPasswordsInLogsHelper(t, debugTraceFlags) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func backendPasswordsInLogsHelper(t *testing.T, debugTraceFlags map[string]bool) { backendName := "passwordBackend" backendProtocol := config.File @@ -1515,11 +1649,21 @@ func backendPasswordsInLogsHelper(t *testing.T, debugTraceFlags map[string]bool) cleanup(t, orchestrator) } +// TestBackendPasswordsInLogs tests that backend passwords are not logged. +// It checks that the backend password is not logged when the backend is created, +// and that it is not logged when the backend is used. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestBackendPasswordsInLogs(t *testing.T) { backendPasswordsInLogsHelper(t, nil) backendPasswordsInLogsHelper(t, map[string]bool{"method": true}) } +// TestEmptyBackendDeletion tests that an empty backend can be deleted. +// It checks that the backend is removed from the orchestrator's memory +// and that the backend is removed from the store client. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestEmptyBackendDeletion(t *testing.T) { const ( backendName = "emptyBackend" @@ -1555,6 +1699,11 @@ func TestEmptyBackendDeletion(t *testing.T) { cleanup(t, orchestrator) } +// TestBootstrapSnapshotMissingVolume tests that a snapshot in the missing_volume state is +// bootstrapped correctly. +// It checks that the snapshot is bootstrapped with the correct state, and that it can be deleted. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestBootstrapSnapshotMissingVolume(t *testing.T) { const ( offlineBackendName = "snapNoVolBackend" @@ -1613,6 +1762,10 @@ func TestBootstrapSnapshotMissingVolume(t *testing.T) { } } +// TestBootstrapSnapshotMissingBackend tests bootstrapping a snapshot that has a missing backend. +// It checks that the snapshot is in the missing_backend state. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestBootstrapSnapshotMissingBackend(t *testing.T) { const ( offlineBackendName = "snapNoBackBackend" @@ -1671,6 +1824,11 @@ func TestBootstrapSnapshotMissingBackend(t *testing.T) { } } +// TestBootstrapVolumeMissingBackend tests that a volume in missing_backend state is bootstrapped +// correctly. +// It checks that the volume is bootstrapped with the correct state and that it can be deleted. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestBootstrapVolumeMissingBackend(t *testing.T) { const ( offlineBackendName = "bootstrapVolBackend" @@ -1723,6 +1881,12 @@ func TestBootstrapVolumeMissingBackend(t *testing.T) { } } +// TestBackendCleanup tests that when a backend is deleted, it is also removed +// from the backend store. +// It checks that when the orchestrator is restarted, the backend is not +// bootstrapped. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestBackendCleanup(t *testing.T) { const ( offlineBackendName = "cleanupBackend" @@ -1773,6 +1937,10 @@ func TestBackendCleanup(t *testing.T) { } } +// TestLoadBackend tests that a backend can be loaded from a config file. +// It checks that the backend is the same after being loaded from the config file. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestLoadBackend(t *testing.T) { const ( backendName = "load-backend-test" @@ -1825,6 +1993,19 @@ func TestLoadBackend(t *testing.T) { cleanup(t, orchestrator) } +// prepRecoveryTest sets up a backend and storage class for testing recovery +// tests. +// Parameters: +// t: the test object +// orchestrator: the orchestrator object +// backendName: the name of the backend to create +// scName: the name of the storage class to create +// Returns: +// None +// Example: +// prepRecoveryTest(t, orchestrator, "recoveryTest", "recoveryTestSC") +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func prepRecoveryTest( t *testing.T, orchestrator *TridentOrchestrator, backendName, scName string, ) { @@ -1862,6 +2043,20 @@ func prepRecoveryTest( } } +// runRecoveryTests runs a set of tests that ensure that the orchestrator +// can recover from a partially completed volume addition. +// Parameters: +// t: The test object +// orchestrator: The orchestrator to be tested +// backendName: The name of the backend to be used +// op: The operation to be tested (add or delete) +// testCases: The set of tests to be run +// Returns: +// None +// Example: +// runRecoveryTests(t, orchestrator, "test-backend", storage.AddVolume, addRecoveryTests) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func runRecoveryTests( t *testing.T, orchestrator *TridentOrchestrator, @@ -1918,6 +2113,12 @@ func runRecoveryTests( } } +// TestAddVolumeRecovery tests that adding a volume is properly rolled back +// when the transaction is rolled back. +// It checks both the case where the volume is added to the orchestrator and +// the case where it is only added to the transaction. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestAddVolumeRecovery(t *testing.T) { const ( backendName = "addRecoveryBackend" @@ -1946,6 +2147,12 @@ func TestAddVolumeRecovery(t *testing.T) { cleanup(t, orchestrator) } +// TestAddVolumeWithTMRNonONTAPNAS tests that we fail to add a volume with +// a relationship annotation if the backend is not ONTAP NAS +// It checks that we fail to add a volume with a relationship annotation +// if the backend is not ONTAP NAS +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestAddVolumeWithTMRNonONTAPNAS(t *testing.T) { // Add a single backend of fake // create volume with relationship annotation added @@ -1972,6 +2179,12 @@ func TestAddVolumeWithTMRNonONTAPNAS(t *testing.T) { cleanup(t, orchestrator) } +// TestDeleteVolumeRecovery tests that the orchestrator can recover from a +// partially completed volume deletion. +// It checks that the orchestrator can recover from deleting a volume that +// has been partially deleted. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestDeleteVolumeRecovery(t *testing.T) { const ( backendName = "deleteRecoveryBackend" @@ -2007,6 +2220,17 @@ func TestDeleteVolumeRecovery(t *testing.T) { cleanup(t, orchestrator) } +// generateSnapshotConfig returns a SnapshotConfig object +// Parameters: +// name: name of the snapshot +// volumeName: name of the volume +// volumeInternalName: internal name of the volume +// Returns: +// SnapshotConfig object +// Example: +// config := generateSnapshotConfig("snapshot-name", "volume-name", "volume-internal-name") +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func generateSnapshotConfig( name, volumeName, volumeInternalName string, ) *storage.SnapshotConfig { @@ -2018,6 +2242,31 @@ func generateSnapshotConfig( } } +// runSnapshotRecoveryTests runs a set of tests that verify that the orchestrator +// can recover from a partially completed snapshot operation. +// Parameters: +// t: the test object +// orchestrator: the orchestrator to test +// backendName: the name of the backend to use +// op: the operation to test +// testCases: a slice of recoveryTest objects that describe the test cases to run +// Returns: +// None +// Example: +// runSnapshotRecoveryTests(t, orchestrator, "fake-backend", storage.AddSnapshot, []recoveryTest{ +// { +// name: "AddSnapshot - volume not found", +// volumeConfig: &storage.VolumeConfig{ +// Name: "snap-vol-not-found", +// }, +// snapshotConfig: &storage.SnapshotConfig{ +// Name: "snap-not-found", +// }, +// expectDestroy: false, +// }, +// }) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func runSnapshotRecoveryTests( t *testing.T, orchestrator *TridentOrchestrator, @@ -2078,6 +2327,13 @@ func runSnapshotRecoveryTests( } } +// TestAddSnapshotRecovery tests that the AddSnapshot transaction is properly +// recovered. +// It checks that the snapshot is created and destroyed when the transaction +// is fully recovered, and that the snapshot is not destroyed when only the +// transaction is recovered. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestAddSnapshotRecovery(t *testing.T) { const ( backendName = "addSnapshotRecoveryBackend" @@ -2117,6 +2373,13 @@ func TestAddSnapshotRecovery(t *testing.T) { cleanup(t, orchestrator) } +// TestDeleteSnapshotRecovery tests that delete snapshot transactions are properly +// recovered after a restart. +// It checks that the snapshot is not deleted if the snapshot was fully deleted +// before the restart, and that the snapshot is deleted if the snapshot was only +// partially deleted before the restart. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestDeleteSnapshotRecovery(t *testing.T) { const ( backendName = "deleteSnapshotRecoveryBackend" @@ -2163,6 +2426,12 @@ func TestDeleteSnapshotRecovery(t *testing.T) { // The next series of tests test that bootstrap doesn't exit early if it // encounters a key error for one of the main types of entries. +// TestStorageClassOnlyBootstrap tests that a storage class can be bootstrapped +// without any volumes. +// It checks that the storage class is bootstrapped and that it matches the +// original. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestStorageClassOnlyBootstrap(t *testing.T) { const scName = "storageclass-only" @@ -2190,6 +2459,13 @@ func TestStorageClassOnlyBootstrap(t *testing.T) { cleanup(t, orchestrator) } +// TestFirstVolumeRecovery tests the first volume recovery scenario. +// +// The first volume recovery scenario is when the first volume is added to a +// backend. +// It checks that the volume is destroyed. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestFirstVolumeRecovery(t *testing.T) { const ( backendName = "firstRecoveryBackend" @@ -2211,6 +2487,11 @@ func TestFirstVolumeRecovery(t *testing.T) { cleanup(t, orchestrator) } +// TestOrchestratorNotReady tests the orchestrator when it is not ready. +// It checks that all orchestrator methods return an error. +// It returns an error if any of the methods do not return an error. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestOrchestratorNotReady(t *testing.T) { var ( err error @@ -2349,6 +2630,22 @@ func TestOrchestratorNotReady(t *testing.T) { } } +// importVolumeSetup is a helper function to setup the orchestrator and volume config for +// It returns a pointer to the orchestrator and the volume config +// Parameters: +// t *testing.T - the test object +// backendName - the name of the backend +// scName - the name of the storage class +// volumeName - the name of the volume +// importOriginalName - the original name of the volume being imported +// backendProtocol - the protocol of the backend +// Returns: +// *TridentOrchestrator - a pointer to the orchestrator +// *storage.VolumeConfig - the volume config +// Example: +// orchestrator, volumeConfig := importVolumeSetup(t, "backend1", "sc1", "volume1", "volume2", config.File) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func importVolumeSetup( t *testing.T, backendName, scName, volumeName, importOriginalName string, backendProtocol config.Protocol, @@ -2382,6 +2679,14 @@ func importVolumeSetup( return orchestrator, volumeConfig } +// TestImportVolumeFailures tests the behavior of the orchestrator when +// importing a volume fails. +// It checks that the volume is renamed to its original name, and that +// the persisted state is cleaned up. +// It returns an error if the volume is not renamed, or if the persisted +// state is not cleaned up. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestImportVolumeFailures(t *testing.T) { const ( backendName = "backend82" @@ -2421,6 +2726,12 @@ func TestImportVolumeFailures(t *testing.T) { cleanup(t, orchestrator) } +// TestLegacyImportVolume tests the legacy +// It checks that the volume is imported correctly and that the volume is +// persisted if it is managed. +// It returns the volume name and the volume config. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestLegacyImportVolume(t *testing.T) { const ( backendName = "backend02" @@ -2498,6 +2809,11 @@ func TestLegacyImportVolume(t *testing.T) { cleanup(t, orchestrator) } +// TestImportVolume tests the +// It checks that the volume is imported with the correct internal name +// and that it is persisted in the orchestrator's volume map. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestImportVolume(t *testing.T) { const ( backendName = "backend02" @@ -2555,6 +2871,16 @@ func TestImportVolume(t *testing.T) { cleanup(t, orchestrator) } +// TestValidateImportVolumeNasBackend tests the validateImportVolume function for NAS backends +// It checks for the following error conditions: +// - The volume exists on the backend with the original name +// - The storage class is unknown +// - The volume does not exist on the backend +// - The volume has an incompatible access mode +// - The volume has an incompatible volume mode +// - The volume has an incompatible protocol +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestValidateImportVolumeNasBackend(t *testing.T) { const ( backendName = "backend01" @@ -2633,6 +2959,36 @@ func TestValidateImportVolumeNasBackend(t *testing.T) { cleanup(t, orchestrator) } +// TestValidateImportVolumeSanBackend tests the validateImportVolume function for SAN backends. +// It checks the following conditions: +// - The volume exists on the backend with the original name. +// - The volume is not already imported. +// - The volume is not already attached to a node. +// - The volume is not already in use by a pod. +// - The volume is not already in use by a PVC. +// - The volume is not already in use by a PV. +// - The volume is not already in use by a snapshot. +// - The volume is not already in use by a clone. +// - The volume is not already in use by a volume group. +// - The volume is not already in use by a consistency group. +// - The volume is not already in use by a consistency group snapshot. +// - The volume is not already in use by a consistency group clone. +// - The volume is not already in use by a consistency group view. +// - The volume is not already in use by a snapshot schedule. +// - The volume is not already in use by a snapshot session. +// - The volume is not already in use by a snapshot session clone. +// - The volume is not already in use by a snapshot session view. +// - The volume is not already in use by a snapshot session schedule. +// - The volume is not already in use by an export policy. +// - The volume is not already in use by an export policy rule. +// - The volume is not already in use by an export policy snapshot rule. +// - The volume is not already in use by an export policy clone rule. +// - The volume is not already in use by an export policy view rule. +// - The volume is not already in use by an export policy schedule rule. +// - The volume has the same protocol as the backend. +// - The volume does not have an ext4 filesystem if it's a raw-block volume. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestValidateImportVolumeSanBackend(t *testing.T) { const ( backendName = "backend01" @@ -2694,6 +3050,11 @@ func TestValidateImportVolumeSanBackend(t *testing.T) { cleanup(t, orchestrator) } +// TestAddVolumePublication tests that the orchestrator correctly adds a volume publication +// to its cache, and calls the store client to persist the volume publication +// It checks that the orchestrator's cache is updated correctly +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestAddVolumePublication(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2726,6 +3087,13 @@ func TestAddVolumePublication(t *testing.T) { "volume publication was not correctly added") } +// TestAddVolumePublicationError tests that the orchestrator correctly handles +// errors from the persistent store client +// It checks that the orchestrator does not add the volume publication to its cache +// if the store client returns an error +// It returns an error if the store client returns an error +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestAddVolumePublicationError(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2754,6 +3122,10 @@ func TestAddVolumePublicationError(t *testing.T) { "volume publication was added orchestrator's cache") } +// TestGetVolumePublication tests that a volume publication can be retrieved from the orchestrator +// It checks that the orchestrator correctly retrieves the volume publication from the cache +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetVolumePublication(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2779,6 +3151,11 @@ func TestGetVolumePublication(t *testing.T) { assert.Equal(t, fakePub, actualPub, "volume publication was not correctly retrieved") } +// TestGetVolumePublicationNotFound tests that a volume publication is not found +// when the volume does not exist +// It checks that the correct error is returned and that the publication is empty +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetVolumePublicationNotFound(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2796,6 +3173,10 @@ func TestGetVolumePublicationNotFound(t *testing.T) { assert.Empty(t, actualPub, "non-empty publication returned") } +// TestGetVolumePublicationError tests the error path for GetVolumePublication +// It checks that the correct error is returned when the orchestrator is in a bootstrap error state +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetVolumePublicationError(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2825,6 +3206,10 @@ func TestGetVolumePublicationError(t *testing.T) { assert.Empty(t, actualPub, "non-empty publication returned") } +// TestListVolumePublications tests the ListVolumePublications function +// It checks that the list of volume publications returned is correct +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublications(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2868,6 +3253,10 @@ func TestListVolumePublications(t *testing.T) { assert.ElementsMatch(t, expectedPubs, actualPubs, "incorrect publication list returned") } +// TestListVolumePublicationsNotFound tests the case where no volume publications are found +// It checks that the orchestrator returns an empty list and no error +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublicationsNotFound(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2884,6 +3273,11 @@ func TestListVolumePublicationsNotFound(t *testing.T) { assert.Empty(t, actualPubs, "non-empty publication list returned") } +// TestListVolumePublicationsError tests the ListVolumePublications method +// when the orchestrator is in an error state +// It checks that the method returns an error and an empty list +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublicationsError(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2913,6 +3307,10 @@ func TestListVolumePublicationsError(t *testing.T) { assert.Empty(t, actualPubs, "non-empty publication list returned") } +// TestListVolumePublicationsForVolume tests the ListVolumePublicationsForVolume function +// It checks that the correct publications are returned for a given volume +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublicationsForVolume(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2956,6 +3354,11 @@ func TestListVolumePublicationsForVolume(t *testing.T) { assert.ElementsMatch(t, expectedPubs, actualPubs, "incorrect publication list returned") } +// TestListVolumePublicationsForVolumeNotFound tests the case where a volume is not found +// when listing volume publications +// It checks that an empty list is returned with no error +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublicationsForVolumeNotFound(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -2982,6 +3385,10 @@ func TestListVolumePublicationsForVolumeNotFound(t *testing.T) { assert.Empty(t, actualPubs, "non-empty publication list returned") } +// TestListVolumePublicationsForVolumeError tests the error path of ListVolumePublicationsForVolume +// It checks that the correct error is returned when the orchestrator is in an error state +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublicationsForVolumeError(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -3011,6 +3418,11 @@ func TestListVolumePublicationsForVolumeError(t *testing.T) { assert.Empty(t, actualPubs, "non-empty publication list returned") } +// TestListVolumePublicationsForNode tests the ListVolumePublicationsForNode +// method of the orchestrator +// It checks that the correct publications are returned for a given node +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublicationsForNode(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -3054,6 +3466,11 @@ func TestListVolumePublicationsForNode(t *testing.T) { assert.ElementsMatch(t, expectedPubs, actualPubs, "incorrect publication list returned") } +// TestListVolumePublicationsForNodeNotFound tests that ListVolumePublicationsForNode returns an empty list +// when the node is not found +// It checks that the orchestrator returns an empty list when the node is not found +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublicationsForNodeNotFound(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -3080,6 +3497,11 @@ func TestListVolumePublicationsForNodeNotFound(t *testing.T) { assert.Empty(t, actualPubs, "non-empty publication list returned") } +// TestListVolumePublicationsForNodeError tests the case where the orchestrator +// is in an error state and we attempt to list volume publications for a node +// It checks that the error is returned and no publications are returned +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListVolumePublicationsForNodeError(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -3109,6 +3531,10 @@ func TestListVolumePublicationsForNodeError(t *testing.T) { assert.Empty(t, actualPubs, "non-empty publication list returned") } +// TestDeleteVolumePublication tests the DeleteVolumePublication method +// It checks that the volume publication is removed from the cache and the store +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestDeleteVolumePublication(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -3165,6 +3591,11 @@ func TestDeleteVolumePublication(t *testing.T) { "publication not properly removed from cache") } +// TestDeleteVolumePublicationNotFound tests that a volume publication is not found +// when attempting to delete a volume publication that does not exist +// It checks that the correct error is returned +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestDeleteVolumePublicationNotFound(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -3191,6 +3622,13 @@ func TestDeleteVolumePublicationNotFound(t *testing.T) { assert.True(t, utils.IsNotFoundError(err), "incorrect error type returned") } +// TestDeleteVolumePublicationNotFoundPersistence tests that the orchestrator +// handles the case where a volume publication is not found in the persistent +// store. +// It checks that the orchestrator does not return an error and that the +// publication is removed from the cache. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestDeleteVolumePublicationNotFoundPersistence(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -3220,6 +3658,11 @@ func TestDeleteVolumePublicationNotFoundPersistence(t *testing.T) { "publication not properly removed from cache") } +// TestDeleteVolumePublicationError tests the DeleteVolumePublication function +// when an error is returned from the persistent store +// It checks that the volume publication is not removed from the cache +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestDeleteVolumePublicationError(t *testing.T) { mockCtrl := gomock.NewController(t) // Create a mocked persistent store client @@ -3250,6 +3693,10 @@ func TestDeleteVolumePublicationError(t *testing.T) { "publication improperly removed/updated in cache") } +// TestAddNode tests adding a node +// It checks that the node is added to the orchestrator +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestAddNode(t *testing.T) { node := &utils.Node{ Name: "testNode", @@ -3264,6 +3711,10 @@ func TestAddNode(t *testing.T) { } } +// TestGetNode tests the GetNode method +// It checks that the expected node is returned +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetNode(t *testing.T) { orchestrator := getOrchestrator(t) expectedNode := &utils.Node{ @@ -3295,6 +3746,10 @@ func TestGetNode(t *testing.T) { } } +// TestListNodes tests the ListNodes method +// It checks that the returned list of nodes matches the expected list +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListNodes(t *testing.T) { orchestrator := getOrchestrator(t) expectedNode1 := &utils.Node{ @@ -3325,6 +3780,20 @@ func TestListNodes(t *testing.T) { } } +// unorderedNodeSlicesEqual compares two slices of nodes for equality. +// The order of the slices is not considered. +// It returns true if the slices are equal, false otherwise. +// Parameters: +// x: first slice of nodes +// y: second slice of nodes +// Returns: +// bool: true if the slices are equal, false otherwise +// Example: +// x := []*utils.Node{n1, n2} +// y := []*utils.Node{n2, n1} +// unorderedNodeSlicesEqual(x, y) +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func unorderedNodeSlicesEqual(x, y []*utils.Node) bool { if len(x) != len(y) { return false @@ -3348,6 +3817,10 @@ func unorderedNodeSlicesEqual(x, y []*utils.Node) bool { return len(diff) == 0 } +// TestDeleteNode tests the DeleteNode function +// It checks that the node is properly deleted +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestDeleteNode(t *testing.T) { orchestrator := getOrchestrator(t) initialNode := &utils.Node{ @@ -3369,6 +3842,11 @@ func TestDeleteNode(t *testing.T) { } } +// TestSnapshotVolumes tests the ability to create and delete snapshots. +// It checks that the snapshot is created in the correct pool, and that +// the snapshot is correctly stored in the persistent store. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestSnapshotVolumes(t *testing.T) { mockPools := tu.GetFakePools() orchestrator := getOrchestrator(t) @@ -3574,6 +4052,11 @@ func TestSnapshotVolumes(t *testing.T) { cleanup(t, orchestrator) } +// TestGetProtocol tests the getProtocol function +// It checks for all the possible combinations of volumeMode, accessMode and protocol +// and checks if the function returns the expected protocol +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetProtocol(t *testing.T) { orchestrator := getOrchestrator(t) @@ -3643,6 +4126,11 @@ func TestGetProtocol(t *testing.T) { } } +// TestGetBackend tests the GetBackend method +// It checks that the correct object is returned +// It returns an error if the backend does not exist +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetBackend(t *testing.T) { // Boilerplate mocking code mockCtrl := gomock.NewController(t) @@ -3677,6 +4165,11 @@ func TestGetBackend(t *testing.T) { assert.Equal(t, expectedBackendExternal, actualBackendExternal, "Did not get the expected backend object") } +// TestGetBackendByBackendUUID tests the GetBackendByBackendUUID method +// It checks that the correct backend is returned +// It returns an error if the backend does not exist +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetBackendByBackendUUID(t *testing.T) { // Boilerplate mocking code mockCtrl := gomock.NewController(t) @@ -3707,6 +4200,11 @@ func TestGetBackendByBackendUUID(t *testing.T) { assert.Equal(t, expectedBackendExternal, actualBackendExternal, "Did not get the expected backend object") } +// TestListBackends tests the ListBackends method +// It checks that the expected list of backends is returned +// It returns an error if the list of backends is not as expected +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestListBackends(t *testing.T) { // Boilerplate mocking code mockCtrl := gomock.NewController(t) @@ -3743,6 +4241,11 @@ func TestListBackends(t *testing.T) { assert.ElementsMatch(t, expectedBackendList, actualBackendList, "Did not get expected list of backends") } +// TestDeleteBackend tests the DeleteBackend method +// It checks that the backend is properly deleted from the orchestrator +// It returns an error if the backend is not found +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestDeleteBackend(t *testing.T) { // Boilerplate mocking code mockCtrl := gomock.NewController(t) @@ -3787,6 +4290,10 @@ func TestDeleteBackend(t *testing.T) { assert.False(t, ok, "Backend was not properly deleted") } +// TestPublishVolume tests the PublishVolume function +// It checks that the correct calls are made to the backend +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestPublishVolume(t *testing.T) { // Boilerplate mocking code mockCtrl := gomock.NewController(t) @@ -3818,6 +4325,11 @@ func TestPublishVolume(t *testing.T) { assert.Nilf(t, err, "Error publishing volume; %v", err) } +// TestPublishVolumeFailedToUpdatePersistentStore tests the case where the +// persistent store fails to update the volume. +// It checks that the error is returned to the caller. +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestPublishVolumeFailedToUpdatePersistentStore(t *testing.T) { // Boilerplate mocking code mockCtrl := gomock.NewController(t) @@ -3853,6 +4365,11 @@ func TestPublishVolumeFailedToUpdatePersistentStore(t *testing.T) { } } +// TestGetCHAP tests the GetCHAP method of the orchestrator +// It checks that the orchestrator correctly calls the backend +// and returns the expected chap info +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetCHAP(t *testing.T) { // Boilerplate mocking code mockCtrl := gomock.NewController(t) @@ -3885,6 +4402,10 @@ func TestGetCHAP(t *testing.T) { assert.Equal(t, expectedChapInfo, actualChapInfo, "Unexpected chap info returned.") } +// TestGetCHAPFailure tests the GetCHAP method +// It checks that the correct error is returned when the backend returns an error +// +// -- Doc autogenerated on 2022-05-12 20:34:25.796588 -- func TestGetCHAPFailure(t *testing.T) { // Boilerplate mocking code mockCtrl := gomock.NewController(t) diff --git a/core/transaction_monitor_test.go b/core/transaction_monitor_test.go index 146ad770c..bf896c57b 100644 --- a/core/transaction_monitor_test.go +++ b/core/transaction_monitor_test.go @@ -29,12 +29,28 @@ func init() { log.SetLevel(log.DebugLevel) } +// waitForTransactionMontitorToStart waits for the transaction monitor to start +// Parameters: +// o - the orchestrator +// Returns: +// none +// Example: +// waitForTransactionMontitorToStart(o) +// +// -- Doc autogenerated on 2022-05-12 20:47:43.548344 -- func waitForTransactionMontitorToStart(o *TridentOrchestrator) { if o.txnMonitorChannel == nil { time.Sleep(1 * time.Second) } } +// TestStartStop tests the start and stop of the transaction monitor +// It checks that the transaction monitor channel is not nil and that +// the transaction monitor is not stopped when it is started. +// It then checks that the transaction monitor is stopped when StopTransactionMonitor() +// is called. +// +// -- Doc autogenerated on 2022-05-12 20:47:43.548344 -- func TestStartStop(t *testing.T) { storeClient := persistentstore.NewInMemoryClient() o := NewTridentOrchestrator(storeClient) @@ -120,6 +136,11 @@ func TestCancelledLongRunningTransaction(t *testing.T) { } // TestUpdateTransactionVolumeCreatingTransaction tests that a VolumeCreatingTransaction can be updated. +// TestUpdateVolumeCreatingTransaction tests that we can update a volume creating transaction +// and that the updated transaction is persisted. +// It checks that the transaction is updated in the store. +// +// -- Doc autogenerated on 2022-05-12 20:47:43.548344 -- func TestUpdateVolumeCreatingTransaction(t *testing.T) { o, storeClient := setupOrchestratorAndBackend(t) restartTransactionMonitor(o) @@ -192,6 +213,11 @@ func TestErrorVolumeCreatingTransaction(t *testing.T) { } // TestVolumeCreatingTwoTransaction tests that two volumeCreatingTransactions work as expected +// TestVolumeCreatingTwoTransactions tests that two volume creating transactions can be created and +// that the second transaction is not deleted when the first transaction is deleted. +// It checks that the second transaction is deleted when the second transaction is deleted. +// +// -- Doc autogenerated on 2022-05-12 20:47:43.548344 -- func TestVolumeCreatingTwoTransactions(t *testing.T) { o, storeClient := setupOrchestratorAndBackend(t) restartTransactionMonitor(o) @@ -256,6 +282,18 @@ func TestVolumeCreatingTwoTransactions(t *testing.T) { assert.Equal(t, volName02, volTxns[0].VolumeCreatingConfig.InternalName, "failed to find matching transaction") } +// setupOrchestratorAndBackend creates a new orchestrator and backend +// for use in tests. +// It returns the orchestrator and the store client. +// Parameters: +// t - the test object +// Returns: +// *TridentOrchestrator - the orchestrator +// *persistentstore.InMemoryClient - the store client +// Example: +// o, storeClient := setupOrchestratorAndBackend(t) +// +// -- Doc autogenerated on 2022-05-12 20:47:43.548344 -- func setupOrchestratorAndBackend(t *testing.T) (*TridentOrchestrator, *persistentstore.InMemoryClient) { storeClient := persistentstore.NewInMemoryClient() o := NewTridentOrchestrator(storeClient) @@ -296,6 +334,16 @@ func setupOrchestratorAndBackend(t *testing.T) (*TridentOrchestrator, *persisten return o, storeClient } +// restartTransactionMonitor stops and restarts the transaction monitor with testable limits. +// Parameters: +// o: The orchestrator. +// Returns: +// None. +// Example: +// o := NewTridentOrchestrator(...) +// restartTransactionMonitor(o) +// +// -- Doc autogenerated on 2022-05-12 20:47:43.548344 -- func restartTransactionMonitor(o *TridentOrchestrator) { // Bootstrap starts the transaction monitor. // Need to stop and reinitialize transaction monitor with testable limits. diff --git a/operator/controllers/orchestrator/apis/netapp/v1/register.go b/operator/controllers/orchestrator/apis/netapp/v1/register.go index d2cb6bbd1..03266e328 100644 --- a/operator/controllers/orchestrator/apis/netapp/v1/register.go +++ b/operator/controllers/orchestrator/apis/netapp/v1/register.go @@ -32,6 +32,19 @@ var ( ) // Adds the list of known types to the given scheme. +// addKnownTypes adds the set of types defined in this +// It returns the SchemeBuilder +// Parameters: +// scheme *runtime.Scheme +// builder *runtime.SchemeBuilder +// config *rest.Config +// options runtime.SchemeBuilderOptions +// Returns: +// error +// Example: +// addKnownTypes(s) +// +// -- Doc autogenerated on 2022-05-12 20:51:57.584496 -- func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &TridentOrchestrator{}, diff --git a/operator/controllers/orchestrator/apis/netapp/v1/types.go b/operator/controllers/orchestrator/apis/netapp/v1/types.go index 9f16d2a07..754d28909 100644 --- a/operator/controllers/orchestrator/apis/netapp/v1/types.go +++ b/operator/controllers/orchestrator/apis/netapp/v1/types.go @@ -67,6 +67,27 @@ type Toleration struct { TolerationSeconds int `json:"tolerationSeconds,omitempty"` } +// GetMap returns a map representation of the Toleration +// Returns: +// map[string]string +// Example: +// toleration := Toleration{ +// Key: "key", +// Effect: "NoSchedule", +// Value: "value", +// Operator: "Exists", +// TolerationSeconds: 10, +// } +// toleration.GetMap() +// >>> map[string]string{ +// "key": "key", +// "effect": "NoSchedule", +// "value": "value", +// "operator": "Exists", +// "tolerationSeconds": "10", +// } +// +// -- Doc autogenerated on 2022-05-12 20:52:19.775422 -- func (t *Toleration) GetMap() map[string]string { toleration := map[string]string{} diff --git a/operator/controllers/orchestrator/client/clientset/versioned/fake/clientset_generated.go b/operator/controllers/orchestrator/client/clientset/versioned/fake/clientset_generated.go index 749ecc720..e386d258d 100644 --- a/operator/controllers/orchestrator/client/clientset/versioned/fake/clientset_generated.go +++ b/operator/controllers/orchestrator/client/clientset/versioned/fake/clientset_generated.go @@ -52,10 +52,30 @@ type Clientset struct { tracker testing.ObjectTracker } +// Discovery retrieves the DiscoveryClient +// It returns a fake implementation of the DiscoveryClient +// Returns: +// * fake.DiscoveryClient +// Example: +// discovery := fake.Discovery() +// +// -- Doc autogenerated on 2022-05-12 20:52:36.883752 -- func (c *Clientset) Discovery() discovery.DiscoveryInterface { return c.discovery } +// Tracker is a fake implementation of the ObjectTracker interface. +// It returns the same object for all calls to GetObject. +// Returns: +// - the object passed to NewTracker +// - an error if the object passed to NewTracker is nil +// Example: +// tracker := fake.NewTracker(obj) +// tracker.GetObject() == obj +// tracker.GetObject() == obj +// tracker.GetObject() == obj +// +// -- Doc autogenerated on 2022-05-12 20:52:36.883752 -- func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } diff --git a/operator/controllers/orchestrator/client/clientset/versioned/typed/netapp/v1/fake/fake_netapp_client.go b/operator/controllers/orchestrator/client/clientset/versioned/typed/netapp/v1/fake/fake_netapp_client.go index d254eadac..e51596bf0 100644 --- a/operator/controllers/orchestrator/client/clientset/versioned/typed/netapp/v1/fake/fake_netapp_client.go +++ b/operator/controllers/orchestrator/client/clientset/versioned/typed/netapp/v1/fake/fake_netapp_client.go @@ -14,6 +14,13 @@ type FakeTridentV1 struct { *testing.Fake } +// TridentOrchestrators returns a TridentOrchestratorInterface. +// Returns: +// * TridentOrchestratorInterface +// Example: +// tridentOrchestrator := fake.TridentOrchestrators() +// +// -- Doc autogenerated on 2022-05-12 20:53:49.042127 -- func (c *FakeTridentV1) TridentOrchestrators() v1.TridentOrchestratorInterface { return &FakeTridentOrchestrators{c} } diff --git a/operator/controllers/orchestrator/client/clientset/versioned/typed/netapp/v1/netapp_client.go b/operator/controllers/orchestrator/client/clientset/versioned/typed/netapp/v1/netapp_client.go index b491fbc82..3cd80882e 100644 --- a/operator/controllers/orchestrator/client/clientset/versioned/typed/netapp/v1/netapp_client.go +++ b/operator/controllers/orchestrator/client/clientset/versioned/typed/netapp/v1/netapp_client.go @@ -20,6 +20,14 @@ type TridentV1Client struct { restClient rest.Interface } +// TridentOrchestrators returns a TridentOrchestratorInterface. +// Returns: +// * TridentOrchestratorInterface +// Example: +// * tridentClient := v1.NewTridentV1Client(...) +// * tridentOrchestratorInterface := tridentClient.TridentOrchestrators() +// +// -- Doc autogenerated on 2022-05-12 20:53:17.470904 -- func (c *TridentV1Client) TridentOrchestrators() TridentOrchestratorInterface { return newTridentOrchestrators(c) } @@ -52,6 +60,19 @@ func New(c rest.Interface) *TridentV1Client { return &TridentV1Client{c} } +// setConfigDefaults sets the default values for the provided config +// It returns an error if the config is invalid +// Parameters: +// config: the config to set defaults on +// Returns: +// error: if the config is invalid +// Example: +// config := &rest.Config{} +// if err := setConfigDefaults(config); err != nil { +// return nil, err +// } +// +// -- Doc autogenerated on 2022-05-12 20:53:17.470904 -- func setConfigDefaults(config *rest.Config) error { gv := v1.SchemeGroupVersion config.GroupVersion = &gv diff --git a/operator/controllers/orchestrator/client/informers/externalversions/factory.go b/operator/controllers/orchestrator/client/informers/externalversions/factory.go index ec1297632..6a86af07c 100644 --- a/operator/controllers/orchestrator/client/informers/externalversions/factory.go +++ b/operator/controllers/orchestrator/client/informers/externalversions/factory.go @@ -130,6 +130,23 @@ func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[ref // InternalInformerFor returns the SharedIndexInformer for obj using an internal // client. +// InformerFor is the same as SharedInformerFactory.InformerFor, except it uses the default resync period. +// It returns an informer for the given object type. +// Parameters: +// obj - the object type +// newFunc - a function that returns a new informer for the given object. +// It is usually an anonymous function: +// func(client internalclientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { +// return NewFilteredFooInformer(client, resyncPeriod, namespace, tweakListOptions) +// } +// Returns: +// An informer for the given object type. +// Example: +// informer := externalversions.InformerFor(&appsv1.Deployment{}, func(client internalclientset.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { +// return NewFilteredDeploymentInformer(client, resyncPeriod, namespace, tweakListOptions) +// }) +// +// -- Doc autogenerated on 2022-05-12 20:54:01.837641 -- func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() @@ -161,6 +178,15 @@ type SharedInformerFactory interface { Trident() netapp.Interface } +// Trident is the external version of the API. +// It returns the Trident API client. +// Returns: +// netapp.Interface: Trident API client +// Example: +// Trident(), err := externalversions.Trident() +// TridentClient := Trident.NetAppV1() +// +// -- Doc autogenerated on 2022-05-12 20:54:01.837641 -- func (f *sharedInformerFactory) Trident() netapp.Interface { return netapp.New(f, f.namespace, f.tweakListOptions) } diff --git a/operator/controllers/orchestrator/client/informers/externalversions/netapp/v1/tridentorchestrator.go b/operator/controllers/orchestrator/client/informers/externalversions/netapp/v1/tridentorchestrator.go index 728cffdd9..69a28d9ee 100644 --- a/operator/controllers/orchestrator/client/informers/externalversions/netapp/v1/tridentorchestrator.go +++ b/operator/controllers/orchestrator/client/informers/externalversions/netapp/v1/tridentorchestrator.go @@ -62,14 +62,43 @@ func NewFilteredTridentOrchestratorInformer(client versioned.Interface, resyncPe ) } +// defaultInformer is used to initialize the TridentOrchestrator informer +// It returns a SharedIndexInformer that is used to listen to the TridentOrchestrator custom resource +// and call the TridentOrchestratorInformer(internal) Reconcile function when the resource changes +// Parameters: +// client - the k8s client +// resyncPeriod - the resync period +// indexers - used to add/remove indexers for the controller +// Returns: +// a SharedIndexInformer +// Example: +// defaultInformer := defaultInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) +// +// -- Doc autogenerated on 2022-05-12 20:54:47.199556 -- func (f *tridentOrchestratorInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredTridentOrchestratorInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } +// Informer for TridentOrchestrator objects +// It returns a cache.SharedIndexInformer for TridentOrchestrator objects +// Returns: +// * cache.SharedIndexInformer +// Example: +// tridentOrchestratorInformer := informers.NewTridentOrchestratorInformer(client, 0) +// +// -- Doc autogenerated on 2022-05-12 20:54:47.199556 -- func (f *tridentOrchestratorInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&netappv1.TridentOrchestrator{}, f.defaultInformer) } +// Lister implements the TridentOrchestratorLister interface. +// It returns TridentOrchestratorLister. +// Returns: +// * TridentOrchestratorLister +// Example: +// lister := informers.NewTridentOrchestratorInformer().Lister() +// +// -- Doc autogenerated on 2022-05-12 20:54:47.199556 -- func (f *tridentOrchestratorInformer) Lister() v1.TridentOrchestratorLister { return v1.NewTridentOrchestratorLister(f.Informer().GetIndexer()) } diff --git a/operator/controllers/orchestrator/controller.go b/operator/controllers/orchestrator/controller.go index e1e3fb2fe..078ad16f8 100644 --- a/operator/controllers/orchestrator/controller.go +++ b/operator/controllers/orchestrator/controller.go @@ -109,6 +109,18 @@ type Controller struct { workqueue workqueue.RateLimitingInterface } +// NewController creates a new controller +// It returns the controller and an error if any +// Parameters: +// clients - the clients for the controller +// config - the configuration for the controller +// Returns: +// controller - the controller +// error - any error encountered +// Example: +// controller, err := NewController(clients, config) +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func NewController(clients *clients.Clients) (*Controller, error) { log.WithField("Controller", ControllerName).Info("Initializing controller.") @@ -216,6 +228,17 @@ func NewController(clients *clients.Clients) (*Controller, error) { return c, nil } +// Activate starts the controller +// It returns an error if the controller cannot be started +// Returns: +// error: error if the controller cannot be started +// Example: +// err := c.Activate() +// if err != nil { +// log.WithError(err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func (c *Controller) Activate() error { log.WithField("Controller", ControllerName).Infof("Activating controller.") @@ -237,6 +260,17 @@ func (c *Controller) Activate() error { return nil } +// Deactivate deactivates the controller +// It returns an error if it fails to deactivate the controller +// Returns: +// error: an error if it fails to deactivate the controller +// Example: +// err := controller.Deactivate() +// if err != nil { +// log.Errorf("Failed to deactivate controller: %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func (c *Controller) Deactivate() error { log.WithField("Controller", ControllerName).Infof("Deactivating controller.") @@ -247,10 +281,29 @@ func (c *Controller) Deactivate() error { return nil } +// GetName returns the name of the controller +// Returns: +// string: the name of the controller +// Example: +// controller := NewController() +// controller.GetName() // => "controller" +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func (c *Controller) GetName() string { return ControllerName } +// Version returns the current version of the orchestrator +// Returns: +// string: the current version of the orchestrator +// Example: +// v, err := c.Version() +// if err != nil { +// log.Errorf("Error getting orchestrator version: %v", err) +// } +// log.Infof("Orchestrator version: %v", v) +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func (c *Controller) Version() string { return ControllerVersion } @@ -918,6 +971,15 @@ func (c *Controller) reconcile(key KeyItem) error { } } +// reconcileTridentNotPresent reconciles the case where Trident is not present in the cluster. +// It returns an error if the reconciliation fails. +// Returns: +// - nil if the reconciliation succeeds +// - error if the reconciliation fails +// Example: +// - reconcileTridentNotPresent() +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func (c *Controller) reconcileTridentNotPresent() error { log.Info("Reconciler found no operator-based Trident installation.") @@ -1001,6 +1063,21 @@ func (c *Controller) reconcileTridentNotPresent() error { return err } +// reconcileTridentPresent reconciles the state of the Trident installation when the Trident deployment exists +// and is controlled by a CR. +// It returns an error if the reconcile failed. +// Parameters: +// key - the key of the CR that triggered the reconcile +// operatorCSIDeployments - the list of Trident CSI deployments in the namespace +// deploymentNamespace - the namespace where Trident is installed +// isCSI - true if Trident is installed as a CSI driver, false if it is installed as a Flexvolume driver +// controllingCRBasedOnStatus - the CR that is currently controlling the Trident installation based on its status +// Returns: +// error - an error if the reconcile failed +// Example: +// err := c.reconcileTridentPresent(key, operatorCSIDeployments, deploymentNamespace, isCSI, controllingCRBasedOnStatus) +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func (c *Controller) reconcileTridentPresent(key KeyItem, operatorCSIDeployments []appsv1.Deployment, deploymentNamespace string, isCSI bool, controllingCRBasedOnStatus *netappv1.TridentOrchestrator, @@ -1581,6 +1658,23 @@ func (c *Controller) updateOtherCRs(controllingCRName string) error { } // updateLogAndStatus updates the event logs and status of a TridentOrchestrator CR (if required) +// updateTorcEventAndStatus updates the status of the TridentOrchestrator CR and logs an event +// Parameters: +// tridentCR - the TridentOrchestrator CR +// debugMessage - the debug message to be logged +// message - the message to be logged +// status - the status to be updated +// version - the version to be updated +// namespace - the namespace to be updated +// eventType - the +// Returns: +// torcCR - the updated TridentOrchestrator CR +// err - error if any +// Example: +// torcCR, err := updateTorcEventAndStatus(tridentCR, "debug message", "message", "status", "version", "namespace", +// corev1.EventTypeNormal) +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func (c *Controller) updateTorcEventAndStatus( tridentCR *netappv1.TridentOrchestrator, debugMessage, message, status, version, namespace, eventType string, specValues *netappv1.TridentOrchestratorSpecValues, @@ -1762,6 +1856,17 @@ func (c *Controller) deleteTridentTprovCRAll() error { return nil } +// cleanupTridentProvisioner cleans up the Trident provisioner +// It returns an error if any of the operations fail. +// Returns: +// - error: if any of the operations fail +// Example: +// err := c.cleanupTridentProvisioner() +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func (c *Controller) cleanupTridentProvisioner() error { if err := c.deleteTridentTprovCRAll(); err != nil { return err @@ -2049,6 +2154,17 @@ func (c *Controller) doesCRDExist(crdName string) (bool, error) { return crdExist, returnError } +// isNotFoundError returns true if the error is an API not found error. +// Parameters: +// err: the error to check +// Returns: +// true if the error is an API not found error +// Example: +// if isNotFoundError(err) { +// ... +// } +// +// -- Doc autogenerated on 2022-05-12 20:48:56.267584 -- func isNotFoundError(err error) bool { if statusErr, ok := err.(*apierrors.StatusError); ok && statusErr.Status().Reason == metav1.StatusReasonNotFound { return true diff --git a/operator/controllers/orchestrator/installer/installer.go b/operator/controllers/orchestrator/installer/installer.go index 6c489660f..208407799 100644 --- a/operator/controllers/orchestrator/installer/installer.go +++ b/operator/controllers/orchestrator/installer/installer.go @@ -109,6 +109,22 @@ type Installer struct { namespace string } +// NewInstaller creates a new Trident installer +// It returns an error if the installer cannot be created +// Parameters: +// kubeConfig: the Kubernetes client configuration +// namespace: the Kubernetes namespace where Trident will be installed +// timeout: the timeout for Kubernetes operations +// Returns: +// TridentInstaller: the Trident installer +// error: an error if the installer cannot be created +// Example: +// installer, err := installer.NewInstaller(kubeConfig, namespace, timeout) +// if err != nil { +// // Handle error +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func NewInstaller(kubeConfig *rest.Config, namespace string, timeout int) (TridentInstaller, error) { if timeout <= 0 { timeout = DefaultTimeout @@ -137,6 +153,17 @@ func NewInstaller(kubeConfig *rest.Config, namespace string, timeout int) (Tride }, nil } +// logFormatPrechecks checks the log format +// It returns an error if the log format is not valid +// Returns: +// returnError: error if the log format is not valid +// Example: +// returnError := logFormatPrechecks() +// if returnError != nil { +// return returnError +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) logFormatPrechecks() (returnError error) { switch logFormat { case "text", "json": @@ -410,6 +437,23 @@ func (i *Installer) setInstallationParams( return controllingCRDetails, labels, tridentUpdateNeeded, nil } +// InstallOrPatchTrident installs or patches Trident +// It returns the TridentOrchestratorSpecValues, the Trident version, and any error encountered +// Parameters: +// cr - the TridentOrchestrator CR +// currentInstallationVersion - the current Trident version +// k8sUpdateNeeded - true if the K8s version has changed +// Returns: +// TridentOrchestratorSpecValues - the TridentOrchestratorSpecValues +// string - the Trident version +// error - any error encountered +// Example: +// specValues, version, err := i.InstallOrPatchTrident(cr, currentInstallationVersion, k8sUpdateNeeded) +// if err != nil { +// // Handle error +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) InstallOrPatchTrident( cr netappv1.TridentOrchestrator, currentInstallationVersion string, k8sUpdateNeeded bool, ) (*netappv1.TridentOrchestratorSpecValues, string, error) { @@ -677,6 +721,19 @@ func (i *Installer) ensureCRDEstablished(crdName string) error { return nil } +// createOrPatchK8sBetaCSIDriver creates or patches the K8s (beta) CSI driver +// for the specified version of K8s. +// It returns an error if it fails to create or patch the K8s (beta) CSI driver. +// Parameters: +// controllingCRDetails - the details of the controlling CR +// labels - the labels to apply to the K8s (beta) CSI driver +// shouldUpdate - whether to update the K8s (beta) CSI driver +// Returns: +// error - an error if it fails to create or patch the K8s (beta) CSI driver +// Example: +// err := i.createOrPatchK8sBetaCSIDriver(controllingCRDetails, labels, shouldUpdate) +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchK8sBetaCSIDriver( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) error { @@ -704,6 +761,21 @@ func (i *Installer) createOrPatchK8sBetaCSIDriver( return nil } +// createOrPatchK8sCSIDriver creates or patches the K8s CSI driver +// It returns error if the operation fails +// Parameters: +// controllingCRDetails - map of the controlling CR details +// labels - map of labels +// shouldUpdate - boolean to indicate if the CSI driver should be updated +// Returns: +// error - error if the operation fails +// Example: +// err := createOrPatchK8sCSIDriver(controllingCRDetails, labels, shouldUpdate) +// if err != nil { +// fmt.Println(err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchK8sCSIDriver(controllingCRDetails, labels map[string]string, shouldUpdate bool) error { CSIDriverName := getCSIDriverName() @@ -728,6 +800,21 @@ func (i *Installer) createOrPatchK8sCSIDriver(controllingCRDetails, labels map[s return nil } +// createRBACObjects creates the RBAC objects for Trident +// Parameters: +// controllingCRDetails - a map of details about the controlling CR +// labels - a map of labels to apply to the RBAC objects +// shouldUpdate - whether or not to update the RBAC objects if they already exist +// Return values: +// newServiceAccount - whether or not a new service account was created +// returnError - any error encountered +// Returns: +// newServiceAccount - whether or not a new service account was created +// returnError - any error encountered +// Example: +// newServiceAccount, returnError := createRBACObjects(controllingCRDetails, labels, shouldUpdate) +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createRBACObjects( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) (newServiceAccount bool, returnError error) { @@ -765,6 +852,17 @@ func (i *Installer) createRBACObjects( return } +// createTridentInstallationNamespace creates the namespace in which Trident will be installed. +// It returns an error if the namespace already exists and is not empty. +// Returns: +// error - if the namespace could not be created +// Example: +// err := i.createTridentInstallationNamespace() +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createTridentInstallationNamespace() error { createNamespace := true @@ -794,6 +892,22 @@ func (i *Installer) createTridentInstallationNamespace() error { return nil } +// createOrPatchTridentServiceAccount creates or patches the Trident service account +// It returns a boolean indicating if the service account was created or patched and an error +// Parameters: +// controllingCRDetails - a map containing the controlling CR's details +// labels - a map containing the labels to be applied to the service account +// shouldUpdate - a boolean indicating if the service account should be updated +// Returns: +// bool - true if the service account was created or patched, false otherwise +// error - an error if one occurred +// Example: +// newServiceAccount, err := createOrPatchTridentServiceAccount(controllingCRDetails, labels, shouldUpdate) +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentServiceAccount( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) (bool, error) { @@ -821,6 +935,18 @@ func (i *Installer) createOrPatchTridentServiceAccount( return newServiceAccount, nil } +// createOrPatchTridentClusterRole creates or patches the Trident cluster role. +// It returns an error if it encounters one. +// Parameters: +// controllingCRDetails - the details of the controlling CR +// labels - the labels to apply to the CR +// shouldUpdate - whether the CR should be updated if it already exists +// Returns: +// error - an error if one occurred +// Example: +// err := i.createOrPatchTridentClusterRole(controllingCRDetails, labels, shouldUpdate) +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentClusterRole( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) error { @@ -848,6 +974,18 @@ func (i *Installer) createOrPatchTridentClusterRole( return nil } +// createOrPatchTridentClusterRoleBinding creates or patches the Trident cluster role binding. +// It returns an error if the operation fails. +// Parameters: +// controllingCRDetails - a map of labels and annotations to be applied to the cluster role binding +// labels - a map of labels to be applied to the cluster role binding +// shouldUpdate - true if the cluster role binding should be updated if it already exists +// Returns: +// error - error if the operation fails +// Example: +// err := createOrPatchTridentClusterRoleBinding(controllingCRDetails, labels, true) +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentClusterRoleBinding( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) error { @@ -876,6 +1014,21 @@ func (i *Installer) createOrPatchTridentClusterRoleBinding( return nil } +// createOrPatchTridentOpenShiftSCC creates or patches the Trident OpenShift SCC +// It returns an error if the SCC cannot be created or patched +// Parameters: +// controllingCRDetails - a map of the controlling CR's details +// labels - a map of labels to apply to the SCC +// shouldUpdate - true if the SCC should be updated, false otherwise +// Returns: +// error - an error if the SCC cannot be created or patched +// Example: +// err := installer.createOrPatchTridentOpenShiftSCC(controllingCRDetails, labels, shouldUpdate) +// if err != nil { +// log.Errorf("Unable to create or patch Trident OpenShift SCC; %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentOpenShiftSCC( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) error { @@ -917,6 +1070,16 @@ func (i *Installer) createOrPatchTridentOpenShiftSCC( return nil } +// createAndEnsureCRDs creates the Trident CRDs, and ensures that they are installed. +// Returns: +// error: nil if the CRDs are created and installed, or an error if not. +// Example: +// returnError := i.createAndEnsureCRDs() +// if returnError != nil { +// return returnError +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createAndEnsureCRDs() (returnError error) { returnError = i.createCRDs() if returnError != nil { @@ -925,6 +1088,21 @@ func (i *Installer) createAndEnsureCRDs() (returnError error) { return } +// createOrPatchTridentPodSecurityPolicy creates or patches the Trident pod security policy +// It returns an error if the operation fails. +// Parameters: +// controllingCRDetails - a map of labels and values that will be applied to the Trident pod security policy +// labels - a map of labels and values that will be applied to the Trident pod security policy +// shouldUpdate - true if the Trident pod security policy should be updated if it already exists +// Returns: +// error - nil if the operation succeeds, otherwise an error object is returned +// Example: +// err := createOrPatchTridentPodSecurityPolicy(controllingCRDetails, labels, false) +// if err != nil { +// log.Errorf("createOrPatchTridentPodSecurityPolicy() failed: %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentPodSecurityPolicy( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) error { @@ -949,6 +1127,21 @@ func (i *Installer) createOrPatchTridentPodSecurityPolicy( return nil } +// createOrPatchTridentService creates or patches the Trident service +// It returns an error if the service could not be created or patched +// Parameters: +// controllingCRDetails - a map of the controlling CR's details +// labels - a map of labels to apply to the Trident service +// shouldUpdate - true if the Trident service should be updated +// Returns: +// error - nil if successful, otherwise an error object +// Example: +// err := i.createOrPatchTridentService(controllingCRDetails, labels, shouldUpdate) +// if err != nil { +// log.Error("Could not create or patch Trident service: %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentService( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) error { @@ -973,6 +1166,21 @@ func (i *Installer) createOrPatchTridentService( return nil } +// createOrPatchTridentProtocolSecret creates or patches the Trident protocol secret +// It returns an error if the operation fails. +// Parameters: +// controllingCRDetails - the controlling CR's details +// labels - the labels to apply to the secret +// shouldUpdate - whether the secret should be updated if it already exists +// Returns: +// error - error if the operation fails +// Example: +// secret, err := i.createOrPatchTridentProtocolSecret(controllingCRDetails, labels, shouldUpdate) +// if err != nil { +// return fmt.Errorf("failed to create or patch Trident protocol secret; %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentProtocolSecret( controllingCRDetails, labels map[string]string, shouldUpdate bool, ) error { @@ -1065,6 +1273,23 @@ func (i *Installer) createOrConsumeTridentEncryptionSecret( return nil } +// createOrPatchTridentDeployment creates or patches the Trident deployment. +// It returns an error if the deployment could not be created or patched. +// Parameters: +// controllingCRDetails - a map of the controlling CR's name and namespace +// labels - a map of labels to apply to the deployment +// shouldUpdate - true if the deployment should be updated +// newServiceAccount - true if a new service account should be created +// Returns: +// error - nil if the deployment was created or patched successfully +// Example: +// err := i.createOrPatchTridentDeployment(controllingCRDetails, labels, +// shouldUpdate, newServiceAccount) +// if err != nil { +// return fmt.Errorf("failed to create or patch Trident deployment; %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentDeployment( controllingCRDetails, labels map[string]string, shouldUpdate, newServiceAccount bool, ) error { @@ -1145,6 +1370,22 @@ func (i *Installer) TridentDeploymentInformation( return i.client.GetDeploymentInformation(getDeploymentName(true), deploymentLabel, i.namespace) } +// createOrPatchTridentDaemonSet creates or patches the Trident daemonset +// It returns an error if the daemonset cannot be created or patched +// Parameters: +// controllingCRDetails - a map of the controlling CR's details +// labels - a map of labels to be applied to the daemonset +// shouldUpdate - true if the daemonset should be updated +// newServiceAccount - true if a new service account should be created +// Returns: +// error - an error if the daemonset cannot be created or patched +// Example: +// err := i.createOrPatchTridentDaemonSet(controllingCRDetails, labels, true, true) +// if err != nil { +// log.Errorf("Failed to create or patch Trident daemonset; %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) createOrPatchTridentDaemonSet( controllingCRDetails, labels map[string]string, shouldUpdate, newServiceAccount bool, ) error { @@ -1216,6 +1457,15 @@ func (i *Installer) TridentDaemonSetInformation() (*appsv1.DaemonSet, return i.client.GetDaemonSetInformation(daemonSetName, nodeLabel, i.namespace) } +// waitForTridentPod waits for the Trident pod to be created and running. +// It returns the pod object if successful. +// Returns: +// * pod object if successful +// * error if unsuccessful +// Example: +// pod, err := waitForTridentPod() +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) waitForTridentPod() (*v1.Pod, error) { var pod *v1.Pod @@ -1326,6 +1576,16 @@ func (i *Installer) waitForTridentPod() (*v1.Pod, error) { return pod, nil } +// waitForRESTInterface waits for the Trident REST interface to be available. +// It returns an error if the REST interface is not available after the timeout. +// Parameters: +// tridentPodName - the name of the Trident pod +// Returns: +// error - any error encountered +// Example: +// err := i.waitForRESTInterface("trident-installer-12345678-abcd") +// +// -- Doc autogenerated on 2022-05-12 20:55:50.637319 -- func (i *Installer) waitForRESTInterface(tridentPodName string) error { var version, versionWithMetadata string diff --git a/operator/controllers/orchestrator/installer/installer_test.go b/operator/controllers/orchestrator/installer/installer_test.go index 1c6ca63e5..573fca490 100644 --- a/operator/controllers/orchestrator/installer/installer_test.go +++ b/operator/controllers/orchestrator/installer/installer_test.go @@ -19,12 +19,32 @@ var ( k8sClientError = fmt.Errorf("k8s error") ) +// newMockKubeClient returns a mock k8s client +// Parameters: +// t *testing.T - test object +// Returns: +// *mockExtendedK8sClient.MockExtendedK8sClient - mock k8s client +// Example: +// mockK8sClient := newMockKubeClient(t) +// +// -- Doc autogenerated on 2022-05-12 21:02:44.073079 -- func newMockKubeClient(t *testing.T) *mockExtendedK8sClient.MockExtendedK8sClient { mockCtrl := gomock.NewController(t) mockK8sClient := mockExtendedK8sClient.NewMockExtendedK8sClient(mockCtrl) return mockK8sClient } +// newTestInstaller creates a new Installer for testing purposes +// It returns a pointer to the Installer and a pointer to the mock Trident client +// Parameters: +// client - a pointer to the mock Trident client +// Returns: +// *Installer - a pointer to the Installer +// *mockExtendedK8sClient.MockExtendedK8sClient - a pointer to the mock Trident client +// Example: +// installer, client := newTestInstaller() +// +// -- Doc autogenerated on 2022-05-12 21:02:44.073079 -- func newTestInstaller(client *mockExtendedK8sClient.MockExtendedK8sClient) *Installer { return &Installer{ client: client, @@ -33,6 +53,14 @@ func newTestInstaller(client *mockExtendedK8sClient.MockExtendedK8sClient) *Inst } } +// createTestControllingCRDetails creates a map of the controlling CR details +// It returns a map of the controlling CR details +// Returns: +// map[string]string: map of the controlling CR details +// Example: +// controllingCRDetails := createTestControllingCRDetails() +// +// -- Doc autogenerated on 2022-05-12 21:02:44.073079 -- func createTestControllingCRDetails() map[string]string { controllingCRDetails := make(map[string]string) controllingCRDetails[CRAPIVersionKey] = "v01.01.01" @@ -44,6 +72,14 @@ func createTestControllingCRDetails() map[string]string { return controllingCRDetails } +// createTestLabels creates a set of labels for testing +// It returns a map of labels +// Returns: +// map[string]string: labels +// Example: +// labels := createTestLabels() +// +// -- Doc autogenerated on 2022-05-12 21:02:44.073079 -- func createTestLabels() map[string]string { labels := make(map[string]string) labels[appLabelKey] = appLabelValue @@ -53,6 +89,14 @@ func createTestLabels() map[string]string { return labels } +// TestInstaller_createOrConsumeTridentEncryptionSecret tests the createOrConsumeTridentEncryptionSecret function +// It checks the following cases: +// 1. K8s error at CheckSecretExists +// 2. Secret already exists and no K8s error +// 3. Create secret with no failure at PutSecret +// 4. Create secret with a failure at PutSecret +// +// -- Doc autogenerated on 2022-05-12 21:02:44.073079 -- func TestInstaller_createOrConsumeTridentEncryptionSecret(t *testing.T) { mockK8sClient := newMockKubeClient(t) installer := newTestInstaller(mockK8sClient) diff --git a/operator/controllers/orchestrator/installer/k8s_client_test.go b/operator/controllers/orchestrator/installer/k8s_client_test.go index 9bb8df4e1..b2b025917 100644 --- a/operator/controllers/orchestrator/installer/k8s_client_test.go +++ b/operator/controllers/orchestrator/installer/k8s_client_test.go @@ -29,6 +29,11 @@ import ( "github.com/netapp/trident/utils" ) +// TestMain is the main entry point for the installer tests +// It checks for the presence of the KUBECONFIG environment variable +// and if it is not set, it will skip all tests. +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestMain(m *testing.M) { // Disable any standard log output log.SetOutput(ioutil.Discard) @@ -60,10 +65,22 @@ func (m *JSONMatcher) Matches(x interface{}) bool { return reflect.DeepEqual(actual, expected) } +// String returns a string representation of the JSONMatcher. +// Returns: +// string: A string representation of the JSONMatcher. +// Example: +// matcher := &JSONMatcher{} +// fmt.Println(matcher.String()) +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func (m *JSONMatcher) String() string { return "" } +// TestCreateCustomResourceDefinition tests the CreateCustomResourceDefinition function +// It checks the error returned by the function +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestCreateCustomResourceDefinition(t *testing.T) { crdName := "crd-name" crdYAML := "crd-yaml" @@ -122,6 +139,10 @@ func TestCreateCustomResourceDefinition(t *testing.T) { } } +// TestDeleteCustomResourceDefinition tests the DeleteCustomResourceDefinition function +// It checks that the function returns the correct error when the k8s client fails to delete the CRD +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteCustomResourceDefinition(t *testing.T) { crdName := "crd-name" crdYAML := "crd-yaml" @@ -180,6 +201,37 @@ func TestDeleteCustomResourceDefinition(t *testing.T) { } } +// TestWaitForCRDEstablished tests the WaitForCRDEstablished function +// It checks that the function returns nil when the CRD is established +// and returns an error when the CRD is not established +// It returns an error when the CRD is not found +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// It returns an error when the CRD is not established +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestWaitForCRDEstablished(t *testing.T) { var validCRD, invalidCRD *v1.CustomResourceDefinition @@ -280,6 +332,14 @@ func TestWaitForCRDEstablished(t *testing.T) { } } +// TestDeleteTransientVersionPod tests the DeleteTransientVersionPod function +// It checks the following cases: +// 1. k8s client error during GetPodsByLabel +// 2. no k8s client error and no transient pods found +// 3. no k8s client error and transient pods found but not removed +// 4. no k8s client error and transient pods found and removed +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTransientVersionPod(t *testing.T) { // declare and initialize variables used throughout the test cases var versionPodLabel, name, invalidName, namespace string @@ -389,6 +449,13 @@ func TestDeleteTransientVersionPod(t *testing.T) { } } +// TestGetBetaCSIDriverInformation tests the GetBetaCSIDriverInformation function +// It checks for the following conditions: +// - no beta CSI driver found +// - valid current beta CSI driver found +// - k8s error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetBetaCSIDriverInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -525,6 +592,14 @@ func TestGetBetaCSIDriverInformation(t *testing.T) { } } +// TestPutBetaCSIDriver tests the PutBetaCSIDriver function +// It checks the following cases: +// - create a beta CSI Driver and no k8s error occurs +// - create a beta CSI Driver and a k8s error occurs +// - update a beta CSI Driver and no k8s error occurs +// - update a beta CSI Driver and a k8s error occurs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutBetaCSIDriver(t *testing.T) { driverName := getCSIDriverName() appLabel := TridentCSILabel @@ -668,6 +743,12 @@ func TestPutBetaCSIDriver(t *testing.T) { } } +// TestDeleteTridentBetaCSIDriverCR tests the DeleteTridentBetaCSIDriverCR function +// It checks that the function returns the expected error when the k8s client +// returns the expected error. +// It returns nil when the k8s client returns nil. +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentBetaCSIDriverCR(t *testing.T) { // arrange variables for the tests var emptyBetaCSIDriverList, unwantedBetaCSIDrivers []storagev1beta1.CSIDriver @@ -766,6 +847,13 @@ func TestDeleteTridentBetaCSIDriverCR(t *testing.T) { } } +// TestRemoveMultipleBetaCSIDriverCRs tests the RemoveMultipleBetaCSIDriverCRs function +// It checks the following cases: +// 1. No beta csi driver crs +// 2. K8s call error +// 3. Valid beta csi driver crs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleBetaCSIDriverCRs(t *testing.T) { // arrange variables for the tests var emptyCSIDriversCRs, undeletedCSIDriverCRs, unwantedCSIDriverCRs []storagev1beta1.CSIDriver @@ -846,6 +934,13 @@ func TestRemoveMultipleBetaCSIDriverCRs(t *testing.T) { } } +// TestGetCSIDriverInformation tests the GetCSIDriverInformation function +// It checks the following cases: +// - fail with k8s error +// - pass with no beta CSI driver found and no k8s error +// - pass with valid current beta CSI driver found and no k8s error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetCSIDriverInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -982,6 +1077,14 @@ func TestGetCSIDriverInformation(t *testing.T) { } } +// TestPutCSIDriver tests the PutCSIDriver method +// It checks for the following cases: +// 1. Creating a CSI Driver and no k8s error occurs +// 2. Creating a CSI Driver and a k8s error occurs +// 3. Updating a CSI Driver and no k8s error occurs +// 4. Updating a CSI Driver and a k8s error occurs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutCSIDriver(t *testing.T) { var validCSIDriver *storagev1.CSIDriver @@ -1126,6 +1229,14 @@ func TestPutCSIDriver(t *testing.T) { } } +// TestDeleteTridentCSIDriverCR tests the DeleteTridentCSIDriverCR function. +// It checks the following cases: +// 1. GetCSIDriversByLabel fails +// 2. GetCSIDriversByLabel succeeds but RemoveMultipleCSIDriverCRs fails +// 3. GetCSIDriversByLabel succeeds and RemoveMultipleCSIDriverCRs succeeds +// It returns an error if any of the tests fail. +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentCSIDriverCR(t *testing.T) { // arrange variables for the tests var emptyCSIDriverList, unwantedCSIDrivers []storagev1.CSIDriver @@ -1224,6 +1335,13 @@ func TestDeleteTridentCSIDriverCR(t *testing.T) { } } +// TestRemoveMultipleCSIDriverCRs tests the RemoveMultipleCSIDriverCRs function +// It checks the following cases: +// 1. No CSI driver CRs +// 2. K8s call error +// 3. Valid CSI driver CRs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleCSIDriverCRs(t *testing.T) { // arrange variables for the tests var emptyCSIDriversCRs, undeletedCSIDriverCRs, unwantedCSIDriverCRs []storagev1.CSIDriver @@ -1304,6 +1422,13 @@ func TestRemoveMultipleCSIDriverCRs(t *testing.T) { } } +// TestGetClusterRoleInformation tests the GetClusterRoleInformation function +// It checks the following cases: +// - k8s error +// - no cluster role found +// - valid current cluster role found +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetClusterRoleInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -1440,6 +1565,11 @@ func TestGetClusterRoleInformation(t *testing.T) { } } +// TestPutClusterRole tests the PutClusterRole function +// It checks that the function returns the expected error when a k8s error occurs +// It also checks that the function returns nil when no k8s error occurs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutClusterRole(t *testing.T) { var validClusterRole *rbacv1.ClusterRole @@ -1581,6 +1711,14 @@ func TestPutClusterRole(t *testing.T) { } } +// TestDeleteTridentClusterRole tests the DeleteTridentClusterRole function +// It checks for the following conditions: +// - GetClusterRolesByLabel fails +// - GetClusterRolesByLabel returns no cluster role bindings +// - GetClusterRolesByLabel succeeds but RemoveMultipleClusterRoles fails +// - GetClusterRolesByLabel succeeds and RemoveMultipleClusterRoles succeeds +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentClusterRole(t *testing.T) { // arrange variables for the tests var emptyClusterRoleList, unwantedClusterRoles []rbacv1.ClusterRole @@ -1678,6 +1816,13 @@ func TestDeleteTridentClusterRole(t *testing.T) { } } +// TestRemoveMultipleClusterRoles tests the RemoveMultipleClusterRoles function +// It checks the following: +// - no cluster roles passed in +// - k8s call error +// - valid cluster roles passed in +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleClusterRoles(t *testing.T) { // arrange variables for the tests var emptyClusterRoles, unwantedClusterRoles, undeletedClusterRoles []rbacv1.ClusterRole @@ -1758,6 +1903,13 @@ func TestRemoveMultipleClusterRoles(t *testing.T) { } } +// TestGetClusterRoleBindingInformation tests the GetClusterRoleBindingInformation function +// It checks the following cases: +// - k8s error +// - no cluster role binding found and no k8s error +// - valid current cluster role binding found and no k8s error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetClusterRoleBindingInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -1898,6 +2050,11 @@ func TestGetClusterRoleBindingInformation(t *testing.T) { } } +// TestPutClusterRoleBinding tests the PutClusterRoleBinding function +// It checks that the correct k8s client calls are made and that the +// correct error is returned. +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutClusterRoleBinding(t *testing.T) { var validClusterRoleBinding *rbacv1.ClusterRoleBinding @@ -2041,6 +2198,13 @@ func TestPutClusterRoleBinding(t *testing.T) { } } +// TestDeleteTridentClusterRoleBinding tests the DeleteTridentClusterRoleBinding function +// It checks the following cases: +// - GetClusterRoleBindingsByLabel fails +// - GetClusterRoleBindingsByLabel succeeds but RemoveMultipleClusterRoleBindings fails +// - GetClusterRoleBindingsByLabel succeeds and RemoveMultipleClusterRoleBindings succeeds +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentClusterRoleBinding(t *testing.T) { // arrange variables for the tests var emptyClusterRoleBindingList, unwantedClusterRoleBindings []rbacv1.ClusterRoleBinding @@ -2138,6 +2302,13 @@ func TestDeleteTridentClusterRoleBinding(t *testing.T) { } } +// TestRemoveMultipleClusterRoleBindings tests the RemoveMultipleClusterRoleBindings function +// It checks the following cases: +// 1. No cluster role bindings +// 2. K8s call error +// 3. Valid cluster role bindings +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleClusterRoleBindings(t *testing.T) { // arrange variables for the tests var emptyClusterRoleBindings, unwantedClusterRoleBindings, undeletedClusterRoleBindings []rbacv1.ClusterRoleBinding @@ -2220,6 +2391,13 @@ func TestRemoveMultipleClusterRoleBindings(t *testing.T) { } } +// TestGetDaemonSetInformation tests the GetDaemonSetInformation function +// It checks the following cases: +// 1. Expect to fail with k8s error +// 2. Expect to pass with no daemonset found and no k8s error +// 3. Expect to pass with current daemonset found and no k8s error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetDaemonSetInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -2352,6 +2530,14 @@ func TestGetDaemonSetInformation(t *testing.T) { } } +// TestPutDaemonSet tests the PutDaemonSet function +// It checks the following cases: +// - creating a DaemonSet and no k8s error occurs +// - creating a DaemonSet and a k8s error occurs +// - updating a DaemonSet and no k8s error occurs +// - updating a DaemonSet and a k8s error occurs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutDaemonSet(t *testing.T) { daemonSetName := TridentCSILabel nodeLabel := "app=node.csi.trident.netapp.io" @@ -2498,6 +2684,14 @@ func TestPutDaemonSet(t *testing.T) { } } +// TestDeleteTridentDaemonSet tests the DeleteTridentDaemonSet function +// It checks the following cases: +// 1. GetDaemonSetsByLabel fails +// 2. GetDaemonSetsByLabel returns no deployments +// 3. GetDaemonSetsByLabel succeeds but RemoveMultipleDeployments fails +// 4. GetDaemonSetsByLabel succeeds and RemoveMultipleDeployments succeeds +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentDaemonSet(t *testing.T) { // arrange variables for the tests var emptyDaemonSetList, unwantedDaemonSets []appsv1.DaemonSet @@ -2580,6 +2774,10 @@ func TestDeleteTridentDaemonSet(t *testing.T) { } } +// TestRemoveMultipleDaemonSets tests the RemoveMultipleDaemonSets function +// It checks that the correct k8s calls are made and that the correct errors are returned +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleDaemonSets(t *testing.T) { // arrange variables for the tests var emptyDaemonSets, unwantedDaemonSets []appsv1.DaemonSet @@ -2658,6 +2856,13 @@ func TestRemoveMultipleDaemonSets(t *testing.T) { } } +// TestGetDeploymentInformation tests the GetDeploymentInformation function +// It checks the following cases: +// - k8s error +// - no daemonset found +// - current daemonset found +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetDeploymentInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -2790,6 +2995,14 @@ func TestGetDeploymentInformation(t *testing.T) { } } +// TestPutDeployment tests the PutDeployment function +// It checks the following cases: +// - creating a Deployment and no k8s error occurs +// - creating a Deployment and a k8s error occurs +// - updating a Deployment and no k8s error occurs +// - updating a Deployment and a k8s error occurs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutDeployment(t *testing.T) { deploymentName := getDeploymentName(true) deployment := &appsv1.Deployment{ @@ -2938,6 +3151,11 @@ func TestPutDeployment(t *testing.T) { } } +// TestDeleteTridentDeployment tests the DeleteTridentDeployment function +// It checks that the function returns the expected error when the k8s client +// returns the expected error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentDeployment(t *testing.T) { // arrange variables for the tests var emptyDeploymentList, unwantedDeployments []appsv1.Deployment @@ -3020,6 +3238,13 @@ func TestDeleteTridentDeployment(t *testing.T) { } } +// TestRemoveMultipleDeployments tests the RemoveMultipleDeployments function +// It checks the following cases: +// 1. No deployments to delete +// 2. K8s call error +// 3. Valid deployments +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleDeployments(t *testing.T) { // arrange variables for the tests var emptyDeploymentList, unwantedDeployments []appsv1.Deployment @@ -3098,6 +3323,14 @@ func TestRemoveMultipleDeployments(t *testing.T) { } } +// TestGetPodSecurityPolicyInformation tests the GetPodSecurityPolicyInformation function +// It checks for the following: +// - returns the correct current pod security policy +// - returns the correct unwanted pod security policies +// - returns the correct create pod security policy boolean +// - returns the correct error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetPodSecurityPolicyInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -3236,6 +3469,14 @@ func TestGetPodSecurityPolicyInformation(t *testing.T) { } } +// TestPutPodSecurityPolicy tests the PutPodSecurityPolicy function +// It checks the following cases: +// - create a new PodSecurityPolicy +// - update an existing PodSecurityPolicy +// - fail to create a new PodSecurityPolicy +// - fail to update an existing PodSecurityPolicy +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutPodSecurityPolicy(t *testing.T) { pspName := getPSPName() podSecurityPolicy := &policyv1beta1.PodSecurityPolicy{ @@ -3372,6 +3613,14 @@ func TestPutPodSecurityPolicy(t *testing.T) { } } +// TestDeleteTridentPodSecurityPolicy tests the DeleteTridentPodSecurityPolicy function +// It checks that the function returns the expected error when the k8s client returns an error +// It checks that the function returns nil when the k8s client returns no policies +// It checks that the function returns the expected error when the k8s client returns policies but +// the delete fails +// It checks that the function returns nil when the k8s client returns policies and the delete succeeds +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentPodSecurityPolicy(t *testing.T) { // arrange variables for the tests var emptyPSPList, unwantedPSPs []policyv1beta1.PodSecurityPolicy @@ -3469,6 +3718,11 @@ func TestDeleteTridentPodSecurityPolicy(t *testing.T) { } } +// TestRemoveMultiplePodSecurityPolicies tests the RemoveMultiplePodSecurityPolicies function +// It checks that the function returns the correct error when the k8s client fails to delete +// a pod security policy +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultiplePodSecurityPolicies(t *testing.T) { // arrange variables for the tests var emptyPodSecurityPolicyList, undeletedPodSecurityPolicies, unwantedPodSecurityPolicies []policyv1beta1.PodSecurityPolicy @@ -3550,6 +3804,13 @@ func TestRemoveMultiplePodSecurityPolicies(t *testing.T) { } } +// TestGetSecretInformation tests the GetSecretInformation function +// It checks for the following conditions: +// 1. k8s error +// 2. no secrets found +// 3. valid current secrets found +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetSecretInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -3693,6 +3954,13 @@ func TestGetSecretInformation(t *testing.T) { } } +// TestPutSecret tests the PutSecret function +// It checks the following cases: +// - createSecret is true and no k8s error occurs +// - createSecret is false +// - createSecret is true and a k8s error occurs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutSecret(t *testing.T) { secretName := getProtocolSecretName() namespace := "trident" @@ -3786,6 +4054,12 @@ func TestPutSecret(t *testing.T) { } } +// TestDeleteTridentSecret tests the DeleteTridentSecret function +// It checks that the function returns the expected error when the +// k8s client returns an error, and that it returns nil when the +// k8s client returns no error. +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentSecret(t *testing.T) { // arrange variables for the tests var emptySecretList, unwantedSecrets []corev1.Secret @@ -3892,6 +4166,12 @@ func TestDeleteTridentSecret(t *testing.T) { } } +// TestRemoveMultipleSecrets tests the RemoveMultipleSecrets function +// It checks that the function returns the correct error when the k8s client +// returns an error, and that it returns nil when the k8s client does not return +// an error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleSecrets(t *testing.T) { // arrange variables for the tests var emptySecretList, undeletedSecrets, unwantedSecrets []corev1.Secret @@ -3979,6 +4259,11 @@ func TestRemoveMultipleSecrets(t *testing.T) { } } +// TestGetServiceInformation tests the GetServiceInformation function +// It checks to see if the correct service is returned and that the correct +// unwanted services are returned +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetServiceInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -4121,6 +4406,10 @@ func TestGetServiceInformation(t *testing.T) { } } +// TestPutService tests the PutService function +// It checks that the correct k8s client functions are called and that the correct error is returned +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutService(t *testing.T) { serviceName := getServiceName() service := &corev1.Service{ @@ -4259,6 +4548,14 @@ func TestPutService(t *testing.T) { } } +// TestDeleteTridentService tests the DeleteTridentService function +// It checks that the function returns an error when the GetServicesByLabel function fails +// It checks that the function returns nil when the GetServicesByLabel function succeeds but +// the RemoveMultipleServices function fails +// It checks that the function returns nil when the GetServicesByLabel function succeeds and +// the RemoveMultipleServices function succeeds +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentService(t *testing.T) { // arrange variables for the tests var emptyServiceList, unwantedServices []corev1.Service @@ -4366,6 +4663,13 @@ func TestDeleteTridentService(t *testing.T) { } } +// TestRemoveMultipleServices tests the RemoveMultipleServices function +// It checks the following cases: +// - no services +// - k8s call error +// - valid services +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleServices(t *testing.T) { // arrange variables for the tests var emptyServiceList, unwantedServices []corev1.Service @@ -4444,6 +4748,13 @@ func TestRemoveMultipleServices(t *testing.T) { } } +// TestGetServiceAccountInformation tests the GetServiceAccountInformation function +// It checks for the following cases: +// - k8s error +// - no service accounts found +// - valid service accounts found +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetServiceAccountInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var label, name, invalidName, namespace string @@ -4610,6 +4921,14 @@ func TestGetServiceAccountInformation(t *testing.T) { } } +// TestPutServiceAccount tests the PutServiceAccount function +// It checks for the following cases: +// - creating a service account and no k8s error occurs +// - creating a service account and a k8s error occurs +// - updating a service account and no k8s error occurs +// - updating a service account and a k8s error occurs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutServiceAccount(t *testing.T) { serviceAccountName := getServiceAccountName(true) serviceAccount := &corev1.ServiceAccount{ @@ -4771,6 +5090,11 @@ func TestPutServiceAccount(t *testing.T) { } } +// TestDeleteTridentServiceAccount tests the DeleteTridentServiceAccount function +// It checks that the function returns the expected error when the k8s client returns an error +// It also checks that the function returns nil when the k8s client returns no error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentServiceAccount(t *testing.T) { // arrange variables for the tests var emptyServiceAccountList, unwantedServiceAccounts []corev1.ServiceAccount @@ -4878,6 +5202,13 @@ func TestDeleteTridentServiceAccount(t *testing.T) { } } +// TestRemoveMultipleServiceAccounts tests the RemoveMultipleServiceAccounts function +// It checks for the following cases: +// 1. No service accounts +// 2. K8s call error +// 3. Valid service accounts +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleServiceAccounts(t *testing.T) { // arrange variables for the tests var emptyServiceAccountList, undeletedServiceAccounts, unwantedServiceAccounts []corev1.ServiceAccount @@ -4965,6 +5296,14 @@ func TestRemoveMultipleServiceAccounts(t *testing.T) { } } +// TestGetTridentOpenShiftSCCInformation tests the GetTridentOpenShiftSCCInformation function +// It checks the following cases: +// - when the k8s client returns an error +// - when the k8s client returns no error and no openshift scc is found +// - when the k8s client returns no error and an openshift scc is found +// - when the k8s client returns no error and an openshift scc is found, but it should be updated +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetTridentOpenShiftSCCInformation(t *testing.T) { // declare and initialize variables used throughout the test cases var name, username string @@ -5110,6 +5449,13 @@ func TestGetTridentOpenShiftSCCInformation(t *testing.T) { } } +// TestExecPodForVersionInformation tests the ExecPodForVersionInformation function +// It checks the following cases: +// 1. No command supplied +// 2. K8s error when exec the supplied cmd +// 3. No error when exec the supplied cmd +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestExecPodForVersionInformation(t *testing.T) { podName := "trident-transient-pod" cmd := []string{"/bin/tridentctl", "version", "--client", "-o", "yaml"} @@ -5203,6 +5549,13 @@ func TestExecPodForVersionInformation(t *testing.T) { } } +// TestGetCSISnapshotterVersion tests the GetCSISnapshotterVersion function +// It checks the following cases: +// 1. When the deployment is empty, it should return v1 +// 2. When the deployment contains a snapshotter:v4 image, it should return v1 +// 3. When the deployment contains a snapshotter image without a version, it should return an empty string +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestGetCSISnapshotterVersion(t *testing.T) { var emptyDeployment, validDeployment, invalidDeployment *appsv1.Deployment @@ -5283,6 +5636,11 @@ func TestGetCSISnapshotterVersion(t *testing.T) { } } +// TestDeleteTridentStatefulSet tests the DeleteTridentStatefulSet function +// It checks that the function returns the expected error when the k8s client +// returns the expected error +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteTridentStatefulSet(t *testing.T) { // arrange variables for the tests var emptyStatefulSets, unwantedStatefulSets []appsv1.StatefulSet @@ -5365,6 +5723,16 @@ func TestDeleteTridentStatefulSet(t *testing.T) { } } +// TestPutOpenShiftSCC tests the PutOpenShiftSCC function +// It checks the following cases: +// - when creating OpenShift SCCs and no k8s error occurs when removing Trident users from OpenShiftSCC +// - when creating OpenShift SCCs and a k8s error occurs when removing Trident users from OpenShiftSCC +// - when creating OpenShift SCCs and no k8s error occurs +// - when creating OpenShift SCCs and a k8s error occurs +// - when updating OpenShift SCCs and no k8s error occurs +// - when updating OpenShift SCCs and a k8s error occurs +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestPutOpenShiftSCC(t *testing.T) { // arrange variables for the tests openShiftSCCUserName := getOpenShiftSCCUserName() @@ -5558,6 +5926,13 @@ func TestPutOpenShiftSCC(t *testing.T) { } } +// TestDeleteOpenShiftSCC tests the DeleteOpenShiftSCC function +// It checks the following: +// - when GetOpenShiftSCCByName fails +// - when GetOpenShiftSCCByName succeeds but DeleteObjectByYAML fails +// - when GetOpenShiftSCCByName succeeds and RemoveTridentUserFromOpenShiftSCC is called +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestDeleteOpenShiftSCC(t *testing.T) { // arrange variables for the tests openShiftSCCName := "trident" @@ -5649,6 +6024,13 @@ func TestDeleteOpenShiftSCC(t *testing.T) { } } +// TestRemoveMultiplePods tests the RemoveMultiplePods function +// It checks the following cases: +// 1. No pods to delete +// 2. Error from k8s client +// 3. Valid pods to delete +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultiplePods(t *testing.T) { // arrange variables for the tests var emptyPodList, undeletedPods, unwantedPods []corev1.Pod @@ -5736,6 +6118,13 @@ func TestRemoveMultiplePods(t *testing.T) { } } +// TestRemoveMultipleStatefulSets tests the RemoveMultipleStatefulSets function +// It checks the following cases: +// 1. No stateful sets to delete +// 2. Error returned from k8s client +// 3. Successful deletion of stateful sets +// +// -- Doc autogenerated on 2022-05-12 21:04:12.772596 -- func TestRemoveMultipleStatefulSets(t *testing.T) { // arrange variables for the tests var emptyStatefulSetList, unwantedStatefulSets []appsv1.StatefulSet diff --git a/operator/controllers/orchestrator/installer/uninstaller.go b/operator/controllers/orchestrator/installer/uninstaller.go index 221c61f28..edd20a7d2 100644 --- a/operator/controllers/orchestrator/installer/uninstaller.go +++ b/operator/controllers/orchestrator/installer/uninstaller.go @@ -11,6 +11,17 @@ import ( k8sclient "github.com/netapp/trident/cli/k8s_client" ) +// UninstallTrident uninstalls Trident from the Kubernetes cluster. +// It returns an error if the uninstall fails. +// Returns: +// error: if the uninstall fails +// Example: +// err := i.UninstallTrident() +// if err != nil { +// log.Errorf("Uninstall failed: %v", err) +// } +// +// -- Doc autogenerated on 2022-05-12 21:12:31.321270 -- func (i *Installer) UninstallTrident() error { // 1. preview CSI Trident --> uninstall preview CSI Trident // 2. preview CSI Trident & legacy Trident --> uninstall preview CSI Trident @@ -106,6 +117,14 @@ func (i *Installer) UninstallTrident() error { return nil } +// UninstallCSIPreviewTrident uninstalls Trident CSI Preview +// It returns an error if the uninstall fails +// Returns: +// error: error object if the uninstall fails +// Example: +// err := i.UninstallCSIPreviewTrident() +// +// -- Doc autogenerated on 2022-05-12 21:12:31.321270 -- func (i *Installer) UninstallCSIPreviewTrident() error { appLabel = TridentCSILabel appLabelKey = TridentCSILabelKey @@ -114,6 +133,17 @@ func (i *Installer) UninstallCSIPreviewTrident() error { return i.client.DeleteTridentStatefulSet(appLabel) } +// UninstallLegacyTrident removes the legacy Trident deployment and RBAC objects +// It returns an error if the uninstall fails +// Returns: +// error: any errors encountered during uninstall +// Example: +// err := i.UninstallLegacyTrident() +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 21:12:31.321270 -- func (i *Installer) UninstallLegacyTrident() error { appLabel = TridentLegacyLabel appLabelKey = TridentLegacyLabelKey @@ -157,6 +187,14 @@ func (i *Installer) removeRBACObjects(csi bool) error { return nil } +// ObliviateCRDs removes all Trident CRDs from the cluster. +// It returns an error if any CRD cannot be deleted. +// Returns: +// error - any error encountered +// Example: +// err := installer.ObliviateCRDs() +// +// -- Doc autogenerated on 2022-05-12 21:12:31.321270 -- func (i *Installer) ObliviateCRDs() error { return cmd.ObliviateCRDs(i.client, i.tridentCRDClient, k8sTimeout) } diff --git a/operator/controllers/orchestrator/installer/utils.go b/operator/controllers/orchestrator/installer/utils.go index f5f1d75bc..8fb95bd0e 100644 --- a/operator/controllers/orchestrator/installer/utils.go +++ b/operator/controllers/orchestrator/installer/utils.go @@ -1,5 +1,14 @@ package installer +// getServiceAccountName returns the name of the service account to use for Trident +// Parameters: +// csi (bool) - true if Trident is being installed as a CSI driver; false if Trident is being installed as a legacy driver +// Returns: +// (string) - the name of the service account to use for Trident +// Example: +// name := getServiceAccountName(true) +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getServiceAccountName(csi bool) string { if csi { return TridentCSI @@ -8,6 +17,16 @@ func getServiceAccountName(csi bool) string { } } +// getClusterRoleName returns the name of the cluster role to use for the given CSI flag +// Parameters: +// csi - true if Trident should be installed as a CSI driver +// Returns: +// string - name of the cluster role to use +// Example: +// getClusterRoleName(false) +// > "trident" +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getClusterRoleName(csi bool) string { if csi { return TridentCSI @@ -16,6 +35,16 @@ func getClusterRoleName(csi bool) string { } } +// getClusterRoleBindingName returns the name of the cluster role binding to use +// Parameters: +// csi - true if Trident should be installed as a CSI driver +// Returns: +// string - the name of the cluster role binding to use +// Example: +// getClusterRoleBindingName(true) +// > "trident-csi" +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getClusterRoleBindingName(csi bool) string { if csi { return TridentCSI @@ -24,22 +53,59 @@ func getClusterRoleBindingName(csi bool) string { } } +// getPSPName returns the name of the PSP to use +// Returns: +// string: the name of the PSP +// Example: +// psp := getPSPName() +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getPSPName() string { return TridentPSP } +// getServiceName returns the name of the service +// Returns: +// string: the name of the service +// Example: +// installer.getServiceName() +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getServiceName() string { return TridentCSI } +// getProtocolSecretName returns the name of the protocol secret +// Returns: +// string - the name of the protocol secret +// Example: +// getProtocolSecretName() +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getProtocolSecretName() string { return TridentCSI } +// getEncryptionSecretName returns the name of the secret that contains the encryption keys +// Returns: +// string: the name of the secret +// Example: +// getEncryptionSecretName() +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getEncryptionSecretName() string { return TridentEncryptionKeys } +// getDeploymentName returns the name of the Trident deployment +// Parameters: +// csi - true if the CSI deployment should be used +// Returns: +// The name of the Trident deployment +// Example: +// getDeploymentName(true) returns "trident-csi" +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getDeploymentName(csi bool) string { if csi { return TridentCSI @@ -48,14 +114,37 @@ func getDeploymentName(csi bool) string { } } +// getDaemonSetName returns the name of the Trident CSI DaemonSet +// Returns: +// string: the name of the Trident CSI DaemonSet +// Example: +// name := getDaemonSetName() +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getDaemonSetName() string { return TridentCSI } +// getCSIDriverName returns the name of the CSI driver +// Returns: +// string: the name of the CSI driver +// Example: +// csiDriverName := getCSIDriverName() +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getCSIDriverName() string { return CSIDriver } +// getOpenShiftSCCUserName returns the name of the OpenShift SCC user +// depending on whether CSI is enabled or not. +// Returns: +// TridentCSI: if CSI is enabled +// TridentLegacy: if CSI is disabled +// Example: +// sccuser := getOpenShiftSCCUserName() +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getOpenShiftSCCUserName() string { if csi { return TridentCSI @@ -64,6 +153,13 @@ func getOpenShiftSCCUserName() string { } } +// getOpenShiftSCCName returns the name of the SCC to use for OpenShift +// Returns: +// string: the name of the SCC to use for OpenShift +// Example: +// sccName := installer.getOpenShiftSCCName() +// +// -- Doc autogenerated on 2022-05-12 21:13:42.659080 -- func getOpenShiftSCCName() string { return OpenShiftSCCName } diff --git a/operator/controllers/provisioner/apis/netapp/v1/register.go b/operator/controllers/provisioner/apis/netapp/v1/register.go index 018e09b4f..0ac19d9f9 100644 --- a/operator/controllers/provisioner/apis/netapp/v1/register.go +++ b/operator/controllers/provisioner/apis/netapp/v1/register.go @@ -32,6 +32,17 @@ var ( ) // Adds the list of known types to the given scheme. +// addKnownTypes adds the set of types defined in this +// It returns the SchemeBuilder. +// Parameters: +// scheme: the SchemeBuilder instance used to register the types +// addToScheme: a function that adds the types to a scheme +// Returns: +// the SchemeBuilder instance used to register the types +// Example: +// addKnownTypes(s, api.SchemeBuilder.AddToScheme) +// +// -- Doc autogenerated on 2022-05-12 21:16:56.865707 -- func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &TridentProvisioner{}, diff --git a/operator/controllers/provisioner/client/clientset/versioned/fake/clientset_generated.go b/operator/controllers/provisioner/client/clientset/versioned/fake/clientset_generated.go index f2d4769ac..2605591f7 100644 --- a/operator/controllers/provisioner/client/clientset/versioned/fake/clientset_generated.go +++ b/operator/controllers/provisioner/client/clientset/versioned/fake/clientset_generated.go @@ -52,10 +52,30 @@ type Clientset struct { tracker testing.ObjectTracker } +// Discovery is the discovery interface +// It returns a fake discovery client +// Returns: +// *fake.Discovery +// Example: +// discovery := fake.Discovery() +// +// -- Doc autogenerated on 2022-05-12 21:17:18.298051 -- func (c *Clientset) Discovery() discovery.DiscoveryInterface { return c.discovery } +// Tracker is a fake implementation of the Tracker interface. +// It returns fake objects from the fake client. +// Returns: +// *fake.Client - fake client +// *fake.Tracker - fake tracker +// Example: +// c := fake.NewSimpleClientset() +// t := c.Tracker() +// fakeClient := t.Client() +// fakeTracker := t.Tracker() +// +// -- Doc autogenerated on 2022-05-12 21:17:18.298051 -- func (c *Clientset) Tracker() testing.ObjectTracker { return c.tracker } diff --git a/operator/controllers/provisioner/client/clientset/versioned/typed/netapp/v1/fake/fake_netapp_client.go b/operator/controllers/provisioner/client/clientset/versioned/typed/netapp/v1/fake/fake_netapp_client.go index 59fa6e60d..213971bdb 100644 --- a/operator/controllers/provisioner/client/clientset/versioned/typed/netapp/v1/fake/fake_netapp_client.go +++ b/operator/controllers/provisioner/client/clientset/versioned/typed/netapp/v1/fake/fake_netapp_client.go @@ -14,6 +14,18 @@ type FakeTridentV1 struct { *testing.Fake } +// TridentProvisioners implements TridentProvisionerInterface +// It returns a fake TridentProvisionerInterface +// Parameters: +// c - a TridentClient +// namespace - the namespace +// Returns: +// a fake TridentProvisionerInterface +// Example: +// c := fake.NewSimpleClientset() +// fake.TridentProvisioners(c, "default") +// +// -- Doc autogenerated on 2022-05-12 21:18:39.129394 -- func (c *FakeTridentV1) TridentProvisioners(namespace string) v1.TridentProvisionerInterface { return &FakeTridentProvisioners{c, namespace} } diff --git a/operator/controllers/provisioner/client/clientset/versioned/typed/netapp/v1/netapp_client.go b/operator/controllers/provisioner/client/clientset/versioned/typed/netapp/v1/netapp_client.go index 832d7ecd9..baa490bbc 100644 --- a/operator/controllers/provisioner/client/clientset/versioned/typed/netapp/v1/netapp_client.go +++ b/operator/controllers/provisioner/client/clientset/versioned/typed/netapp/v1/netapp_client.go @@ -20,6 +20,16 @@ type TridentV1Client struct { restClient rest.Interface } +// TridentProvisioners returns a TridentProvisionerInterface. +// Parameters: +// namespace - the namespace where Trident is installed +// Returns: +// a TridentProvisionerInterface +// Example: +// c := v1.NewTridentV1Client("", "", nil) +// c.TridentProvisioners("trident").Get("trident") +// +// -- Doc autogenerated on 2022-05-12 21:18:04.957298 -- func (c *TridentV1Client) TridentProvisioners(namespace string) TridentProvisionerInterface { return newTridentProvisioners(c, namespace) } @@ -52,6 +62,17 @@ func New(c rest.Interface) *TridentV1Client { return &TridentV1Client{c} } +// setConfigDefaults sets the default values for the provided config +// It returns an error if the config is invalid +// Parameters: +// config: the configuration to set the defaults for +// Returns: +// error: an error if the config is invalid +// Example: +// config := &rest.Config{} +// setConfigDefaults(config) +// +// -- Doc autogenerated on 2022-05-12 21:18:04.957298 -- func setConfigDefaults(config *rest.Config) error { gv := v1.SchemeGroupVersion config.GroupVersion = &gv diff --git a/operator/controllers/provisioner/client/informers/externalversions/factory.go b/operator/controllers/provisioner/client/informers/externalversions/factory.go index 4a863e53d..5f0d09672 100644 --- a/operator/controllers/provisioner/client/informers/externalversions/factory.go +++ b/operator/controllers/provisioner/client/informers/externalversions/factory.go @@ -130,6 +130,19 @@ func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[ref // InternalInformerFor returns the SharedIndexInformer for obj using an internal // client. +// InformerFor returns the SharedIndexInformer for objects of a given type. +// It is a convenience method for calling NewFilteredSharedInformerFactory. +// Parameters: +// obj - the object type +// newFunc - a function that creates a new object of the given type. +// This is used to instantiate a new informer. +// If newFunc is nil, the default informer for the given +// Returns: +// The SharedIndexInformer for the given object type +// Example: +// informer := f.InformerFor(&v1.Pod{}, newPodInformer) +// +// -- Doc autogenerated on 2022-05-12 21:19:03.478754 -- func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { f.lock.Lock() defer f.lock.Unlock() @@ -161,6 +174,13 @@ type SharedInformerFactory interface { Trident() netapp.Interface } +// Trident returns a new interface to the Trident API. +// Returns: +// * netapp.Interface: Trident API client +// Example: +// trident := externalversions.Trident() +// +// -- Doc autogenerated on 2022-05-12 21:19:03.478754 -- func (f *sharedInformerFactory) Trident() netapp.Interface { return netapp.New(f, f.namespace, f.tweakListOptions) } diff --git a/operator/controllers/provisioner/client/informers/externalversions/netapp/v1/tridentprovisioner.go b/operator/controllers/provisioner/client/informers/externalversions/netapp/v1/tridentprovisioner.go index 766e4c0f4..f0b7de285 100644 --- a/operator/controllers/provisioner/client/informers/externalversions/netapp/v1/tridentprovisioner.go +++ b/operator/controllers/provisioner/client/informers/externalversions/netapp/v1/tridentprovisioner.go @@ -63,14 +63,48 @@ func NewFilteredTridentProvisionerInformer(client versioned.Interface, namespace ) } +// defaultInformer is used to initialize the TridentProvisioner informer +// It returns a SharedIndexInformer for TridentProvisioner objects +// Parameters: +// client - the TridentProvisioner client +// resyncPeriod - the resync period +// indexers - the indexers +// Returns: +// a SharedIndexInformer for TridentProvisioner objects +// Example: +// defaultInformer := v1.defaultInformer(clientset, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) +// +// -- Doc autogenerated on 2022-05-12 21:19:39.312814 -- func (f *tridentProvisionerInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { return NewFilteredTridentProvisionerInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } +// Informer provides access to a shared informer and lister for +// TridentProvisioners. +// It returns a cache.SharedIndexInformer +// Returns: +// * cache.SharedIndexInformer +// Example: +// tpInformer := informers.NewTridentProvisionerInformer(client, 0) +// tpInformer.Informer() +// tpInformer.Lister() +// +// -- Doc autogenerated on 2022-05-12 21:19:39.312814 -- func (f *tridentProvisionerInformer) Informer() cache.SharedIndexInformer { return f.factory.InformerFor(&netappv1.TridentProvisioner{}, f.defaultInformer) } +// Lister implements a generic lister for TridentProvisioner resources. +// It returns TridentProvisioner objects retrieved from a shared informer's store. +// Returns: +// * TridentProvisionerLister +// * TridentProvisionerNamespaceLister +// Example: +// lister := listers.NewTridentProvisionerLister() +// svc, err := lister.Get("foo") +// Use "NewTridentProvisionerLister" to construct a new TridentProvisionerLister. +// +// -- Doc autogenerated on 2022-05-12 21:19:39.312814 -- func (f *tridentProvisionerInformer) Lister() v1.TridentProvisionerLister { return v1.NewTridentProvisionerLister(f.Informer().GetIndexer()) } diff --git a/utils/crypto.go b/utils/crypto.go index 30845d98e..b86c7ef82 100644 --- a/utils/crypto.go +++ b/utils/crypto.go @@ -36,6 +36,19 @@ type CertInfo struct { // the parameters are configurable...the serial numbers and principal names are // hardcoded, the validity period is hardcoded to 1970-2070, and the algorithm // and key size are hardcoded to 521-bit elliptic curve. +// MakeHTTPCertInfo creates a CA, server, and client certificate for use with HTTPS +// It returns a CertInfo struct with the base64 encoded certificates and keys +// Parameters: +// caCertName: The name to use for the CA certificate +// serverCertName: The name to use for the server certificate +// clientCertName: The name to use for the client certificate +// Returns: +// *CertInfo: A struct with the base64 encoded certificates and keys +// error: An error if one occurred +// Example: +// certInfo, err := MakeHTTPCertInfo("my-ca", "my-server", "my-client") +// +// -- Doc autogenerated on 2022-05-12 14:15:35.781744 -- func MakeHTTPCertInfo(caCertName, serverCertName, clientCertName string) (*CertInfo, error) { certInfo := &CertInfo{} @@ -154,6 +167,21 @@ func MakeHTTPCertInfo(caCertName, serverCertName, clientCertName string) (*CertI return certInfo, nil } +// makeSubject creates a pkix.Name for the given common name +// It returns a pkix.Name with the following fields: +// Country: []string{"US"} +// Locality: []string{"RTP"} +// Organization: []string{"NetApp"} +// Province: []string{"NC"} +// CommonName: cn +// Parameters: +// cn: the common name to use +// Returns: +// a pkix.Name with the above fields +// Example: +// makeSubject("test") +// +// -- Doc autogenerated on 2022-05-12 14:15:35.781744 -- func makeSubject(cn string) pkix.Name { return pkix.Name{ Country: []string{"US"}, @@ -164,6 +192,18 @@ func makeSubject(cn string) pkix.Name { } } +// makeSerial creates a random serial number for a certificate +// It returns a big.Int and an error +// Returns: +// *big.Int: the serial number +// error: if any +// Example: +// serial, err := makeSerial() +// if nil != err { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 14:15:35.781744 -- func makeSerial() (*big.Int, error) { maxSerial := big.NewInt(math.MaxInt64) serial, err := rand.Int(rand.Reader, maxSerial) @@ -173,6 +213,24 @@ func makeSerial() (*big.Int, error) { return serial, nil } +// keyToBase64String converts an ECDSA private key to a base64 encoded string +// It returns an error if the key cannot be marshaled +// Parameters: +// key - the ECDSA private key to convert +// Returns: +// string - the base64 encoded string +// error - any error encountered +// Example: +// key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) +// if err != nil { +// return +// } +// keyString, err := keyToBase64String(key) +// if err != nil { +// return +// } +// +// -- Doc autogenerated on 2022-05-12 14:15:35.781744 -- func keyToBase64String(key *ecdsa.PrivateKey) (string, error) { b, err := x509.MarshalECPrivateKey(key) if err != nil { @@ -182,6 +240,20 @@ func keyToBase64String(key *ecdsa.PrivateKey) (string, error) { return base64.StdEncoding.EncodeToString(keyBytes), nil } +// certToBase64String converts a DER encoded certificate to a base64 encoded string +// It returns an empty string if the input is not a valid DER encoded certificate +// Parameters: +// derBytes: DER encoded certificate +// Returns: +// base64 encoded string +// Example: +// derBytes, err := ioutil.ReadFile("cert.der") +// if err != nil { +// return err +// } +// base64Cert := certToBase64String(derBytes) +// +// -- Doc autogenerated on 2022-05-12 14:15:35.781744 -- func certToBase64String(derBytes []byte) string { certBytes := pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) return base64.StdEncoding.EncodeToString(certBytes) @@ -276,6 +348,21 @@ func PKCS7Pad(input []byte, blockSize int) []byte { } // PKCS7Pad will remove the padding from input according to PKCS#7 standard +// PKCS7Unpad removes the padding from the input. +// It returns an error if the padding is invalid. +// Parameters: +// input - the input to be unpadded +// Returns: +// the unpadded input +// an error if the padding is invalid +// Example: +// input := []byte("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") +// unpadded, err := PKCS7Unpad(input) +// if err != nil { +// panic("bad padding") +// } +// +// -- Doc autogenerated on 2022-05-12 14:15:35.781744 -- func PKCS7Unpad(input []byte) ([]byte, error) { inputLength := len(input) paddingLength := int(input[inputLength-1]) diff --git a/utils/crypto_test.go b/utils/crypto_test.go index e26264483..57b434ec2 100644 --- a/utils/crypto_test.go +++ b/utils/crypto_test.go @@ -8,6 +8,11 @@ import ( "testing" ) +// TestGenerateAESKey tests the GenerateAESKey function +// It checks that the key is 32 bytes long, and that it is base64-encoded. +// It also checks that the key is random by generating two keys and comparing them. +// +// -- Doc autogenerated on 2022-05-12 14:17:58.986546 -- func TestGenerateAESKey(t *testing.T) { var ( key1, key2 string @@ -39,6 +44,11 @@ func TestGenerateAESKey(t *testing.T) { } } +// TestEncryptStringWithAES tests the EncryptStringWithAES and DecryptStringWithAES functions. +// It checks that the returned string is base64-encoded, and that the decrypted string matches +// the original string. +// +// -- Doc autogenerated on 2022-05-12 14:17:58.986546 -- func TestEncryptStringWithAES(t *testing.T) { var ( encodedKey, encryptedText, decryptedText string @@ -107,6 +117,11 @@ func TestEncryptStringWithAES(t *testing.T) { } } +// TestPKCS7Pad tests the PKCS7Pad function +// It checks that padding is added, that the padded result is a multiple of the block size, +// that the pad bytes are correct, and that the padding can be removed +// +// -- Doc autogenerated on 2022-05-12 14:17:58.986546 -- func TestPKCS7Pad(t *testing.T) { blockSize := 16 // aes block size is 16 inputSizes := []int{ @@ -148,6 +163,11 @@ func TestPKCS7Pad(t *testing.T) { } } +// TestBigIntHash tests the bigIntHash function +// It checks that the function returns a hash that is different from the input +// and that it returns different hashes for different inputs +// +// -- Doc autogenerated on 2022-05-12 14:17:58.986546 -- func TestBigIntHash(t *testing.T) { var n big.Int h, err := bigIntHash(&n) diff --git a/utils/errors.go b/utils/errors.go index 90804971e..c0dd532ed 100644 --- a/utils/errors.go +++ b/utils/errors.go @@ -18,12 +18,36 @@ type bootstrapError struct { func (e *bootstrapError) Error() string { return e.message } +// BootstrapError is a wrapper for errors that occur during Trident bootstrap. +// It returns a string that can be used to display the error to the user. +// Parameters: +// err - the error that occurred +// Returns: +// error - the bootstrap error +// Example: +// err := utils.BootstrapError(err) +// log.WithFields(log.Fields{ +// "error": err.Error(), +// }).Error("Trident initialization failed.") +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func BootstrapError(err error) error { return &bootstrapError{ fmt.Sprintf("Trident initialization failed; %s", err.Error()), } } +// IsBootstrapError returns true if the error is a bootstrap error +// Parameters: +// err: error +// Returns: +// bool +// Example: +// if utils.IsBootstrapError(err) { +// log.Error("Bootstrap error") +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsBootstrapError(err error) bool { if err == nil { return false @@ -42,10 +66,31 @@ type foundError struct { func (e *foundError) Error() string { return e.message } +// FoundError is a custom error +// It returns a string message +// Parameters: +// message string +// Returns: +// error +// Example: +// if err := FoundError("not found"); err != nil { +// fmt.Println(err) +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func FoundError(message string) error { return &foundError{message} } +// IsFoundError returns true if the error is a foundError +// Parameters: +// err - error to check +// Returns: +// true if the error is a foundError +// Example: +// foundError := IsFoundError(err) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsFoundError(err error) bool { if err == nil { return false @@ -64,10 +109,29 @@ type notFoundError struct { func (e *notFoundError) Error() string { return e.message } +// NotFoundError is a custom error +// It returns a 404 error +// Parameters: +// message (string) - the error message +// Returns: +// error - the error +// Example: +// err := utils.NotFoundError("The resource could not be found") +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func NotFoundError(message string) error { return ¬FoundError{message} } +// IsNotFoundError returns true if the error is a not found error. +// Parameters: +// err: the error to check +// Returns: +// true if the error is a not found error +// Example: +// IsNotFoundError(fmt.Errorf("not found")) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsNotFoundError(err error) bool { if err == nil { return false @@ -80,6 +144,17 @@ func IsNotFoundError(err error) bool { // resourceNotFoundError - To identify external not found errors // /////////////////////////////////////////////////////////////////////////// +// IsResourceNotFoundError returns true if the error is a resource not found error. +// Parameters: +// err: the error to check +// Return: +// true if the error is a resource not found error, false otherwise +// Example: +// if IsResourceNotFoundError(err) { +// // handle resource not found error +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsResourceNotFoundError(err error) bool { if err == nil { return false @@ -97,12 +172,31 @@ type notReadyError struct { func (e *notReadyError) Error() string { return e.message } +// NotReadyError is an error +// It returns a string that Trident is initializing, please try again later +// Returns: +// *notReadyError +// Example: +// if err := utils.NotReadyError(); err != nil { +// fmt.Println(err.Error()) +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func NotReadyError() error { return ¬ReadyError{ "Trident is initializing, please try again later", } } +// IsNotReadyError returns true if the error is a not ready error +// Parameters: +// err - the error to check +// Returns: +// true if the error is a not ready error, false otherwise +// Example: +// err := utils.IsNotReadyError(err) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsNotReadyError(err error) bool { if err == nil { return false @@ -121,10 +215,31 @@ type unsupportedError struct { func (e *unsupportedError) Error() string { return e.message } +// UnsupportedError is an error that is returned when a feature is not supported +// It returns a message that can be displayed to the user +// Parameters: +// message - the message to be displayed +// Returns: +// error - the error object +// Example: +// err := UnsupportedError("Snapshot creation is not supported on this storage driver") +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func UnsupportedError(message string) error { return &unsupportedError{message} } +// IsUnsupportedError returns true if the error is an unsupportedError +// Parameters: +// err - error to check +// Returns: +// true if the error is an unsupportedError +// Example: +// if IsUnsupportedError(err) { +// // handle unsupported error +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsUnsupportedError(err error) bool { if err == nil { return false @@ -143,10 +258,29 @@ type volumeCreatingError struct { func (e *volumeCreatingError) Error() string { return e.message } +// VolumeCreatingError is returned when a volume is being created +// It returns a message that can be used to describe the error +// Parameters: +// message: the message to be returned +// Returns: +// error: an error object +// Example: +// err := utils.VolumeCreatingError("Error creating volume") +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func VolumeCreatingError(message string) error { return &volumeCreatingError{message} } +// IsVolumeCreatingError returns true if the error is a volumeCreatingError +// Parameters: +// err - error to check +// Returns: +// true if the error is a volumeCreatingError +// Example: +// utils.IsVolumeCreatingError(err) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsVolumeCreatingError(err error) bool { if err == nil { return false @@ -165,10 +299,31 @@ type volumeDeletingError struct { func (e *volumeDeletingError) Error() string { return e.message } +// VolumeDeletingError is an error +// It returns a message +// Parameters: +// message: the error message +// Return: +// error +// Example: +// err := utils.VolumeDeletingError("volume deleting error") +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func VolumeDeletingError(message string) error { return &volumeDeletingError{message} } +// IsVolumeDeletingError returns true if the error is a volumeDeletingError +// Parameters: +// err: error to check +// Return: +// true if the error is a volumeDeletingError +// Example: +// if IsVolumeDeletingError(err) { +// // do something +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsVolumeDeletingError(err error) bool { if err == nil { return false @@ -187,10 +342,34 @@ type timeoutError struct { func (e *timeoutError) Error() string { return e.message } +// TimeoutError is a custom error +// It returns a string with the error message +// Parameters: +// message - error message +// Returns: +// error - error object +// Example: +// err := utils.TimeoutError("error message") +// if err != nil { +// fmt.Println(err) +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func TimeoutError(message string) error { return &timeoutError{message} } +// IsTimeoutError returns true if the error is a timeout error +// Parameters: +// err: error +// Returns: +// bool +// Example: +// if IsTimeoutError(err) { +// ... +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsTimeoutError(err error) bool { if err == nil { return false @@ -209,12 +388,35 @@ type unsupportedKubernetesVersionError struct { func (e *unsupportedKubernetesVersionError) Error() string { return e.message } +// UnsupportedKubernetesVersionError is an error that is returned when the Kubernetes version is not supported +// It returns a message that includes the original error message +// Parameters: +// err - the original error message +// Returns: +// an error that includes the original error message +// Example: +// err := utils.UnsupportedKubernetesVersionError(errors.New("unsupported Kubernetes version")) +// fmt.Println(err.Error()) +// // Output: unsupported Kubernetes version; unsupported Kubernetes version +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func UnsupportedKubernetesVersionError(err error) error { return &unsupportedKubernetesVersionError{ message: fmt.Sprintf("unsupported Kubernetes version; %s", err.Error()), } } +// IsUnsupportedKubernetesVersionError returns true if the error is an unsupportedKubernetesVersionError +// Parameters: +// err: the error to check +// Returns: +// true if the error is an unsupportedKubernetesVersionError +// Example: +// if utils.IsUnsupportedKubernetesVersionError(err) { +// // error is an unsupportedKubernetesVersionError +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsUnsupportedKubernetesVersionError(err error) bool { if err == nil { return false @@ -233,12 +435,33 @@ type reconcileDeferredError struct { func (e *reconcileDeferredError) Error() string { return e.message } +// ReconcileDeferredError is a special error +// It returns a special error that can be used to defer reconciliation +// Parameters: +// err - error message +// Returns: +// error - error object +// Example: +// err := ReconcileDeferredError(errors.New("deferred")) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func ReconcileDeferredError(err error) error { return &reconcileDeferredError{ message: err.Error(), } } +// IsReconcileDeferredError returns true if the error is a ReconcileDeferredError +// Parameters: +// err - the error to check +// Returns: +// true if the error is a ReconcileDeferredError +// Example: +// if utils.IsReconcileDeferredError(err) { +// // do something +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsReconcileDeferredError(err error) bool { if err == nil { return false @@ -257,18 +480,46 @@ type reconcileIncompleteError struct { func (e *reconcileIncompleteError) Error() string { return e.message } +// ReconcileIncompleteError is an error that indicates that the reconcile is incomplete +// It returns true for IsReconcileIncompleteError +// Returns: +// true +// Example: +// err := ReconcileIncompleteError() +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func ReconcileIncompleteError() error { return &reconcileIncompleteError{ message: "reconcile incomplete", } } +// ConvertToReconcileIncompleteError returns a new error that indicates the reconcile is incomplete +// Parameters: +// err - the original error +// Returns: +// a new error that indicates the reconcile is incomplete +// Example: +// err := errors.New("Incomplete") +// newErr := ConvertToReconcileIncompleteError(err) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func ConvertToReconcileIncompleteError(err error) error { return &reconcileIncompleteError{ message: err.Error(), } } +// IsReconcileIncompleteError returns true if the error is a reconcileIncompleteError +// Parameters: +// err - the error to check +// Returns: +// true if the error is a reconcileIncompleteError, false otherwise +// Example: +// err := errors.New("error") +// IsReconcileIncompleteError(err) // false +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsReconcileIncompleteError(err error) bool { if err == nil { return false @@ -287,12 +538,33 @@ type reconcileFailedError struct { func (e *reconcileFailedError) Error() string { return e.message } +// ReconcileFailedError is an error +// It returns a string with the error message +// Parameters: +// err: the error message +// Returns: +// error: the error +// Example: +// err := utils.ReconcileFailedError(err) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func ReconcileFailedError(err error) error { return &reconcileFailedError{ message: fmt.Sprintf("reconcile failed; %s", err.Error()), } } +// IsReconcileFailedError returns true if the error is a reconcileFailedError +// Parameters: +// err: error to check +// Returns: +// true if the error is a reconcileFailedError +// Example: +// if IsReconcileFailedError(err) { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsReconcileFailedError(err error) bool { if err == nil { return false @@ -311,12 +583,30 @@ type unsupportedConfigError struct { func (e *unsupportedConfigError) Error() string { return e.message } +// UnsupportedConfigError returns an error indicating that the supplied configuration is not supported +// Parameters: +// err - the error that caused the configuration to be unsupported +// Returns: +// error - an error indicating that the supplied configuration is not supported +// Example: +// err := utils.UnsupportedConfigError(fmt.Errorf("unsupported feature")) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func UnsupportedConfigError(err error) error { return &unsupportedConfigError{ message: fmt.Sprintf("unsupported configuration; %s", err.Error()), } } +// IsUnsupportedConfigError returns true if the error is an unsupportedConfigError. +// Parameters: +// err: the error to check +// Returns: +// true if the error is an unsupportedConfigError, false otherwise +// Example: +// IsUnsupportedConfigError(errors.New("unsupported config")) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsUnsupportedConfigError(err error) bool { if err == nil { return false @@ -335,12 +625,35 @@ type tempOperatorError struct { func (e *tempOperatorError) Error() string { return e.message } +// TempOperatorError is a temporary error that should be retried +// It returns a temporary error that should be retried +// Parameters: +// err: the error to wrap +// Returns: +// a temporary error that should be retried +// Example: +// if err := doSomething(); err != nil { +// return utils.TempOperatorError(err) +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func TempOperatorError(err error) error { return &tempOperatorError{ message: fmt.Sprintf("temporary operator error; %s", err.Error()), } } +// IsTempOperatorError returns true if the error is a temporary operator error +// Parameters: +// err - error to check +// Returns: +// true if the error is a temporary operator error +// Example: +// if utils.IsTempOperatorError(err) { +// // handle temporary operator error +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsTempOperatorError(err error) bool { if err == nil { return false @@ -359,10 +672,31 @@ type invalidInputError struct { func (e *invalidInputError) Error() string { return e.message } +// InvalidInputError is a custom error +// It returns a message +// Parameters: +// message: string +// Returns: +// error +// Example: +// err := utils.InvalidInputError("This is an error") +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func InvalidInputError(message string) error { return &invalidInputError{message} } +// IsInvalidInputError returns true if the error is an invalid input error +// Parameters: +// err - the error to check +// Returns: +// true if the error is an invalid input error +// Example: +// if IsInvalidInputError(err) { +// // err was an invalid input error +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsInvalidInputError(err error) bool { if err == nil { return false @@ -384,6 +718,18 @@ func (e *unsupportedCapacityRangeError) Unwrap() error { return e.err } func (e *unsupportedCapacityRangeError) Error() string { return e.message } +// UnsupportedCapacityRangeError is an error that is returned when a capacity +// range is not supported by the storage driver. +// It returns an error with the message: +// "unsupported capacity range; " +// Parameters: +// err - the error message +// Returns: +// an error +// Example: +// err := UnsupportedCapacityRangeError(errors.New("invalid capacity range")) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func UnsupportedCapacityRangeError(err error) error { return &unsupportedCapacityRangeError{ err, fmt.Sprintf("unsupported capacity range; %s", @@ -391,6 +737,16 @@ func UnsupportedCapacityRangeError(err error) error { } } +// HasUnsupportedCapacityRangeError returns true if the error is an unsupportedCapacityRangeError +// Parameters: +// err - the error to check +// Returns: +// bool - true if the error is an unsupportedCapacityRangeError +// *unsupportedCapacityRangeError - the error if it is an unsupportedCapacityRangeError, nil otherwise +// Example: +// _, ok := HasUnsupportedCapacityRangeError(err) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func HasUnsupportedCapacityRangeError(err error) (bool, *unsupportedCapacityRangeError) { if err == nil { return false, nil @@ -410,10 +766,32 @@ type maxLimitReachedError struct { func (e *maxLimitReachedError) Error() string { return e.message } +// MaxLimitReachedError is an error that is returned when the maximum limit for a resource has been reached +// It returns a string message +// Parameters: +// message - the error message +// Returns: +// error - the error +// Example: +// if err := utils.MaxLimitReachedError("Maximum limit of volumes has been reached"); err != nil { +// log.Errorf("Error: %v\n", err) +// return +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func MaxLimitReachedError(message string) error { return &maxLimitReachedError{message} } +// IsMaxLimitReachedError returns true if the error is a maxLimitReachedError +// Parameters: +// err - the error to check +// Returns: +// true if the error is a maxLimitReachedError +// Example: +// result := utils.IsMaxLimitReachedError(err) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsMaxLimitReachedError(err error) bool { if err == nil { return false @@ -430,10 +808,34 @@ type typeAssertionError struct { assertion string } +// Error returned when a +// It returns a string representation of the assertion that failed. +// Returns: +// string representation of the assertion that failed +// Example: +// err := utils.TypeAssertionError{assertion: "slice"} +// fmt.Println(err.Error()) +// Output: +// could not perform assertion: slice +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func (e *typeAssertionError) Error() string { return fmt.Sprintf("could not perform assertion: %s", e.assertion) } +// TypeAssertionError is a +// It returns an error with the given assertion string. +// Parameters: +// assertion: the assertion string +// Returns: +// an error with the given assertion string +// Example: +// err := utils.TypeAssertionError("a.b.c") +// fmt.Printf("%v", err) +// // Output: +// // Type assertion error: a.b.c +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func TypeAssertionError(assertion string) error { return &typeAssertionError{assertion} } @@ -448,10 +850,29 @@ type authError struct { func (e *authError) Error() string { return e.message } +// AuthError is an error that can be returned from the auth package +// It returns a message that can be displayed to the user +// Parameters: +// message (string) - the message to display to the user +// Returns: +// error - an error that can be returned from the auth package +// Example: +// err := auth.AuthError("There was an error authenticating") +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func AuthError(message string) error { return &authError{message} } +// IsAuthError returns true if the error is an auth error +// Parameters: +// err: the error to check +// Returns: +// true if the error is an auth error +// Example: +// IsAuthError(err) +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsAuthError(err error) bool { if err == nil { return false @@ -470,10 +891,31 @@ type tooManyRequestsError struct { func (e *tooManyRequestsError) Error() string { return e.message } +// TooManyRequestsError is an error that indicates that the client has sent too many requests in a given amount of time. +// It returns a 429 status code. +// Parameters: +// message: the error message +// Returns: +// an error +// Example: +// err := utils.TooManyRequestsError("Too many requests") +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func TooManyRequestsError(message string) error { return &tooManyRequestsError{message} } +// IsTooManyRequestsError returns true if the error is a TooManyRequestsError +// Parameters: +// err - the error to check +// Returns: +// true if the error is a TooManyRequestsError, false otherwise +// Example: +// if utils.IsTooManyRequestsError(err) { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 16:29:59.146129 -- func IsTooManyRequestsError(err error) bool { if err == nil { return false diff --git a/utils/errors_test.go b/utils/errors_test.go index 84931bb00..cd989d588 100644 --- a/utils/errors_test.go +++ b/utils/errors_test.go @@ -9,6 +9,13 @@ import ( "github.com/stretchr/testify/assert" ) +// TestUnsupportedCapacityRangeError tests the UnsupportedCapacityRangeError +// function. +// It checks that the function correctly identifies an UnsupportedCapacityRangeError +// and that it correctly identifies an UnsupportedCapacityRangeError within a +// wrapped error. +// +// -- Doc autogenerated on 2022-05-12 14:35:56.524034 -- func TestUnsupportedCapacityRangeError(t *testing.T) { // test setup err := fmt.Errorf("a generic error") diff --git a/utils/k8s_utils.go b/utils/k8s_utils.go index 2ce6d0618..49250e7c3 100644 --- a/utils/k8s_utils.go +++ b/utils/k8s_utils.go @@ -97,6 +97,17 @@ func IsLikelyNotMountPoint(ctx context.Context, mountpoint string) (bool, error) return true, nil } +// GetDeviceNameFromMount returns the device name and reference count for a given mount path. +// Parameters: +// mountpath: The mount path to look up. +// Returns: +// device: The device name. +// refCount: The number of references to the device. +// err: Any error encountered. +// Example: +// device, refCount, err := GetDeviceNameFromMount("/mnt/foo") +// +// -- Doc autogenerated on 2022-05-12 14:36:06.472497 -- func GetDeviceNameFromMount(ctx context.Context, mountpath string) (string, int, error) { fields := log.Fields{"mountpath": mountpath} Logc(ctx).WithFields(fields).Debug(">>>> k8s_utils.GetDeviceNameFromMount") @@ -205,6 +216,16 @@ func parseProcSelfMountinfo(content []byte) ([]MountInfo, error) { return out, nil } +// listProcMounts returns a list of all current mounts on the system. +// Parameters: +// mountFilePath: The path to the file to read (/proc/mounts) +// Returns: +// A slice of MountPoint structs containing information about each mount point +// An error if one occurred +// Example: +// mountPoints, err := listProcMounts("/proc/mounts") +// +// -- Doc autogenerated on 2022-05-12 14:36:06.472497 -- func listProcMounts(mountFilePath string) ([]MountPoint, error) { content, err := ConsistentRead(mountFilePath, maxListTries) if err != nil { @@ -213,6 +234,27 @@ func listProcMounts(mountFilePath string) ([]MountPoint, error) { return parseProcMounts(content) } +// parseProcMounts parses the content of /proc/mounts and returns a slice of MountPoint structs +// See 'man proc' for more details on the file format +// It returns an error if the file content does not have the expected format +// Parameters: +// content: the content of the /proc/mounts file +// Returns: +// a slice of MountPoint structs, or an error if the file content does not have the expected format +// Example: +// content, err := ioutil.ReadFile("/proc/mounts") +// if err != nil { +// return err +// } +// mounts, err := parseProcMounts(content) +// if err != nil { +// return err +// } +// for _, mount := range mounts { +// fmt.Printf("%s %s %s %v %d %d\n", mount.Device, mount.Path, mount.Type, mount.Opts, mount.Freq, mount.Pass) +// } +// +// -- Doc autogenerated on 2022-05-12 14:36:06.472497 -- func parseProcMounts(content []byte) ([]MountPoint, error) { out := make([]MountPoint, 0) lines := strings.Split(string(content), "\n") diff --git a/utils/k8s_utils_test.go b/utils/k8s_utils_test.go index b66596415..dec080bf4 100644 --- a/utils/k8s_utils_test.go +++ b/utils/k8s_utils_test.go @@ -7,6 +7,15 @@ import ( "github.com/stretchr/testify/assert" ) +// TestParseProcSelfMountinfo tests the parseProcSelfMountinfo function +// It checks for the following cases: +// - 10-13 fields +// - one valid one invalid +// - too few fields +// - separator in 5th position +// - no separator +// +// -- Doc autogenerated on 2022-05-12 14:37:23.777213 -- func TestParseProcSelfMountinfo(t *testing.T) { tests := []struct { name string diff --git a/utils/locks_test.go b/utils/locks_test.go index 9269f3b43..59ab66d31 100644 --- a/utils/locks_test.go +++ b/utils/locks_test.go @@ -10,6 +10,10 @@ import ( var ctx = context.Background +// TestLockCreated tests that a lock is created when it is locked. +// It checks that the lock is not created when it is not locked. +// +// -- Doc autogenerated on 2022-05-12 14:37:31.818596 -- func TestLockCreated(t *testing.T) { Lock(ctx(), "testContext", "myLock") defer Unlock(ctx(), "testContext", "myLock") @@ -23,6 +27,10 @@ func TestLockCreated(t *testing.T) { } } +// TestLockReused tests that the same lock is reused +// It checks that the lock is not created twice +// +// -- Doc autogenerated on 2022-05-12 14:37:31.818596 -- func TestLockReused(t *testing.T) { Lock(ctx(), "testContext", "reuseLock") Unlock(ctx(), "testContext", "reuseLock") @@ -39,6 +47,22 @@ func TestLockReused(t *testing.T) { } } +// acquire1 acquires a lock and then releases it +// Parameters: +// m1 - channel for commands +// r - channel for results +// Returns: +// none +// Example: +// m1 := make(chan string, 3) +// r := make(chan string) +// go acquire1(m1, r) +// m1 <- "lock" +// m1 <- "unlock" +// m1 <- "done" +// <-r +// +// -- Doc autogenerated on 2022-05-12 14:37:31.818596 -- func acquire1(m1, r chan string) { for i := 0; i < 3; i++ { op := <-m1 @@ -55,6 +79,27 @@ func acquire1(m1, r chan string) { } } +// acquire2 is a helper function for testing the behavior of the lock manager. +// It acquires a lock, then releases it, then acquires it again. +// Parameters: +// m2: a channel for receiving commands from the test +// r: a channel for sending a response to the test +// Returns: +// nothing +// Example: +// r := make(chan string) +// m2 := make(chan string) +// go acquire2(m2, r) +// m2 <- "lock" +// <-r +// m2 <- "unlock" +// <-r +// m2 <- "lock" +// <-r +// m2 <- "done" +// <-r +// +// -- Doc autogenerated on 2022-05-12 14:37:31.818596 -- func acquire2(m2, r chan string) { for i := 0; i < 3; i++ { op := <-m2 @@ -71,10 +116,26 @@ func acquire2(m2, r chan string) { } } +// snooze is a no-op function that sleeps for 1 millisecond. +// It is used to prevent the scheduler from spinning too fast. +// Returns: +// None +// Example: +// snooze() +// +// -- Doc autogenerated on 2022-05-12 14:37:31.818596 -- func snooze() { time.Sleep(1 * time.Millisecond) } +// TestLockBehavior tests the behavior of the Lock and Unlock methods. +// It is not a unit test, but rather a functional test. +// It checks that the lock is acquired by the first caller and that +// the second caller blocks until the first caller releases the lock. +// It also checks that the second caller can acquire the lock after +// the first caller releases it. +// +// -- Doc autogenerated on 2022-05-12 14:37:31.818596 -- func TestLockBehavior(t *testing.T) { r := make(chan string, 2) m1 := make(chan string, 3) diff --git a/utils/osutils.go b/utils/osutils.go index 47eb0da67..4d4759f1b 100644 --- a/utils/osutils.go +++ b/utils/osutils.go @@ -54,6 +54,15 @@ var ( chrootPathPrefix string ) +// IPv6Check returns true if the IP is IPv6 +// Parameters: +// ip - IP address +// Returns: +// true if the IP is IPv6 +// Example: +// IPv6Check("fe80::f816:3eff:fe20:57c3") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func IPv6Check(ip string) bool { return strings.Count(ip, ":") >= 2 } @@ -66,6 +75,15 @@ func init() { } } +// SetChrootPathPrefix sets the chroot path prefix +// Parameters: +// prefix - the chroot path prefix +// Returns: +// none +// Example: +// SetChrootPathPrefix("/var/lib/trident") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func SetChrootPathPrefix(prefix string) { Logc(context.Background()).Debugf("SetChrootPathPrefix = '%s'", prefix) chrootPathPrefix = prefix @@ -73,6 +91,22 @@ func SetChrootPathPrefix(prefix string) { // Attach the volume to the local host. This method must be able to accomplish its task using only the data passed in. // It may be assumed that this method always runs on the host to which the volume will be attached. +// AttachNFSVolume publishes an NFS volume to the host +// It returns an error if the volume could not be published. +// Parameters: +// name: the volume name +// mountpoint: the directory where the volume will be mounted +// publishInfo: the volume publish information +// Returns: +// error: nil if successful, or an error if the volume could not be published +// Example: +// err := utils.AttachNFSVolume(ctx, "vol1", "/mnt/vol1", &utils.VolumePublishInfo{ +// NfsServerIP: "10.63.0.1", +// NfsPath: "/nfsvol1", +// MountOptions: "rw", +// }) +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func AttachNFSVolume(ctx context.Context, name, mountpoint string, publishInfo *VolumePublishInfo) error { Logc(ctx).Debug(">>>> osutils.AttachNFSVolume") defer Logc(ctx).Debug("<<<< osutils.AttachNFSVolume") @@ -90,6 +124,23 @@ func AttachNFSVolume(ctx context.Context, name, mountpoint string, publishInfo * return mountNFSPath(ctx, exportPath, mountpoint, options) } +// AttachBlockOnFileVolume attaches a block-on-file volume to the host. +// +// If a mountPath is specified, the device will be mounted at mountPath/volumeMountDir. +// If a mountPath is not specified, the device will not be mounted. +// It returns the device name and the mountpoint. +// Parameters: +// ctx - context +// mountPath - the path to mount the device +// publishInfo - the volume publish information +// Returns: +// deviceName - the device name +// deviceMountpoint - the device mountpoint +// err - error if any +// Example: +// deviceName, deviceMountpoint, err := AttachBlockOnFileVolume(ctx, "", &VolumePublishInfo{...}) +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func AttachBlockOnFileVolume( ctx context.Context, mountPath string, publishInfo *VolumePublishInfo, ) (string, string, error) { @@ -205,6 +256,18 @@ func AttachBlockOnFileVolume( return loopDevice.Name, deviceMountpoint, nil } +// DetachBlockOnFileVolume detaches a loop device from a file +// It returns an error if the loop device is not attached to the file +// Parameters: +// ctx - the context +// loopDevice - the loop device to detach +// loopFile - the file to detach from +// Returns: +// error - any error encountered +// Example: +// err := DetachBlockOnFileVolume(ctx, "/dev/loop0", "/var/lib/trident/block-volumes/test-volume") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func DetachBlockOnFileVolume(ctx context.Context, loopDevice, loopFile string) error { Logc(ctx).Debug(">>>> osutils.DetachBlockOnFileVolume") defer Logc(ctx).Debug("<<<< osutils.DetachBlockOnFileVolume") @@ -414,6 +477,19 @@ func AttachISCSIVolume(ctx context.Context, name, mountpoint string, publishInfo return nil } +// logInToPortals logs in to the specified portals using CHAP. +// It returns true if it was able to log in to at least one portal. +// Parameters: +// ctx - context +// bkPortalsToLogin - list of portals to login to +// publishInfo - volume publish information +// loggedIn - true if already logged in to at least one portal +// Returns: +// loggedIn - true if logged in to at least one portal +// Example: +// loggedIn := logInToPortals(ctx, bkPortalsToLogin, publishInfo, loggedIn) +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func logInToPortals( ctx context.Context, bkPortalsToLogin []string, publishInfo *VolumePublishInfo, loggedIn bool, ) bool { @@ -1524,7 +1600,22 @@ func ExpandFilesystemOnNode( return size, nil } +// expandFilesystem expands the filesystem on the given mount point +// It returns the new size of the filesystem +// Parameters: +// ctx: context +// cmd: command to execute +// cmdArguments: arguments to the command +// tmpMountPoint: mount point of the filesystem to expand +// Returns: +// int64: size of the filesystem after expansion +// error: any error encountered +// Example: +// newSize, err := osutils.expandFilesystem(ctx, "resize2fs", "/dev/sdb1", "/tmp/foo") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func expandFilesystem(ctx context.Context, cmd, cmdArguments, tmpMountPoint string) (int64, error) { + logFields := log.Fields{ "cmd": cmd, "cmdArguments": cmdArguments, @@ -1707,6 +1798,19 @@ func formatPortal(portal string) string { } } +// ISCSIRescanDevices rescan iSCSI devices +// It returns an error if the device is not large enough after rescanning +// Parameters: +// ctx: context +// targetIQN: the IQN of the iSCSI target +// lunID: the LUN ID of the iSCSI target +// minSize: the minimum size of the iSCSI device +// Returns: +// error: nil if no error occurred +// Example: +// err := ISCSIRescanDevices(ctx, "iqn.2010-10.org.openstack:volume-ebd8e5f7-e0e3-4f9b-8c1d-e1a5d20f5d2f", 0, 10737418240) +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func ISCSIRescanDevices(ctx context.Context, targetIQN string, lunID int32, minSize int64) error { fields := log.Fields{"targetIQN": targetIQN, "lunID": lunID} Logc(ctx).WithFields(fields).Debug(">>>> osutils.ISCSIRescanDevices") @@ -1783,6 +1887,17 @@ func ISCSIRescanDevices(ctx context.Context, targetIQN string, lunID int32, minS return nil } +// reloadMultipathDevice reloads a multipath device. +// It returns an error if the reload fails. +// Parameters: +// ctx - context for logging +// multipathDevice - the multipath device to reload +// Returns: +// error - error if the reload fails +// Example: +// err := reloadMultipathDevice(ctx, "3600a098038303837b000000000000001") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func reloadMultipathDevice(ctx context.Context, multipathDevice string) error { fields := log.Fields{"multipathDevice": multipathDevice} Logc(ctx).WithFields(fields).Debug(">>>> osutils.reloadMultipathDevice") @@ -2275,6 +2390,26 @@ func GetISCSIDevices(ctx context.Context) ([]*ScsiDeviceInfo, error) { return devices, nil } +// IsNFSShareMounted checks if the given NFS export is mounted at the given mountpoint +// It returns true if the export is mounted at the given mountpoint +// Parameters: +// exportPath: the NFS export to check +// mountpoint: the mountpoint to check +// Returns: +// bool: true if the export is mounted at the given mountpoint +// error: any error encountered +// Example: +// mounted, err := IsNFSShareMounted(ctx, "server:/vol/vol1", "/mnt/vol1") +// if err != nil { +// log.Fatal(err) +// } +// if mounted { +// log.Printf("NFS Share is mounted.") +// } else { +// log.Printf("NFS Share is not mounted.") +// } +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func IsNFSShareMounted(ctx context.Context, exportPath, mountpoint string) (bool, error) { fields := log.Fields{ "exportPath": exportPath, @@ -3001,6 +3136,20 @@ func getTargets(ctx context.Context, tp string) ([]string, error) { return filterTargets(string(output), tp), nil } +// updateDiscoveryDb updates the discovery database with the given key and value +// It returns an error if the discovery database could not be updated +// Parameters: +// ctx - context +// tp - portal +// iface - interface +// key - key +// value - value +// Returns: +// error - error if the discovery database could not be updated +// Example: +// err := updateDiscoveryDb(ctx, "192.168.0.1:3260", "default", "iface.iscsi_ifacename", "eth0") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func updateDiscoveryDb(ctx context.Context, tp, iface, key, value string) error { Logc(ctx).WithFields(log.Fields{ "Key": key, @@ -3144,6 +3293,16 @@ type LoopDevice struct { BackFile string `json:"back-file"` } +// getLoopDeviceInfo returns a list of loop devices +// Parameters: +// ctx: The context for the request +// Returns: +// []LoopDevice: A list of loop devices +// error: Any error encountered +// Example: +// loopDevices, err := getLoopDeviceInfo() +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func getLoopDeviceInfo(ctx context.Context) ([]LoopDevice, error) { Logc(ctx).Debug(">>>> osutils.getLoopDeviceInfo") defer Logc(ctx).Debug("<<<< osutils.getLoopDeviceInfo") @@ -3167,6 +3326,26 @@ func getLoopDeviceInfo(ctx context.Context) ([]LoopDevice, error) { return loopDevicesResponse.LoopDevices, nil } +// GetLoopDeviceAttachedToFile returns the loop device attached to the specified file +// Parameters: +// ctx - context +// loopFile - path to the loop file +// Returns: +// bool - true if the loop device is attached to the specified file +// *LoopDevice - the loop device +// error - any error encountered +// Example: +// attached, device, err := GetLoopDeviceAttachedToFile(ctx, "/dev/loop0") +// if err != nil { +// return err +// } +// if attached { +// fmt.Printf("Loop device %s is attached to file %s\n", device.Name, device.BackFile) +// } else { +// fmt.Printf("No loop device is attached to file %s\n", loopFile) +// } +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func GetLoopDeviceAttachedToFile(ctx context.Context, loopFile string) (bool, *LoopDevice, error) { Logc(ctx).WithField("loopFile", loopFile).Debug(">>>> osutils.GetLoopDeviceAttachedToFile") defer Logc(ctx).Debug("<<<< osutils.GetLoopDeviceAttachedToFile") @@ -3193,6 +3372,19 @@ func GetLoopDeviceAttachedToFile(ctx context.Context, loopFile string) (bool, *L return false, nil, nil } +// GetAllLoopDeviceBackFiles returns a list of all loop device back-files +// Parameters: +// ctx - logging context +// Returns: +// []string - list of all loop device back-files +// error - any error encountered +// Example: +// deviceBackFiles, err := utils.GetAllLoopDeviceBackFiles(ctx) +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func GetAllLoopDeviceBackFiles(ctx context.Context) ([]string, error) { Logc(ctx).Debug(">>>> osutils.GetAllLoopDeviceBackFiles") defer Logc(ctx).Debug("<<<< osutils.GetAllLoopDeviceBackFiles") @@ -3214,6 +3406,31 @@ func GetAllLoopDeviceBackFiles(ctx context.Context) ([]string, error) { return deviceBackFiles, nil } +// IsLoopDeviceAttachedToFile checks if a loop device is attached to a file +// It returns true if the loop device is attached to the file +// Parameters: +// ctx: context.Context object +// loopDevice: loop device name +// loopFile: file name +// Returns: +// bool: true if the loop device is attached to the file +// error: error object if an error occurred +// Example: +// loopDevices, err := osutils.GetLoopDeviceInfo(ctx) +// if err != nil { +// return err +// } +// for _, loopDevice := range loopDevices { +// isAttached, err := osutils.IsLoopDeviceAttachedToFile(ctx, loopDevice.Name, loopFile) +// if err != nil { +// return err +// } +// if isAttached { +// return true +// } +// } +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func IsLoopDeviceAttachedToFile(ctx context.Context, loopDevice, loopFile string) (bool, error) { Logc(ctx).WithFields(log.Fields{ "loopFile": loopFile, @@ -3243,6 +3460,22 @@ func IsLoopDeviceAttachedToFile(ctx context.Context, loopDevice, loopFile string return false, nil } +// ResizeLoopDevice resizes the loop device to the required size +// It returns an error if the loop device is not resized to the required size +// Parameters: +// ctx: context.Context object +// loopDevice: the loop device to resize +// loopFile: the loop file to resize +// requiredBytes: the required size in bytes +// Returns: +// error: nil if successful, error if not +// Example: +// err := ResizeLoopDevice(ctx, "/dev/loop0", "/tmp/iscsi-test.img", 10737418240) +// if err != nil { +// fmt.Println("Failed to resize loop device") +// } +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func ResizeLoopDevice(ctx context.Context, loopDevice, loopFile string, requiredBytes int64) error { Logc(ctx).WithFields(log.Fields{ "loopFile": loopFile, @@ -3491,6 +3724,20 @@ func SafeToRemoveNFSMount(ctx context.Context, nfsMountPoint string) bool { } // loginISCSITarget logs in to an iSCSI target. +// configureISCSITarget configures the iSCSI target with the specified name and value +// It returns an error if the command fails +// Parameters: +// ctx - context for logging +// iqn - IQN of the target +// portal - portal of the target +// name - name of the target configuration +// value - value of the target configuration +// Returns: +// error - error if the command fails +// Example: +// err := configureISCSITarget(ctx, iqn, portal, "node.conn[0].startup", "automatic") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func configureISCSITarget(ctx context.Context, iqn, portal, name, value string) error { Logc(ctx).WithFields(log.Fields{ "IQN": iqn, @@ -3604,6 +3851,19 @@ func loginWithChap( return nil } +// EnsureISCSISessions ensures that the iSCSI target is logged in to all portals +// It returns true if a session was established with at least one portal +// Parameters: +// targetIQN: the IQN of the iSCSI target +// portalsIps: the IP addresses of the iSCSI portals +// iface: the interface to use for iSCSI +// Returns: +// bool: true if a session was established with at least one portal +// Example: +// EnsureISCSISessions(ctx, "iqn.2003-01.org.linux-iscsi.target1", []string{"192.168.1.10", "192.168.1.11"}, "eth0") +// EnsureISCSISessions(ctx, "iqn.2003-01.org.linux-iscsi.target1", []string{"192.168.1.10", "192.168.1.11"}, "") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func EnsureISCSISessions(ctx context.Context, targetIQN, iface string, portalsIps []string) bool { logFields := log.Fields{ "targetIQN": targetIQN, @@ -3685,6 +3945,19 @@ func EnsureISCSISessions(ctx context.Context, targetIQN, iface string, portalsIp return successfulLogin } +// EnsureISCSISessionsWithPortalDiscovery ensures that all the hostDataIPs have an iSCSI session +// with the portal discovery +// It returns an error if any of the hostDataIPs fail to have an iSCSI session +// Parameters: +// hostDataIPs: list of host data IPs +// Returns: +// error: nil if all the hostDataIPs have an iSCSI session with the portal discovery +// Example: +// if err := utils.EnsureISCSISessionsWithPortalDiscovery(ctx, []string{"10.63.11.1", "10.63.11.2"}); nil != err { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func EnsureISCSISessionsWithPortalDiscovery(ctx context.Context, hostDataIPs []string) error { for _, ip := range hostDataIPs { if err := EnsureISCSISessionWithPortalDiscovery(ctx, ip); nil != err { @@ -3694,6 +3967,18 @@ func EnsureISCSISessionsWithPortalDiscovery(ctx context.Context, hostDataIPs []s return nil } +// EnsureISCSISessionWithPortalDiscovery ensures that an iSCSI session exists for the specified portal +// If no session exists, it will run discovery and log in to the target +// It returns an error if the session could not be established +// Parameters: +// ctx - context +// hostDataIP - IP address of the iSCSI portal +// Returns: +// error - error if session could not be established +// Example: +// err := utils.EnsureISCSISessionWithPortalDiscovery(ctx, "192.168.1.2") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func EnsureISCSISessionWithPortalDiscovery(ctx context.Context, hostDataIP string) error { Logc(ctx).WithField("hostDataIP", hostDataIP).Debug(">>>> osutils.EnsureISCSISessionWithPortalDiscovery") defer Logc(ctx).Debug("<<<< osutils.EnsureISCSISessionWithPortalDiscovery") @@ -3774,6 +4059,21 @@ func EnsureISCSISessionWithPortalDiscovery(ctx context.Context, hostDataIP strin } // execIscsiadmCommand uses the 'iscsiadm' command to perform operations without logging specified secrets +// execIscsiadmCommandRedacted executes an iscsiadm command with the provided args, +// and redacts any secrets in the output. +// It returns the output of the command and any error encountered. +// Parameters: +// ctx: context for the command +// args: arguments to the command +// secretsToRedact: map of secrets to redact from the output +// Returns: +// output of the command +// error encountered +// Example: +// output, err := execIscsiadmCommandRedacted(ctx, []string{"-m", "session", "-P", "3"}, +// map[string]string{"password": "secret"}) +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func execIscsiadmCommandRedacted(ctx context.Context, args []string, secretsToRedact map[string]string) ([]byte, error) { return execCommandRedacted(ctx, "iscsiadm", args, secretsToRedact) } @@ -3807,6 +4107,21 @@ func execCommand(ctx context.Context, name string, args ...string) ([]byte, erro } // execCommand invokes an external process, and redacts sensitive arguments +// execCommandRedacted executes a command and returns the output. +// It also redacts any secrets passed in the args. +// It returns the output and error. +// Parameters: +// ctx - context +// name - name of the command to execute +// args - arguments to the command +// secretsToRedact - map of secrets to redact +// Returns: +// []byte - output of the command +// error - error +// Example: +// output, err := execCommandRedacted(ctx, "ls", []string{"-l"}, nil) +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func execCommandRedacted(ctx context.Context, name string, args []string, secretsToRedact map[string]string, ) ([]byte, error) { @@ -3845,6 +4160,22 @@ type execCommandResult struct { } // execCommand invokes an external shell command +// execCommandWithTimeout executes a command with a timeout. +// If the command times out, the process is killed and an error is returned. +// It returns the output of the command and an error. +// Parameters: +// ctx: context +// name: command name +// timeoutSeconds: timeout in seconds +// logOutput: whether to log the output +// args: command arguments +// Returns: +// output: command output +// error: error +// Example: +// out, err := execCommandWithTimeout(ctx, "ls", 10, true, "-l", "/tmp") +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func execCommandWithTimeout( ctx context.Context, name string, timeoutSeconds time.Duration, logOutput bool, args ...string, ) ([]byte, error) { @@ -3899,6 +4230,18 @@ func execCommandWithTimeout( return result.Output, result.Error } +// sanitizeString removes xterm control characters and trailing newlines +// It returns a sanitized string +// Parameters: +// s: string to sanitize +// Returns: +// sanitized string +// Example: +// s := "this is a string\n" +// sanitizeString(s) +// // returns "this is a string" +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func sanitizeString(s string) string { // Strip xterm color & movement characters s = xtermControlRegex.ReplaceAllString(s, "") @@ -3942,6 +4285,15 @@ func SafeToLogOut(ctx context.Context, hostNumber, sessionNumber int) bool { } // In the case of a iscsi trace debug, log info about session and what devices are present +// listAllISCSIDevices lists all iSCSI devices +// Parameters: +// ctx - context +// Returns: +// none +// Example: +// listAllISCSIDevices(ctx) +// +// -- Doc autogenerated on 2022-05-12 14:39:06.443870 -- func listAllISCSIDevices(ctx context.Context) { if !Logc(ctx).Logger.IsLevelEnabled(log.TraceLevel) { // Don't even run the commands if trace logging is not enabled diff --git a/utils/osutils_darwin.go b/utils/osutils_darwin.go index 98491a0c6..6eead1548 100644 --- a/utils/osutils_darwin.go +++ b/utils/osutils_darwin.go @@ -14,36 +14,108 @@ import ( // At compile time golang will type checks the entire code base. Since the CLI is part // of the Trident code base this file exists to handle darwin specific code. +// getIPAddresses returns the IP addresses of the host. +// Parameters: +// ctx - context +// Returns: +// []net.Addr - the IP addresses of the host +// error - error if any +// Example: +// []net.Addr, err := utils.getIPAddresses(ctx) +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func getIPAddresses(ctx context.Context) ([]net.Addr, error) { Logc(ctx).Debug(">>>> osutils_darwin.getIPAddresses") defer Logc(ctx).Debug("<<<< osutils_darwin.getIPAddresses") return nil, errors.New("getIPAddresses is not supported for darwin") } +// getFilesystemSize returns the size of the filesystem containing the given path. +// Parameters: +// path - path to a file or directory +// Returns: +// size of the filesystem in bytes +// error - nil if successful +// Example: +// size, err := getFilesystemSize("/tmp") +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func getFilesystemSize(ctx context.Context, _ string) (int64, error) { Logc(ctx).Debug(">>>> osutils_darwin.getFilesystemSize") defer Logc(ctx).Debug("<<<< osutils_darwin.getFilesystemSize") return 0, errors.New("getFilesystemSize is not supported for darwin") } +// GetFilesystemStats returns the filesystem stats for the given path +// Parameters: +// ctx - context for logging +// path - the path to get the stats for +// Returns: +// total - total size of the filesystem +// free - free space on the filesystem +// avail - available space on the filesystem +// files - number of files on the filesystem +// ffree - number of free files on the filesystem +// fsid - filesystem id +// err - any error encountered +// Example: +// total, free, avail, files, ffree, fsid, err := GetFilesystemStats(ctx, "/") +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func GetFilesystemStats(ctx context.Context, _ string) (int64, int64, int64, int64, int64, int64, error) { Logc(ctx).Debug(">>>> osutils_darwin.GetFilesystemStats") defer Logc(ctx).Debug("<<<< osutils_darwin.GetFilesystemStats") return 0, 0, 0, 0, 0, 0, errors.New("GetFilesystemStats is not supported for darwin") } +// getISCSIDiskSize returns the size of the iSCSI disk +// Parameters: +// ctx - context for logging +// device - the device name +// Returns: +// size - the size of the iSCSI disk +// err - any error encountered +// Example: +// size, err := getISCSIDiskSize(context.Background(), "/dev/disk2") +// if err != nil { +// return err +// } +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func getISCSIDiskSize(ctx context.Context, _ string) (int64, error) { Logc(ctx).Debug(">>>> osutils_darwin.getISCSIDiskSize") defer Logc(ctx).Debug("<<<< osutils_darwin.getISCSIDiskSize") return 0, errors.New("getBlockSize is not supported for darwin") } +// flushOneDevice is not supported for darwin +// It returns an error +// Parameters: +// ctx - logging context +// devicePath - the device to flush +// Returns: +// error - any error encountered +// Example: +// err := flushOneDevice(ctx, devicePath) +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func flushOneDevice(ctx context.Context, devicePath string) error { Logc(ctx).Debug(">>>> osutils_darwin.flushOneDevice") defer Logc(ctx).Debug("<<<< osutils_darwin.flushOneDevice") return errors.New("flushOneDevice is not supported for darwin") } +// GetHostSystemInfo is not supported for darwin +// It returns an error +// Parameters: +// ctx - logging context +// Returns: +// *HostSystem - host system information +// error - error object if any +// Example: +// hs, err := GetHostSystemInfo(ctx) +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func GetHostSystemInfo(ctx context.Context) (*HostSystem, error) { Logc(ctx).Debug(">>>> osutils_darwin.GetHostSystemInfo") defer Logc(ctx).Debug("<<<< osutils_darwin.GetHostSystemInfo") @@ -51,6 +123,17 @@ func GetHostSystemInfo(ctx context.Context) (*HostSystem, error) { return nil, UnsupportedError(msg) } +// PrepareNFSPackagesOnHost is not is not supported for darwin +// It returns an UnsupportedError +// Parameters: +// ctx - context for logging +// host - host system +// Returns: +// error - error if any +// Example: +// err := osutils_darwin.PrepareNFSPackagesOnHost(ctx, host) +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func PrepareNFSPackagesOnHost(ctx context.Context, host HostSystem) error { Logc(ctx).Debug(">>>> osutils_darwin.PrepareNFSPackagesOnHost") defer Logc(ctx).Debug("<<<< osutils_darwin.PrepareNFSPackagesOnHost") @@ -58,6 +141,16 @@ func PrepareNFSPackagesOnHost(ctx context.Context, host HostSystem) error { return UnsupportedError(msg) } +// PrepareNFSServicesOnHost is not supported for darwin +// It returns an UnsupportedError +// Parameters: +// ctx - context for logging +// Returns: +// error - an error if one occurred +// Example: +// err := utils.PrepareNFSServicesOnHost(ctx) +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func PrepareNFSServicesOnHost(ctx context.Context) error { Logc(ctx).Debug(">>>> osutils_darwin.PrepareNFSServicesOnHost") defer Logc(ctx).Debug("<<<< osutils_darwin.PrepareNFSServicesOnHost") @@ -65,6 +158,18 @@ func PrepareNFSServicesOnHost(ctx context.Context) error { return UnsupportedError(msg) } +// ServiceActiveOnHost checks if a service is active on the host +// It returns true if the service is active, false if not, and an error if there was a problem +// Parameters: +// ctx - context for logging +// service - the service to check +// Returns: +// bool - true if the service is active, false if not +// error - an error if there was a problem +// Example: +// active, err := utils.ServiceActiveOnHost(ctx, "iscsi") +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func ServiceActiveOnHost(ctx context.Context, service string) (bool, error) { Logc(ctx).Debug(">>>> osutils_darwin.ServiceActiveOnHost") defer Logc(ctx).Debug("<<<< osutils_darwin.ServiceActiveOnHost") @@ -72,6 +177,18 @@ func ServiceActiveOnHost(ctx context.Context, service string) (bool, error) { return false, UnsupportedError(msg) } +// ServiceEnabledOnHost checks if a service is enabled on the host +// It returns true if the service is enabled, false if not, and an error +// Parameters: +// ctx - context for logging +// service - the service to check +// Returns: +// bool - true if the service is enabled, false if not +// error - any error encountered +// Example: +// enabled, err := ServiceEnabledOnHost(ctx, "glusterd") +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func ServiceEnabledOnHost(ctx context.Context, service string) (bool, error) { Logc(ctx).Debug(">>>> osutils_darwin.ServiceEnabledOnHost") defer Logc(ctx).Debug("<<<< osutils_darwin.ServiceEnabledOnHost") @@ -79,6 +196,16 @@ func ServiceEnabledOnHost(ctx context.Context, service string) (bool, error) { return false, UnsupportedError(msg) } +// ISCSIActiveOnHost returns true if iSCSI is active on the host +// Parameters: +// host - host system +// Returns: +// bool - true if iSCSI is active on the host +// error - any error encountered +// Example: +// isActive, err := ISCSIActiveOnHost(host) +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func ISCSIActiveOnHost(ctx context.Context, host HostSystem) (bool, error) { Logc(ctx).Debug(">>>> osutils_darwin.ISCSIActiveOnHost") defer Logc(ctx).Debug("<<<< osutils_darwin.ISCSIActiveOnHost") @@ -86,6 +213,18 @@ func ISCSIActiveOnHost(ctx context.Context, host HostSystem) (bool, error) { return false, UnsupportedError(msg) } +// PrepareISCSIPackagesOnHost is not supported on darwin +// It returns an UnsupportedError +// Parameters: +// ctx - context for logging +// host - host system +// iscsiPreconfigured - true if the host is already configured for iSCSI +// Returns: +// error - an error if one occurred +// Example: +// err := PrepareISCSIPackagesOnHost(ctx, host, iscsiPreconfigured) +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func PrepareISCSIPackagesOnHost(ctx context.Context, host HostSystem, iscsiPreconfigured bool) error { Logc(ctx).Debug(">>>> osutils_darwin.PrepareISCSIPackagesOnHost") defer Logc(ctx).Debug("<<<< osutils_darwin.PrepareISCSIPackagesOnHost") @@ -93,6 +232,20 @@ func PrepareISCSIPackagesOnHost(ctx context.Context, host HostSystem, iscsiPreco return UnsupportedError(msg) } +// PrepareISCSIServicesOnHost is not supported for darwin +// It returns an UnsupportedError +// Parameters: +// ctx - context for logging +// host - the host to prepare +// Returns: +// error - an error if one occurred, otherwise nil +// Example: +// err := PrepareISCSIServicesOnHost(ctx, host) +// if err != nil { +// // Handle error +// } +// +// -- Doc autogenerated on 2022-05-12 14:49:46.905128 -- func PrepareISCSIServicesOnHost(ctx context.Context, host HostSystem) error { Logc(ctx).Debug(">>>> osutils_darwin.PrepareISCSIServicesOnHost") defer Logc(ctx).Debug("<<<< osutils_darwin.PrepareISCSIServicesOnHost") diff --git a/utils/osutils_linux.go b/utils/osutils_linux.go index adb0b3d14..19c13eeec 100644 --- a/utils/osutils_linux.go +++ b/utils/osutils_linux.go @@ -31,6 +31,22 @@ type statFSResult struct { // getFilesystemSize returns the size of the filesystem for the given path. // The caller of the func is responsible for verifying the mountPoint existence and readiness. +// GetFilesystemStats returns the filesystem stats for the given path. +// The returned values are in bytes. +// Parameters: +// path: the path to get filesystem stats for +// Returns: +// available: the number of bytes available on the filesystem +// capacity: the total number of bytes on the filesystem +// usage: the number of bytes used on the filesystem +// inodes: the total number of inodes on the filesystem +// inodesFree: the number of free inodes on the filesystem +// inodesUsed: the number of used inodes on the filesystem +// err: an error if one occurred +// Example: +// available, capacity, usage, inodes, inodesFree, inodesUsed, err := utils.GetFilesystemStats("/") +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func GetFilesystemStats( ctx context.Context, path string, ) (available, capacity, usage, inodes, inodesFree, inodesUsed int64, err error) { @@ -146,6 +162,17 @@ func flushOneDevice(ctx context.Context, devicePath string) error { return nil } +// determineNFSPackages returns the list of packages to install for NFS support based on the host's OS. +// Parameters: +// ctx - context +// host - host system +// Returns: +// list of packages to install for NFS support +// error - error if any +// Example: +// packages, err := determineNFSPackages(ctx, host) +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func determineNFSPackages(ctx context.Context, host HostSystem) ([]string, error) { var packages []string @@ -168,6 +195,18 @@ func determineNFSPackages(ctx context.Context, host HostSystem) ([]string, error return packages, nil } +// determineISCSIPackages returns a list of packages to install for the given host +// If iscsiPreconfigured is true, then iscsi and multipath packages are not included +// Parameters: +// host: host system +// iscsiPreconfigured: true if iscsi is already configured +// Return: +// list of packages to install +// error: error if any +// Example: +// packages, err := determineISCSIPackages(host, false) +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func determineISCSIPackages(ctx context.Context, host HostSystem, iscsiPreconfigured bool) ([]string, error) { packages := make([]string, 0) @@ -193,6 +232,18 @@ func determineISCSIPackages(ctx context.Context, host HostSystem, iscsiPreconfig return packages, nil } +// PrepareNFSPackagesOnHost installs NFS packages on the host +// It returns an error if the packages could not be installed +// Parameters: +// ctx - context for logging +// host - host to install NFS packages on +// Returns: +// error - error if the packages could not be installed +// Example: +// ctx := context.Background() +// err := PrepareNFSPackagesOnHost(ctx, host) +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func PrepareNFSPackagesOnHost(ctx context.Context, host HostSystem) error { Logc(ctx).Debug(">>>> osutils_linux.PrepareNFSPackagesOnHost") defer Logc(ctx).Debug("<<<< osutils_linux.PrepareNFSPackagesOnHost") @@ -241,6 +292,19 @@ func installMissingPackagesOnHost(ctx context.Context, packages []string, host H return nil } +// checkPackagesOnHost checks if the packages are installed on the host +// Parameters: +// ctx - context for logging +// packages - list of packages to check +// host - host to check +// Returns: +// list of packages not installed on the host +// error +// Example: +// notInstalled, err := checkPackagesOnHost(ctx, []string{"python", "python-pip"}, host) +// +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func checkPackagesOnHost(ctx context.Context, packages []string, host HostSystem) (notInstalled []string, err error) { for _, pkg := range packages { found, err2 := packageInstalledOnHost(ctx, pkg, host) @@ -256,6 +320,17 @@ func checkPackagesOnHost(ctx context.Context, packages []string, host HostSystem return } +// packageInstalledOnHost checks if a +// It returns true if the +// Parameters: +// ctx - context +// pkg - +// Returns: +// bool - true if the +// Example: +// installed, err := packageInstalledOnHost(ctx, "vim", host) +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func packageInstalledOnHost(ctx context.Context, pkg string, host HostSystem) (bool, error) { // Determine command to use cmd, err := getPackageManagerForHost(ctx, host) @@ -322,6 +397,15 @@ func packageInstalledOnHost(ctx context.Context, pkg string, host HostSystem) (b return true, nil } +// getPackageManagerForHost returns the +// Parameters: +// host - host system +// Returns: +// string - +// Example: +// packageManager, err := getPackageManagerForHost(host) +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func getPackageManagerForHost(ctx context.Context, host HostSystem) (string, error) { switch host.OS.Distro { case Centos, RHEL: @@ -345,6 +429,18 @@ func getPackageManagerForHost(ctx context.Context, host HostSystem) (string, err } } +// installPackagesOnHost installs the specified packages on the specified host. +// It returns an error if any of the packages fail to install. +// Parameters: +// ctx - context for logging +// packages - list of packages to install +// host - host to install packages on +// Returns: +// error - error if any of the packages fail to install +// Example: +// err := installPackagesOnHost(ctx, []string{"package1", "package2"}, host) +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func installPackagesOnHost(ctx context.Context, packages []string, host HostSystem) error { if len(packages) == 0 { Logc(ctx).Debug("No packages to install.") @@ -405,6 +501,19 @@ func installPackagesOnHost(ctx context.Context, packages []string, host HostSyst return nil } +// PrepareNFSServicesOnHost prepares the NFS services on the host +// It returns an error if any of the services fail to start +// Parameters: +// ctx - context for logging +// Returns: +// error - any error encountered +// Example: +// err := PrepareNFSServicesOnHost(ctx) +// if err != nil { +// // handle error +// } +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func PrepareNFSServicesOnHost(ctx context.Context) error { Logc(ctx).Debug(">>>> osutils_linux.PrepareNFSServicesOnHost") defer Logc(ctx).Debug("<<<< osutils_linux.PrepareNFSServicesOnHost") @@ -431,6 +540,16 @@ func PrepareNFSServicesOnHost(ctx context.Context) error { return nil } +// determineISCSIServices returns the list of ISCSI services for the given host +// Parameters: +// host - host system +// Returns: +// list of ISCSI services +// error - error if any +// Example: +// services, err := utils.determineISCSIServices(host) +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func determineISCSIServices(host HostSystem) ([]string, error) { services := make([]string, 0) @@ -478,6 +597,19 @@ func PrepareISCSIServicesOnHost(ctx context.Context, host HostSystem) error { return nil } +// configureMultipathServiceOnHost configures multipath service on the given host +// Parameters: +// ctx - context +// host - host to configure +// Returns: +// error - error if any +// Example: +// err := configureMultipathServiceOnHost(ctx, host) +// if err != nil { +// log.Error(err) +// } +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func configureMultipathServiceOnHost(ctx context.Context, host HostSystem) error { var err error var output []byte @@ -522,6 +654,17 @@ func ISCSIActiveOnHost(ctx context.Context, host HostSystem) (bool, error) { return ServiceActiveOnHost(ctx, serviceName) } +// enableAndStartServiceOnHost enables and starts a service on the host +// It returns an error if the service is not enabled or started +// Parameters: +// ctx - context for logging +// service - the service to enable and start +// Returns: +// error - error if the service is not enabled or started +// Example: +// err := enableAndStartServiceOnHost(ctx, "iscsi.service") +// +// -- Doc autogenerated on 2022-05-12 14:56:13.838311 -- func enableAndStartServiceOnHost(ctx context.Context, service string) error { var ( active, enabled bool diff --git a/utils/osutils_linux_test.go b/utils/osutils_linux_test.go index 141427f60..3dc8a412e 100644 --- a/utils/osutils_linux_test.go +++ b/utils/osutils_linux_test.go @@ -14,6 +14,10 @@ import ( "github.com/stretchr/testify/assert" ) +// TestDetermineNFSPackages tests the determineNFSPackages function +// It checks the packages returned for a variety of distros +// +// -- Doc autogenerated on 2022-05-12 15:01:28.925004 -- func TestDetermineNFSPackages(t *testing.T) { log.Debug("Running TestDetermineNFSPackages...") @@ -68,6 +72,10 @@ func TestDetermineNFSPackages(t *testing.T) { } } +// TestGetPackageManagerForHost tests the getPackageManagerForHost function +// It checks that the correct +// +// -- Doc autogenerated on 2022-05-12 15:01:28.925004 -- func TestGetPackageManagerForHost(t *testing.T) { log.Debug("Running TestGetPackageManagerForHost...") @@ -140,6 +148,10 @@ func TestGetPackageManagerForHost(t *testing.T) { } } +// TestGetIPAddresses tests the getIPAddresses function +// It checks that the returned addresses are not loopback and are global unicast +// +// -- Doc autogenerated on 2022-05-12 15:01:28.925004 -- func TestGetIPAddresses(t *testing.T) { addrs, err := getIPAddresses(context.TODO()) if err != nil { @@ -156,6 +168,11 @@ func TestGetIPAddresses(t *testing.T) { } } +// TestGetIPAddressesExceptingDummyInterfaces tests the getIPAddressesExceptingDummyInterfaces function +// It checks that the function returns at least one address, and that all addresses are global unicast +// and not loopback +// +// -- Doc autogenerated on 2022-05-12 15:01:28.925004 -- func TestGetIPAddressesExceptingDummyInterfaces(t *testing.T) { addrs, err := getIPAddressesExceptingDummyInterfaces(context.TODO()) if err != nil { @@ -172,6 +189,10 @@ func TestGetIPAddressesExceptingDummyInterfaces(t *testing.T) { } } +// TestGetIPAddressesExceptingNondefaultRoutes tests the getIPAddressesExceptingNondefaultRoutes function +// It checks that the function returns at least one IP address and that the IP addresses returned are valid +// +// -- Doc autogenerated on 2022-05-12 15:01:28.925004 -- func TestGetIPAddressesExceptingNondefaultRoutes(t *testing.T) { addrs, err := getIPAddressesExceptingNondefaultRoutes(context.TODO()) if err != nil { diff --git a/utils/osutils_test.go b/utils/osutils_test.go index bceb71b17..00b00e671 100644 --- a/utils/osutils_test.go +++ b/utils/osutils_test.go @@ -11,6 +11,11 @@ import ( "github.com/stretchr/testify/assert" ) +// TestParseIPv6Valid tests valid IPv6 addresses +// It checks that the IPv6Check function returns true for valid IPv6 addresses +// It returns false for invalid IPv6 addresses +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestParseIPv6Valid(t *testing.T) { tests := map[string]struct { input string @@ -74,6 +79,11 @@ func TestParseIPv6Valid(t *testing.T) { } } +// TestParseIPv4Valid tests that the IPv6Check function returns false for valid IPv4 addresses +// It checks that the IPv6Check function returns false for valid IPv4 addresses +// It returns true for invalid IPv4 addresses +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestParseIPv4Valid(t *testing.T) { tests := map[string]struct { input string @@ -116,6 +126,10 @@ func TestParseIPv4Valid(t *testing.T) { } } +// TestSanitizeString tests the sanitizeString function +// It checks that the function strips out xterm control characters and trailing newlines +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestSanitizeString(t *testing.T) { tests := map[string]struct { input string @@ -138,6 +152,10 @@ func TestSanitizeString(t *testing.T) { } } +// TestPidRunningOrIdleRegex tests the pidRunningOrIdleRegex +// It checks for both positive and negative matches +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestPidRunningOrIdleRegex(t *testing.T) { log.Debug("Running TestPidRegexes...") @@ -177,6 +195,11 @@ func TestPidRunningOrIdleRegex(t *testing.T) { } } +// TestGetHostportIP tests the getHostportIP function +// It checks that the function returns the correct IP address +// for various inputs +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestGetHostportIP(t *testing.T) { type IPAddresses struct { InputIP string @@ -219,6 +242,11 @@ func TestGetHostportIP(t *testing.T) { } } +// TestEnsureHostportFormatted tests ensureHostportFormatted +// It checks that the function correctly formats IP addresses +// with and without ports +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestEnsureHostportFormatted(t *testing.T) { type IPAddresses struct { InputIP string @@ -266,6 +294,12 @@ func TestEnsureHostportFormatted(t *testing.T) { } } +// TestFormatPortal tests the formatPortal function +// It checks that the function correctly adds the default iSCSI port to an IP address +// It also checks that the function does not add the default iSCSI port to an IP address that already has a port +// It also checks that the function does not add the default iSCSI port to an IP address that already has a non-default port +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestFormatPortal(t *testing.T) { type IPAddresses struct { InputPortal string @@ -304,6 +338,10 @@ func TestFormatPortal(t *testing.T) { } } +// TestFilterTargets tests the filterTargets function +// It checks that the correct IQNs are returned for a given portal +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestFilterTargets(t *testing.T) { type FilterCase struct { CommandOutput string @@ -381,6 +419,10 @@ func TestFilterTargets(t *testing.T) { } } +// TestParseInitiatorIQNs tests the parseInitiatorIQNs function +// It checks that the function returns the expected initiator IQNs +// +// -- Doc autogenerated on 2022-05-12 15:02:24.480017 -- func TestParseInitiatorIQNs(t *testing.T) { ctx := context.TODO() tests := map[string]struct { diff --git a/utils/utils.go b/utils/utils.go index fd3100c52..349a5c60e 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -60,14 +60,47 @@ var ( type sizeUnit2 []string +// Len implements sort.Interface. +// It returns the length of the slice. +// Returns: +// int +// Example: +// s := sizeUnit2{} +// s.Len() +// >> 0 +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func (s sizeUnit2) Len() int { return len(s) } +// Swap implements the Swap method in sort.Interface +// Parameters: +// i: index of first element to swap +// j: index of second element to swap +// Returns: +// none +// Example: +// sizeUnit2 := []SizeUnit{SizeUnit{Size: 1}, SizeUnit{Size: 2}} +// sizeUnit2.Swap(0,1) +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func (s sizeUnit2) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +// Less is used to sort the sizeUnit2 slice +// It returns true if the length of the first string is greater than the length of the second string +// Parameters: +// i: index of the first string +// j: index of the second string +// Returns: +// true if the length of the first string is greater than the length of the second string +// Example: +// Less(2, 3) +// returns true if the length of the string at index 2 is greater than the length of the string at index 3 +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func (s sizeUnit2) Less(i, j int) bool { return len(s[i]) > len(s[j]) } @@ -120,14 +153,45 @@ func init() { type sizeUnit10 []string +// Len returns the length of the sizeUnit10 +// Returns: +// int: the length of the sizeUnit10 +// Example: +// s := sizeUnit10{1,2,3} +// fmt.Println(s.Len()) +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func (s sizeUnit10) Len() int { return len(s) } +// Swap implements the sort.Interface +// Parameters: +// i: index of the first element to swap +// j: index of the second element to swap +// Returns: +// none +// Example: +// s := []int{1,2,3} +// s.Swap(0,2) +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func (s sizeUnit10) Swap(i, j int) { s[i], s[j] = s[j], s[i] } +// Less is used to sort the sizeUnit10 slice +// It returns true if the length of the first string is greater than the length of the second string +// Parameters: +// i - index of the first string +// j - index of the second string +// Returns: +// true if the length of the first string is greater than the length of the second string +// Example: +// sizeUnit10{ "1", "10", "100", "1000" }.Less(2, 3) +// returns true +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func (s sizeUnit10) Less(i, j int) bool { return len(s[i]) > len(s[j]) } @@ -322,6 +386,17 @@ func StringInSlice(s string, list []string) bool { return false } +// LogHTTPRequest logs an HTTP request +// Parameters: +// request: the HTTP request +// requestBody: the body of the HTTP request +// redactBody: whether to redact the body of the HTTP request +// Returns: +// None +// Example: +// LogHTTPRequest(request, requestBody, true) +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func LogHTTPRequest(request *http.Request, requestBody []byte, redactBody bool) { header := ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>" footer := "--------------------------------------------------------------------------------" @@ -352,6 +427,18 @@ func LogHTTPRequest(request *http.Request, requestBody []byte, redactBody bool) header, request.Method, requestURL, headers, body, footer) } +// LogHTTPResponse logs the HTTP response +// Parameters: +// ctx - context +// response - HTTP response +// responseBody - HTTP response body +// redactBody - if true, the body will be redacted +// Returns: +// none +// Example: +// LogHTTPResponse(ctx, response, responseBody, true) +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func LogHTTPResponse(ctx context.Context, response *http.Response, responseBody []byte, redactBody bool) { header := "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<" footer := "================================================================================" @@ -381,10 +468,28 @@ type HTTPError struct { StatusCode int } +// Error types +// It returns the error message as a string +// Returns: +// string: error message +// Example: +// e := utils.HTTPError{Status: "400 Bad Request"} +// fmt.Println(e.Error()) +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func (e HTTPError) Error() string { return fmt.Sprintf("HTTP error: %s", e.Status) } +// NewHTTPError returns an HTTPError if the response status code is >= 300 +// Parameters: +// response *http.Response +// Returns: +// *HTTPError +// Example: +// err := NewHTTPError(response) +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func NewHTTPError(response *http.Response) *HTTPError { if response.StatusCode < 300 { return nil @@ -565,6 +670,18 @@ func FilterIPs(ctx context.Context, ips, cidrs []string) ([]string, error) { return filteredIPs, nil } +// GetYAMLTagWithSpaceCount returns the indentation of a tag in a YAML file. +// It returns the tag with the indentation and the number of spaces. +// Parameters: +// text: The text of the YAML file. +// tagName: The name of the tag to search for. +// Returns: +// string: The tag with the indentation. +// int: The number of spaces in the indentation. +// Example: +// tag, indentation := utils.GetYAMLTagWithSpaceCount(text, "tagName") +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func GetYAMLTagWithSpaceCount(text, tagName string) (string, int) { // This matches pattern in a multiline string of type " {something}\n" tagsWithIndentationRegex := regexp.MustCompile(`(?m)^[\t ]*{` + tagName + `}$\n`) @@ -581,6 +698,16 @@ func GetYAMLTagWithSpaceCount(text, tagName string) (string, int) { return "", 0 } +// CountSpacesBeforeText counts the number of spaces before the text +// It returns the number of spaces before the text +// Parameters: +// text: the text to count spaces before +// Returns: +// the number of spaces before the text +// Example: +// CountSpacesBeforeText(" Hello") returns 3 +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func CountSpacesBeforeText(text string) int { return len(text) - len(strings.TrimLeft(text, " \t")) } @@ -767,10 +894,27 @@ func GetRegexSubmatches(r *regexp.Regexp, s string) map[string]string { } // Detect if code is running in a container or not +// RunningInContainer returns true if the code is running in a container +// Returns: +// bool +// Example: +// utils.RunningInContainer() +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func RunningInContainer() bool { return os.Getenv("CSI_ENDPOINT") != "" } +// Max returns the larger of x or y. +// Parameters: +// x: first value +// y: second value +// Returns: +// the larger of x or y +// Example: +// Max(1, 2) => 2 +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func Max(x, y int64) int64 { if x > y { return x @@ -806,6 +950,19 @@ func MinInt64(a, b int64) int64 { return b } +// ValidateOctalUnixPermissions validates that the given string is a valid octal unix permissions value +// It returns an error if the given string is not a valid octal unix permissions value +// Parameters: +// perms: string to validate +// Returns: +// error: nil if the given string is a valid octal unix permissions value, otherwise an error +// Example: +// err := utils.ValidateOctalUnixPermissions("0755") +// if err != nil { +// handle error +// } +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func ValidateOctalUnixPermissions(perms string) error { permsRegex := regexp.MustCompile(`^[0-7]{4}$`) @@ -816,6 +973,20 @@ func ValidateOctalUnixPermissions(perms string) error { return nil } +// GenerateVolumePublishName generates the volume publish name +// It returns the volumeID.nodeID +// Parameters: +// volumeID: the volume ID +// nodeID: the node ID +// Returns: +// string: the volume publish name +// Example: +// volumeID := "8e0f9c1c-b3ac-40f5-8c7a-d9b68a9a95a2" +// nodeID := "node1" +// volumePublishName := utils.GenerateVolumePublishName(volumeID, nodeID) +// // volumePublishName is "8e0f9c1c-b3ac-40f5-8c7a-d9b68a9a95a2.node1" +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func GenerateVolumePublishName(volumeID, nodeID string) string { return fmt.Sprintf(volumeID + "." + nodeID) } @@ -850,6 +1021,25 @@ func ToStringRedacted(structPointer interface{}, redactList []string, configVal return } +// RedactSecretsFromString redacts secrets from a string +// It returns a string with the secrets redacted +// Parameters: +// stringToSanitize - the string to sanitize +// replacements - a map of secrets to redact and their replacement values +// useRegex - whether or not to use regex to redact the secrets +// Returns: +// string - the sanitized string +// Example: +// stringToSanitize := "secret1=foo secret2=bar" +// replacements := map[string]string{ +// "secret1=.*": "secret1=********", +// "secret2=.*": "secret2=********", +// } +// useRegex := true +// RedactSecretsFromString(stringToSanitize, replacements, useRegex) +// // secret1=******** secret2=******** +// +// -- Doc autogenerated on 2022-05-12 15:04:08.156871 -- func RedactSecretsFromString(stringToSanitize string, replacements map[string]string, useRegex bool) string { compileError := "regex matching the secret could not compile, so the entire string has been redacted" diff --git a/utils/utils_test.go b/utils/utils_test.go index 317ec79ec..03f07dbfc 100644 --- a/utils/utils_test.go +++ b/utils/utils_test.go @@ -50,12 +50,24 @@ var testCustomStringSlice = []CustomString{ "superbingstring", } +// TestMain is the main function for the test suite +// It checks for any errors and exits with the appropriate status code +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestMain(m *testing.M) { // Disable any standard log output log.SetOutput(ioutil.Discard) os.Exit(m.Run()) } +// TestPow tests the Pow function +// It checks the following cases: +// 1024^0 == 1 +// 1024^1 == 1024 +// 1024^2 == 1048576 +// 1024^3 == 1073741824 +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestPow(t *testing.T) { log.Debug("Running TestPow...") @@ -76,6 +88,20 @@ func TestPow(t *testing.T) { } } +// TestConvertSizeToBytes tests the ConvertSizeToBytes function +// It checks the following: +// - 512 == 512 +// - 1KB == 1000 +// - 1Ki == 1024 +// - 1KiB == 1024 +// - 4k == 4096 +// - 1gi == 1073741824 +// - 1Gi == 1073741824 +// - 1GiB == 1073741824 +// - 1gb == 1000000000 +// - 1g == 1073741824 +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestConvertSizeToBytes(t *testing.T) { log.Debug("Running TestConvertSizeToBytes...") @@ -101,6 +127,10 @@ func TestConvertSizeToBytes(t *testing.T) { } } +// TestGetV tests the GetV function +// It checks that the correct value is returned when the key is present and when it is not +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestGetV(t *testing.T) { log.Debug("Running TestGetV...") @@ -116,6 +146,13 @@ func TestGetV(t *testing.T) { } } +// TestVolumeSizeWithinTolerance tests the VolumeSizeWithinTolerance function +// It checks the following cases: +// 1. Requested size is within delta of current size +// 2. Requested size is exactly the same as current size +// 3. Requested size is outside of delta of current size +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestVolumeSizeWithinTolerance(t *testing.T) { log.Debug("Running TestVolumeSizeWithinTolerance...") @@ -146,6 +183,10 @@ func TestVolumeSizeWithinTolerance(t *testing.T) { } } +// TestSliceContainsString tests the SliceContainsString function +// It checks for both positive and negative cases +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSliceContainsString(t *testing.T) { log.Debug("Running TestSliceContainsString...") @@ -171,6 +212,12 @@ func TestSliceContainsString(t *testing.T) { } } +// TestSliceContains tests the SliceContains function +// It checks the following: +// - Positive cases +// - Negative cases +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSliceContains(t *testing.T) { log.Debug("Running TestSliceContains...") @@ -213,6 +260,10 @@ func TestSliceContains(t *testing.T) { } } +// TestSliceContainElements tests the SliceContainsElements function +// It checks for both ContainsAll and ContainsSome +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSliceContainElements(t *testing.T) { log.Debug("Running TestSliceContainElements...") @@ -318,6 +369,11 @@ func TestSliceContainElements(t *testing.T) { } } +// TestRemoveStringFromSlice tests the RemoveStringFromSlice function +// It checks that the string is removed from the slice and that the slice is not modified +// if the string is not in the slice +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestRemoveStringFromSlice(t *testing.T) { log.Debug("Running TestRemoveStringFromSlice...") @@ -348,6 +404,11 @@ func TestRemoveStringFromSlice(t *testing.T) { } } +// TestRemoveStringFromSliceConditionally tests the RemoveStringFromSliceConditionally function +// It checks that the function removes the correct elements from the slice +// It returns an error if the function does not remove the correct elements +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestRemoveStringFromSliceConditionally(t *testing.T) { log.Debug("Running TestRemoveStringFromSlice...") @@ -400,6 +461,10 @@ func TestRemoveStringFromSliceConditionally(t *testing.T) { } } +// TestSliceContainsStringCaseInsensitive tests the SliceContainsStringCaseInsensitive function +// It checks both positive and negative cases +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSliceContainsStringCaseInsensitive(t *testing.T) { log.Debug("Running TestSliceContainsStringCaseInsensitive...") @@ -425,6 +490,11 @@ func TestSliceContainsStringCaseInsensitive(t *testing.T) { } } +// TestSliceContainsStringConditionally tests the SliceContainsStringConditionally function +// It checks that the function returns the expected result for a variety of inputs +// It returns an error if the function does not return the expected result +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSliceContainsStringConditionally(t *testing.T) { log.Debug("Running TestSliceContainsStringConditionally...") @@ -454,6 +524,10 @@ func TestSliceContainsStringConditionally(t *testing.T) { } } +// TestSplitImageDomain tests the SplitImageDomain function. +// It checks that the domain and remainder are split correctly. +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSplitImageDomain(t *testing.T) { log.Debug("Running TestSplitImageDomain...") @@ -470,6 +544,11 @@ func TestSplitImageDomain(t *testing.T) { assert.Equal(t, "k8scsi/csi-node-driver-registrar:v1.0.2", remainder) } +// TestReplaceImageRegistry tests the ReplaceImageRegistry function +// It checks that the image is not changed if the registry is empty +// It checks that the image is changed if the registry is not empty +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestReplaceImageRegistry(t *testing.T) { log.Debug("Running ReplaceImageRegistry...") @@ -483,6 +562,10 @@ func TestReplaceImageRegistry(t *testing.T) { assert.Equal(t, "mydomain:5000/k8scsi/csi-node-driver-registrar:v1.0.2", image) } +// TestFilterIPs tests the FilterIPs function +// It checks that the function returns the correct IPs for a variety of inputs +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestFilterIPs(t *testing.T) { log.Debug("Running TestFilterIPs...") @@ -564,6 +647,10 @@ text {REPLACE-4} ` +// TestGetYAMLTagWithSpaceCount tests the GetYAMLTagWithSpaceCount function +// It checks that the correct tag is returned and that the correct number of spaces is returned +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestGetYAMLTagWithSpaceCount(t *testing.T) { log.Debug("Running TestGetYAMLTagWithSpaceCount...") @@ -590,6 +677,10 @@ func TestGetYAMLTagWithSpaceCount(t *testing.T) { assert.Equal(t, spaces, 4) } +// TestCountSpacesBeforeText tests the CountSpacesBeforeText function. +// It checks that the function returns the correct number of spaces before the text. +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestCountSpacesBeforeText(t *testing.T) { log.Debug("Running TestCountSpacesBeforeText...") @@ -612,6 +703,10 @@ func TestCountSpacesBeforeText(t *testing.T) { } } +// TestGetNFSVersionFromMountOptions tests the GetNFSVersionFromMountOptions function +// It checks that the correct version is returned for different mount options +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestGetNFSVersionFromMountOptions(t *testing.T) { log.Debug("Running TestGetNFSVersionFromMountOptions...") @@ -656,6 +751,10 @@ func TestGetNFSVersionFromMountOptions(t *testing.T) { } } +// TestGetNFSVersionMountOptions tests the GetNFSVersionMountOptions function +// It checks that the correct NFS version is returned from the mount options +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestGetNFSVersionMountOptions(t *testing.T) { log.Debug("Running TestGetNFSVersionMountOptions...") @@ -689,6 +788,10 @@ func TestGetNFSVersionMountOptions(t *testing.T) { } } +// TestSetNFSVersionMountOptions tests the SetNFSVersionMountOptions function +// It checks that the correct mount options are returned for the given input +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSetNFSVersionMountOptions(t *testing.T) { log.Debug("Running TestSetNFSVersionMountOptions...") @@ -733,6 +836,19 @@ defaults { ` +// TestGetFindMultipathValue tests the GetFindMultipathValue function +// It checks the following cases: +// 1. find_multipaths is set to no +// 2. find_multipaths is commented out +// 3. find_multipaths is set to yes +// 4. find_multipaths is set to on +// 5. find_multipaths is set to off +// 6. find_multipaths is set to random +// 7. find_multipaths is set to smart +// 8. find_multipaths is set to greedy +// 9. find_multipaths is set to 'no' +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestGetFindMultipathValue(t *testing.T) { log.Debug("Running TestGetFindMultipathValue...") @@ -800,6 +916,19 @@ func TestGetFindMultipathValue(t *testing.T) { assert.Equal(t, "no", findMultipathsValue) } +// TestSplitString tests the SplitString function. +// It checks the following cases: +// - a,b,c +// - a,b, c +// - a,b,c +// - a,b,c +// - a,b,c +// - "" +// - "" +// - " " +// - ;a;b +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSplitString(t *testing.T) { log.Debug("Running TestSplitString...") @@ -830,6 +959,11 @@ func TestSplitString(t *testing.T) { assert.Equal(t, []string{"", "a", "b"}, stringList) } +// TestReplaceAtIndex tests the ReplaceAtIndex function +// It checks that the function returns the expected string +// and error for various inputs +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestReplaceAtIndex(t *testing.T) { actual, err := ReplaceAtIndex("foo", 'f', 0) assert.Nil(t, err) @@ -856,6 +990,10 @@ func TestReplaceAtIndex(t *testing.T) { assert.Equal(t, "boo", actual) } +// TestMinInt64 tests the MinInt64 function +// It checks that the minimum value is returned for a variety of inputs +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestMinInt64(t *testing.T) { log.Debug("Running TestMinInt64...") assert.Equal(t, int64(2), MinInt64(2, 3)) @@ -868,6 +1006,15 @@ func TestMinInt64(t *testing.T) { assert.Equal(t, int64(2), MinInt64(2, 2)) } +// TestValidateCIDRSet tests the ValidateCIDRSet function +// It checks the following: +// 1. A set of valid CIDR blocks does not return an error +// 2. An error is returned when a set of invalid CIDR blocks is passed in +// 3. An error is returned when a set of valid and invalid CIDR blocks is passed in +// 4. The error contains the invalid CIDR blocks +// It returns an error if any of the tests fail +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestValidateCIDRSet(t *testing.T) { ctx := context.TODO() @@ -937,6 +1084,10 @@ func TestValidateCIDRSet(t *testing.T) { } } +// TestValidateOctalUnixPermissions tests the ValidateOctalUnixPermissions function +// It checks that the function returns the expected error for a variety of inputs +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestValidateOctalUnixPermissions(t *testing.T) { tests := []struct { perms string @@ -964,6 +1115,10 @@ func TestValidateOctalUnixPermissions(t *testing.T) { } } +// TestMustParseMajorMinorVersion tests the MustParseMajorMinorVersion function +// It checks that it returns the expected value for a valid input and panics for invalid inputs +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestMustParseMajorMinorVersion(t *testing.T) { majorMinor := "v1.23" majorMinorVersion := MustParseSemantic(majorMinor + ".0").ToMajorMinorVersion() @@ -977,6 +1132,11 @@ func TestMustParseMajorMinorVersion(t *testing.T) { " major version should cause a panic") } +// TestRedactSecretsFromString tests the RedactSecretsFromString function +// It checks that the function properly redacts secrets from a string +// It also checks that the function returns a safe string when the regex cannot be compiled +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestRedactSecretsFromString(t *testing.T) { passphrase := "chap-initiator-secret" outboundPassphrase := "chap-target-initiator-secret" @@ -1062,6 +1222,10 @@ func TestRedactSecretsFromString(t *testing.T) { } } +// TestGetVerifiedBlockFsType tests the GetVerifiedBlockFsType function. +// It checks that the function returns the expected fsType and error. +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestGetVerifiedBlockFsType(t *testing.T) { log.Debug("Running TestGetVerifiedBlockFsType...") @@ -1092,6 +1256,10 @@ func TestGetVerifiedBlockFsType(t *testing.T) { } } +// TestVerifyFilesystemSupport verifies the VerifyFilesystemSupport function +// It checks for supported filesystems and unsupported filesystems +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestVerifyFilesystemSupport(t *testing.T) { log.Debug("Running TestVerifyFilesystemSupport...") @@ -1126,6 +1294,10 @@ func TestVerifyFilesystemSupport(t *testing.T) { } } +// TestAppendToStringList tests the AppendToStringList function. +// It checks that the function correctly appends a new item to a string list. +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestAppendToStringList(t *testing.T) { log.Debug("Running TestAppendToStringList...") @@ -1168,6 +1340,10 @@ func TestAppendToStringList(t *testing.T) { } } +// TestSanitizeMountOptions tests the SanitizeMountOptions function +// It checks that the correct mount options are removed +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestSanitizeMountOptions(t *testing.T) { log.Debug("Running TestSanitizeMountOptions...") @@ -1193,6 +1369,11 @@ func TestSanitizeMountOptions(t *testing.T) { } } +// TestAreMountOptionsInList tests the AreMountOptionsInList function +// It checks that the function returns true if the mount options are in the list +// and false if they are not. +// +// -- Doc autogenerated on 2022-05-12 15:10:00.616723 -- func TestAreMountOptionsInList(t *testing.T) { log.Debug("Running TestAreMountOptionsInList...") diff --git a/utils/version.go b/utils/version.go index 04170960e..e8e3a3fa5 100644 --- a/utils/version.go +++ b/utils/version.go @@ -45,6 +45,27 @@ var ( extraMatchRE = regexp.MustCompile(`^(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?\s*$`) ) +// parse parses a version string. +// +// If semver is true, the version must be a semantic version. +// If datever is true, the version must be a date version. +// If neither is true, the version must be at least a major.minor version. +// It returns an error if the version string is invalid. +// Parameters: +// str: the version string to parse +// semver: whether to parse as a semantic version +// datever: whether to parse as a date version +// Returns: +// *Version: the parsed version +// error: an error if the version string is invalid +// Example: +// version, err := parse("1.2.3", true, false) +// if err != nil { +// fmt.Println(err) +// } +// fmt.Println(version) +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func parse(str string, semver, datever bool) (*Version, error) { parts := versionMatchRE.FindStringSubmatch(str) if parts == nil { @@ -157,22 +178,66 @@ func MustParseDate(str string) *Version { return v } +// MajorVersion returns the major version of the version string +// Returns: +// uint: The major version +// Example: +// v := &Version{components: []uint{1, 2, 3, 4}} +// v.MajorVersion() returns 1 +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func (v *Version) MajorVersion() uint { return v.components[0] } +// MajorVersionString returns the major version as a string +// Returns: +// string - major version +// Example: +// version := NewVersion("1.2.3") +// version.MajorVersionString() // "1" +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func (v *Version) MajorVersionString() string { return strconv.FormatUint(uint64(v.components[0]), 10) } +// MinorVersion returns the minor version of the version string +// Returns: +// uint - minor version +// Example: +// v := NewVersion("1.2.3") +// v.MinorVersion() +// // Output: 2 +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func (v *Version) MinorVersion() uint { return v.components[1] } +// MinorVersionString returns the minor version as a string +// Returns: +// string: minor version +// Example: +// v := utils.NewVersion("3.5.0") +// v.MinorVersionString() +// Returns: +// "5" +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func (v *Version) MinorVersionString() string { return strconv.FormatUint(uint64(v.components[1]), 10) } +// PatchVersion returns the patch version of the version. +// Returns: +// 0 if the version is not in the form of major.minor.patch +// Example: +// v := Version{[]uint{1, 2, 3}} +// v.PatchVersion() +// Output: 3 +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func (v *Version) PatchVersion() uint { if len(v.components) < 3 { return 0 @@ -180,6 +245,15 @@ func (v *Version) PatchVersion() uint { return v.components[2] } +// PreRelease returns the pre-release string of the version. +// Returns: +// string: the pre-release string of the version +// Example: +// v := NewVersion("1.0.0-alpha") +// fmt.Println(v.PreRelease()) +// // Output: alpha +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func (v *Version) PreRelease() string { return v.preRelease } @@ -348,10 +422,26 @@ func (v *Version) Compare(other string) (int, error) { return v.compareInternal(ov), nil } +// ToMajorMinorVersion returns a new Version with the patch version set to 0. +// Returns: +// *Version: A new Version with the patch version set to 0. +// Example: +// version := MustParseGeneric("1.2.3") +// version.ToMajorMinorVersion() // Returns 1.2.0 +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func (v *Version) ToMajorMinorVersion() *Version { return MustParseGeneric(fmt.Sprintf("%d.%d", v.MajorVersion(), v.MinorVersion())) } +// ToMajorMinorString returns a string representation of the major and minor version +// Returns: +// "major.minor" +// Example: +// v := NewVersion("1.2.3") +// v.ToMajorMinorString() // "1.2" +// +// -- Doc autogenerated on 2022-05-12 15:16:15.188335 -- func (v *Version) ToMajorMinorString() string { return fmt.Sprintf("%d.%d", v.MajorVersion(), v.MinorVersion()) } diff --git a/utils/version_test.go b/utils/version_test.go index ff9c0fab8..ac115254e 100644 --- a/utils/version_test.go +++ b/utils/version_test.go @@ -27,6 +27,27 @@ type testItem struct { equalsPrev bool } +// testOne tests a single version string. +// It returns an error if the version string does not round-trip, +// or if it is not ordered correctly relative to the previous version string. +// Parameters: +// v: the version to test +// item: the test item for the version +// prev: the previous test item +// Returns: +// error: an error if the version does not round-trip or is not ordered correctly +// Example: +// var v *Version +// var err error +// for _, item := range testItems { +// err = testOne(v, item, prev) +// if err != nil { +// return err +// } +// prev = item +// } +// +// -- Doc autogenerated on 2022-05-12 15:19:23.516989 -- func testOne(v *Version, item, prev testItem) error { str := v.String() if item.unparsed == "" { @@ -57,6 +78,11 @@ func testOne(v *Version, item, prev testItem) error { return nil } +// TestSemanticVersions tests the ParseSemantic function. +// It checks that the parsed version is correct, and that +// the ordering of the versions is correct. +// +// -- Doc autogenerated on 2022-05-12 15:19:23.516989 -- func TestSemanticVersions(t *testing.T) { tests := []testItem{ // This is every version string that appears in the 2.0 semver spec, @@ -112,6 +138,11 @@ func TestSemanticVersions(t *testing.T) { } } +// TestBadSemanticVersions tests that invalid semver strings are rejected. +// It checks that the parser is not too permissive, and that it rejects +// invalid semver strings. +// +// -- Doc autogenerated on 2022-05-12 15:19:23.516989 -- func TestBadSemanticVersions(t *testing.T) { tests := []string{ // "MUST take the form X.Y.Z" @@ -168,6 +199,11 @@ func TestBadSemanticVersions(t *testing.T) { } } +// TestDateVersions tests the date version parsing +// It checks that the parsed version is correct, and that +// it is ordered correctly. +// +// -- Doc autogenerated on 2022-05-12 15:19:23.516989 -- func TestDateVersions(t *testing.T) { tests := []testItem{ // This is every version string that appears in the 2.0 semver spec, @@ -221,6 +257,16 @@ func TestDateVersions(t *testing.T) { } } +// TestBadDateVersions tests that invalid date versions are rejected. +// It checks that all of the following are rejected: +// - invalid format +// - invalid month +// - invalid pre-release +// - invalid build metadata +// - whitespace +// - "v"-prefix +// +// -- Doc autogenerated on 2022-05-12 15:19:23.516989 -- func TestBadDateVersions(t *testing.T) { tests := []string{ // "MUST take the form X.Y.Z" @@ -280,6 +326,11 @@ func TestBadDateVersions(t *testing.T) { } } +// TestGenericVersions tests that the generic version parser works as expected. +// It checks that the generic parser parses the same strings as the semantic +// parser, and that it parses some additional strings. +// +// -- Doc autogenerated on 2022-05-12 15:19:23.516989 -- func TestGenericVersions(t *testing.T) { tests := []testItem{ // This is all of the strings from TestSemanticVersions, plus some strings @@ -350,6 +401,10 @@ func TestGenericVersions(t *testing.T) { } } +// TestBadGenericVersions tests that invalid versions fail to parse +// It checks that the error is not nil +// +// -- Doc autogenerated on 2022-05-12 15:19:23.516989 -- func TestBadGenericVersions(t *testing.T) { tests := []string{ "1",