From 1868c55b885ab2714aa536da122df2ec41a4fa2f Mon Sep 17 00:00:00 2001 From: Ian Booth Date: Fri, 1 Mar 2024 13:26:27 +1000 Subject: [PATCH] Various fixes, better validation, txn closures --- domain/storage/errors/errors.go | 10 +- domain/storage/service/service.go | 28 ++-- domain/storage/service/service_test.go | 45 +++++- domain/storage/state/state.go | 188 +++++++++++++++---------- domain/storage/state/state_test.go | 13 +- 5 files changed, 190 insertions(+), 94 deletions(-) diff --git a/domain/storage/errors/errors.go b/domain/storage/errors/errors.go index 9f817049c1f..604ce954638 100644 --- a/domain/storage/errors/errors.go +++ b/domain/storage/errors/errors.go @@ -9,7 +9,13 @@ import ( const ( // MissingPoolTypeError is used when a provider type is empty. - MissingPoolTypeError = errors.ConstError("pool provider type is missing") + MissingPoolTypeError = errors.ConstError("pool provider type is empty") // MissingPoolNameError is used when a name is empty. - MissingPoolNameError = errors.ConstError("pool name is missing") + MissingPoolNameError = errors.ConstError("pool name is empty") + + InvalidPoolNameError = errors.ConstError("pool name is not valid") + + PoolNotFoundError = errors.ConstError("storage pool is not found") + + PoolAlreadyExists = errors.ConstError("storage pool already exists") ) diff --git a/domain/storage/service/service.go b/domain/storage/service/service.go index 1dc4373b062..f89eeb5d1ff 100644 --- a/domain/storage/service/service.go +++ b/domain/storage/service/service.go @@ -51,13 +51,6 @@ type PoolAttrs map[string]any // CreateStoragePool creates a storage pool, returning an error satisfying [errors.AlreadyExists] // if a pool with the same name already exists. func (s *Service) CreateStoragePool(ctx context.Context, name string, providerType storage.ProviderType, attrs PoolAttrs) error { - if name == "" { - return storageerrors.MissingPoolNameError - } - if providerType == "" { - return storageerrors.MissingPoolTypeError - } - err := s.validateConfig(name, providerType, attrs) if err != nil { return errors.Trace(err) @@ -74,9 +67,19 @@ func (s *Service) CreateStoragePool(ctx context.Context, name string, providerTy } func (s *Service) validateConfig(name string, providerType storage.ProviderType, attrs map[string]interface{}) error { + if name == "" { + return storageerrors.MissingPoolNameError + } + if !storage.IsValidPoolName(name) { + return fmt.Errorf("pool name %q not valid%w", name, errors.Hide(storageerrors.InvalidPoolNameError)) + } + if providerType == "" { + return storageerrors.MissingPoolTypeError + } if s.registry == nil { - return errors.New("cannot validate storage provider config without a registry") + return errors.Errorf("cannot validate storage provider config for %q without a registry", name) } + cfg, err := storage.NewConfig(name, providerType, attrs) if err != nil { return errors.Trace(err) @@ -126,7 +129,7 @@ func (s *Service) DeleteStoragePool(ctx context.Context, name string) error { } // ReplaceStoragePool replaces an existing storage pool, returning an error -// satisfying [errors.NotFound] if a pool with the name does not exist. +// satisfying [storageerrors.PoolNotFoundError] if a pool with the name does not exist. func (s *Service) ReplaceStoragePool(ctx context.Context, name string, providerType storage.ProviderType, attrs PoolAttrs) error { // Use the existing provider type unless explicitly overwritten. if providerType == "" { @@ -185,7 +188,7 @@ func (a *Service) validatePoolListFilter(filter domainstorage.StoragePoolFilter) func (a *Service) validateNameCriteria(names []string) error { for _, n := range names { if !storage.IsValidPoolName(n) { - return errors.NotValidf("pool name %q", n) + return fmt.Errorf("pool name %q not valid%w", n, errors.Hide(storageerrors.InvalidPoolNameError)) } } return nil @@ -205,8 +208,11 @@ func (s *Service) validateProviderCriteria(providers []string) error { } // GetStoragePoolByName returns the storage pool with the specified name, returning an error -// satisfying [errors.NotFound] if it doesn't exist. +// satisfying [storageerrors.PoolNotFoundError] if it doesn't exist. func (s *Service) GetStoragePoolByName(ctx context.Context, name string) (*storage.Config, error) { + if !storage.IsValidPoolName(name) { + return nil, fmt.Errorf("pool name %q not valid%w", name, errors.Hide(storageerrors.InvalidPoolNameError)) + } sp, err := s.st.GetStoragePoolByName(ctx, name) if err != nil { return nil, errors.Trace(err) diff --git a/domain/storage/service/service_test.go b/domain/storage/service/service_test.go index e1990a88e69..8a10d959556 100644 --- a/domain/storage/service/service_test.go +++ b/domain/storage/service/service_test.go @@ -5,7 +5,6 @@ package service import ( "context" - "fmt" "github.com/juju/errors" "github.com/juju/loggo/v2" @@ -15,6 +14,7 @@ import ( gc "gopkg.in/check.v1" domainstorage "github.com/juju/juju/domain/storage" + storageerrors "github.com/juju/juju/domain/storage/errors" "github.com/juju/juju/internal/storage" dummystorage "github.com/juju/juju/internal/storage/provider/dummy" ) @@ -28,6 +28,8 @@ type serviceSuite struct { var _ = gc.Suite(&serviceSuite{}) +const validationError = errors.ConstError("missing attribute foo") + func (s *serviceSuite) setupMocks(c *gc.C) *gomock.Controller { ctrl := gomock.NewController(c) @@ -38,7 +40,7 @@ func (s *serviceSuite) setupMocks(c *gc.C) *gomock.Controller { "ebs": &dummystorage.StorageProvider{ ValidateConfigFunc: func(sp *storage.Config) error { if _, ok := sp.Attrs()["foo"]; !ok { - return fmt.Errorf("missing attribute foo") + return validationError } return nil }, @@ -69,10 +71,32 @@ func (s *serviceSuite) TestCreateStoragePool(c *gc.C) { c.Assert(err, jc.ErrorIsNil) } +func (s *serviceSuite) TestCreateStoragePoolInvalidName(c *gc.C) { + defer s.setupMocks(c).Finish() + + err := s.service().CreateStoragePool(context.Background(), "66invalid", "ebs", PoolAttrs{"foo": "foo val"}) + c.Assert(err, jc.ErrorIs, storageerrors.InvalidPoolNameError) +} + +func (s *serviceSuite) TestCreateStoragePoolMissingName(c *gc.C) { + defer s.setupMocks(c).Finish() + + err := s.service().CreateStoragePool(context.Background(), "", "ebs", PoolAttrs{"foo": "foo val"}) + c.Assert(err, jc.ErrorIs, storageerrors.MissingPoolNameError) +} + +func (s *serviceSuite) TestCreateStoragePoolMissingType(c *gc.C) { + defer s.setupMocks(c).Finish() + + err := s.service().CreateStoragePool(context.Background(), "ebs-fast", "", PoolAttrs{"foo": "foo val"}) + c.Assert(err, jc.ErrorIs, storageerrors.MissingPoolTypeError) +} + func (s *serviceSuite) TestCreateStoragePoolValidates(c *gc.C) { defer s.setupMocks(c).Finish() err := s.service().CreateStoragePool(context.Background(), "ebs-fast", "ebs", PoolAttrs{"bar": "bar val"}) + c.Assert(err, jc.ErrorIs, validationError) c.Assert(err, gc.ErrorMatches, `.* missing attribute foo`) } @@ -101,6 +125,20 @@ func (s *serviceSuite) TestReplaceStoragePool(c *gc.C) { c.Assert(err, jc.ErrorIsNil) } +func (s *serviceSuite) TestReplaceStoragePoolInvalidName(c *gc.C) { + defer s.setupMocks(c).Finish() + + err := s.service().ReplaceStoragePool(context.Background(), "66invalid", "ebs", PoolAttrs{"foo": "foo val"}) + c.Assert(err, jc.ErrorIs, storageerrors.InvalidPoolNameError) +} + +func (s *serviceSuite) TestReplaceStoragePoolMissingName(c *gc.C) { + defer s.setupMocks(c).Finish() + + err := s.service().ReplaceStoragePool(context.Background(), "", "ebs", PoolAttrs{"foo": "foo val"}) + c.Assert(err, jc.ErrorIs, storageerrors.MissingPoolNameError) +} + func (s *serviceSuite) TestReplaceStoragePoolExistingProvider(c *gc.C) { defer s.setupMocks(c).Finish() @@ -122,6 +160,7 @@ func (s *serviceSuite) TestReplaceStoragePoolValidates(c *gc.C) { defer s.setupMocks(c).Finish() err := s.service().ReplaceStoragePool(context.Background(), "ebs-fast", "ebs", PoolAttrs{"bar": "bar val"}) + c.Assert(err, jc.ErrorIs, validationError) c.Assert(err, gc.ErrorMatches, `.* missing attribute foo`) } @@ -175,7 +214,7 @@ func (s *serviceSuite) TestListStoragePoolsInvalidFilterName(c *gc.C) { _, err := s.service().ListStoragePools(context.Background(), domainstorage.StoragePoolFilter{ Names: []string{"666invalid"}, }) - c.Assert(err, jc.ErrorIs, errors.NotValid) + c.Assert(err, jc.ErrorIs, storageerrors.InvalidPoolNameError) c.Assert(err, gc.ErrorMatches, `pool name "666invalid" not valid`) } diff --git a/domain/storage/state/state.go b/domain/storage/state/state.go index 31a388f836a..b9a753fee94 100644 --- a/domain/storage/state/state.go +++ b/domain/storage/state/state.go @@ -13,6 +13,7 @@ import ( coredatabase "github.com/juju/juju/core/database" "github.com/juju/juju/domain" domainstorage "github.com/juju/juju/domain/storage" + storageerrors "github.com/juju/juju/domain/storage/errors" "github.com/juju/juju/internal/uuid" ) @@ -31,7 +32,7 @@ func NewState(factory coredatabase.TxnRunnerFactory) *State { type poolAttributes map[string]string -// CreateStoragePool creates a storage pool, returning an error satisfying [errors.AlreadyExists] +// CreateStoragePool creates a storage pool, returning an error satisfying [storageerrors.PoolAlreadyExists] // if a pool with the same name already exists. func (st State) CreateStoragePool(ctx context.Context, pool domainstorage.StoragePoolDetails) error { db, err := st.DB() @@ -43,6 +44,16 @@ func (st State) CreateStoragePool(ctx context.Context, pool domainstorage.Storag if err != nil { return errors.Trace(domain.CoerceError(err)) } + + storagePoolUpserter, err := storagePoolUpserter() + if err != nil { + return errors.Trace(domain.CoerceError(err)) + } + poolAttributesUpdater, err := poolAttributesUpdater() + if err != nil { + return errors.Trace(domain.CoerceError(err)) + } + err = db.Txn(ctx, func(ctx context.Context, tx *sqlair.TX) error { dbPool := StoragePool{Name: pool.Name} err := tx.Query(ctx, selectUUIDStmt, dbPool).Get(&dbPool) @@ -50,37 +61,26 @@ func (st State) CreateStoragePool(ctx context.Context, pool domainstorage.Storag return errors.Trace(domain.CoerceError(err)) } if err == nil { - return fmt.Errorf("storage pool %q %w", pool.Name, errors.AlreadyExists) + return fmt.Errorf("storage pool %q %w", pool.Name, storageerrors.PoolAlreadyExists) } poolUUID := uuid.MustNewUUID().String() - if err := upsertStoragePool(ctx, tx, poolUUID, pool.Name, pool.Provider); err != nil { - return errors.Annotate(domain.CoerceError(err), "creating storage pool") + if err := storagePoolUpserter(ctx, tx, poolUUID, pool.Name, pool.Provider); err != nil { + return errors.Annotatef(err, "creating storage pool %q", pool.Name) } - if err := updatePoolAttributes(ctx, tx, poolUUID, pool.Attrs); err != nil { - return errors.Annotatef(domain.CoerceError(err), "creating storage pool %s attributes", poolUUID) + if err := poolAttributesUpdater(ctx, tx, poolUUID, pool.Attrs); err != nil { + return errors.Annotatef(err, "creating storage pool %q attributes", pool.Name) } return nil }) - return errors.Trace(err) + return errors.Trace(domain.CoerceError(err)) } -func upsertStoragePool(ctx context.Context, tx *sqlair.TX, poolUUID string, name string, providerType string) error { - if name == "" { - return fmt.Errorf("storage pool name cannot be empty%w", errors.Hide(errors.NotValid)) - } - if providerType == "" { - return fmt.Errorf("storage pool type cannot be empty%w", errors.Hide(errors.NotValid)) - } - - dbPool := StoragePool{ - ID: poolUUID, - Name: name, - ProviderType: providerType, - } +type upsertStoragePoolFunc func(ctx context.Context, tx *sqlair.TX, poolUUID string, name string, providerType string) error +func storagePoolUpserter() (upsertStoragePoolFunc, error) { insertQuery := ` INSERT INTO storage_pool (uuid, name, type) VALUES ( @@ -94,17 +94,34 @@ ON CONFLICT(uuid) DO UPDATE SET name=excluded.name, insertStmt, err := sqlair.Prepare(insertQuery, StoragePool{}) if err != nil { - return errors.Trace(err) + return nil, errors.Trace(err) } - err = tx.Query(ctx, insertStmt, dbPool).Run() - if err != nil { - return errors.Trace(err) - } - return nil + return func(ctx context.Context, tx *sqlair.TX, poolUUID string, name string, providerType string) error { + if name == "" { + return fmt.Errorf("storage pool name cannot be empty%w", errors.Hide(storageerrors.MissingPoolNameError)) + } + if providerType == "" { + return fmt.Errorf("storage pool type cannot be empty%w", errors.Hide(storageerrors.MissingPoolTypeError)) + } + + dbPool := StoragePool{ + ID: poolUUID, + Name: name, + ProviderType: providerType, + } + + err = tx.Query(ctx, insertStmt, dbPool).Run() + if err != nil { + return errors.Trace(err) + } + return nil + }, nil } -func updatePoolAttributes(ctx context.Context, tx *sqlair.TX, storagePoolUUID string, attr domainstorage.Attrs) error { +type updatePoolAttributesFunc func(ctx context.Context, tx *sqlair.TX, storagePoolUUID string, attr domainstorage.Attrs) error + +func poolAttributesUpdater() (updatePoolAttributesFunc, error) { // Delete any keys no longer in the attributes map. // TODO(wallyworld) - use sqlair NOT IN operation deleteQuery := fmt.Sprintf(` @@ -115,10 +132,7 @@ WHERE storage_pool_uuid = $M.uuid deleteStmt, err := sqlair.Prepare(deleteQuery, sqlair.M{}) if err != nil { - return errors.Trace(err) - } - if err := tx.Query(ctx, deleteStmt, sqlair.M{"uuid": storagePoolUUID}).Run(); err != nil { - return errors.Trace(domain.CoerceError(err)) + return nil, errors.Trace(err) } insertQuery := ` @@ -133,19 +147,24 @@ ON CONFLICT(storage_pool_uuid, key) DO UPDATE SET key=excluded.key, ` insertStmt, err := sqlair.Prepare(insertQuery, poolAttribute{}) if err != nil { - return errors.Trace(err) + return nil, errors.Trace(err) } - for key, value := range attr { - if err := tx.Query(ctx, insertStmt, poolAttribute{ - ID: storagePoolUUID, - Key: key, - Value: value, - }).Run(); err != nil { - return errors.Trace(domain.CoerceError(err)) + return func(ctx context.Context, tx *sqlair.TX, storagePoolUUID string, attr domainstorage.Attrs) error { + if err := tx.Query(ctx, deleteStmt, sqlair.M{"uuid": storagePoolUUID}).Run(); err != nil { + return errors.Trace(err) } - } - return nil + for key, value := range attr { + if err := tx.Query(ctx, insertStmt, poolAttribute{ + ID: storagePoolUUID, + Key: key, + Value: value, + }).Run(); err != nil { + return errors.Trace(err) + } + } + return nil + }, nil } // DeleteStoragePool deletes a storage pool, returning an error satisfying @@ -175,25 +194,26 @@ WHERE storage_pool.uuid = (select uuid FROM storage_pool WHERE name = $M.name) return errors.Trace(err) } - return db.Txn(ctx, func(ctx context.Context, tx *sqlair.TX) error { + err = db.Txn(ctx, func(ctx context.Context, tx *sqlair.TX) error { nameMap := sqlair.M{"name": name} if err := tx.Query(ctx, poolAttributeDeleteStmt, nameMap).Run(); err != nil { - return errors.Annotate(domain.CoerceError(err), "deleting storage pool attributes") + return errors.Annotate(err, "deleting storage pool attributes") } var outcome = sqlair.Outcome{} err = tx.Query(ctx, poolDeleteStmt, nameMap).Get(&outcome) if err != nil { - return errors.Trace(domain.CoerceError(err)) + return errors.Trace(err) } rowsAffected, err := outcome.Result().RowsAffected() if err != nil { - return errors.Annotate(domain.CoerceError(err), "deleting storage pool") + return errors.Annotate(err, "deleting storage pool") } if rowsAffected == 0 { - return fmt.Errorf("storage pool %q %w", name, errors.NotFound) + return fmt.Errorf("storage pool %q not found%w", name, errors.Hide(storageerrors.PoolNotFoundError)) } - return errors.Annotate(domain.CoerceError(err), "deleting storage pool") + return errors.Annotate(err, "deleting storage pool") }) + return errors.Trace(domain.CoerceError(err)) } // ReplaceStoragePool replaces an existing storage pool, returning an error @@ -208,30 +228,42 @@ func (st State) ReplaceStoragePool(ctx context.Context, pool domainstorage.Stora if err != nil { return errors.Trace(domain.CoerceError(err)) } + + storagePoolUpserter, err := storagePoolUpserter() + if err != nil { + return errors.Trace(domain.CoerceError(err)) + } + poolAttributesUpdater, err := poolAttributesUpdater() + if err != nil { + return errors.Trace(domain.CoerceError(err)) + } + err = db.Txn(ctx, func(ctx context.Context, tx *sqlair.TX) error { dbPool := StoragePool{Name: pool.Name} err := tx.Query(ctx, selectUUIDStmt, dbPool).Get(&dbPool) if err != nil && !errors.Is(err, sqlair.ErrNoRows) { - return errors.Trace(domain.CoerceError(err)) + return errors.Trace(err) } if err != nil { - return fmt.Errorf("storage pool %q %w", pool.Name, errors.NotFound) + return fmt.Errorf("storage pool %q not found%w", pool.Name, errors.Hide(storageerrors.PoolNotFoundError)) } poolUUID := dbPool.ID - if err := upsertStoragePool(ctx, tx, poolUUID, pool.Name, pool.Provider); err != nil { - return errors.Annotate(domain.CoerceError(err), "updating storage pool") + if err := storagePoolUpserter(ctx, tx, poolUUID, pool.Name, pool.Provider); err != nil { + return errors.Annotate(err, "updating storage pool") } - if err := updatePoolAttributes(ctx, tx, poolUUID, pool.Attrs); err != nil { - return errors.Annotatef(domain.CoerceError(err), "updating storage pool %s attributes", poolUUID) + if err := poolAttributesUpdater(ctx, tx, poolUUID, pool.Attrs); err != nil { + return errors.Annotatef(err, "updating storage pool %s attributes", poolUUID) } return nil }) - return errors.Trace(err) + return errors.Trace(domain.CoerceError(err)) } -func (st State) loadStoragePools(ctx context.Context, tx *sqlair.TX, filter domainstorage.StoragePoolFilter) ([]domainstorage.StoragePoolDetails, error) { +type loadStoragePoolsFunc func(ctx context.Context, tx *sqlair.TX) ([]domainstorage.StoragePoolDetails, error) + +func (st State) storagePoolsLoader(filter domainstorage.StoragePoolFilter) (loadStoragePoolsFunc, error) { query := ` SELECT (sp.uuid, sp.name, sp.type) AS (&StoragePool.*), (sp_attr.key, sp_attr.value) AS (&poolAttribute.*) @@ -257,15 +289,17 @@ FROM storage_pool sp return nil, errors.Trace(err) } - var ( - dbRows StoragePools - keyValues []poolAttribute - ) - err = tx.Query(ctx, queryStmt, queryArgs...).GetAll(&dbRows, &keyValues) - if err != nil { - return nil, errors.Annotate(domain.CoerceError(err), "loading storage pool") - } - return dbRows.toStoragePools(keyValues) + return func(ctx context.Context, tx *sqlair.TX) ([]domainstorage.StoragePoolDetails, error) { + var ( + dbRows StoragePools + keyValues []poolAttribute + ) + err = tx.Query(ctx, queryStmt, queryArgs...).GetAll(&dbRows, &keyValues) + if err != nil { + return nil, errors.Annotate(err, "loading storage pool") + } + return dbRows.toStoragePools(keyValues) + }, nil } // ListStoragePools returns the storage pools matching the specified filter. @@ -275,13 +309,18 @@ func (st State) ListStoragePools(ctx context.Context, filter domainstorage.Stora return nil, errors.Trace(err) } + storagePoolsLoader, err := st.storagePoolsLoader(filter) + if err != nil { + return nil, errors.Trace(err) + } + var result []domainstorage.StoragePoolDetails err = db.Txn(ctx, func(ctx context.Context, tx *sqlair.TX) error { var err error - result, err = st.loadStoragePools(ctx, tx, filter) + result, err = storagePoolsLoader(ctx, tx) return errors.Trace(err) }) - return result, errors.Trace(err) + return result, errors.Trace(domain.CoerceError(err)) } func (st State) buildFilter(filter domainstorage.StoragePoolFilter) (string, []any) { @@ -304,29 +343,34 @@ func (st State) buildFilter(filter domainstorage.StoragePoolFilter) (string, []a } // GetStoragePoolByName returns the storage pool with the specified name, returning an error -// satisfying [errors.NotFound] if it doesn't exist. +// satisfying [storageerrors.PoolNotFoundError] if it doesn't exist. func (st State) GetStoragePoolByName(ctx context.Context, name string) (domainstorage.StoragePoolDetails, error) { db, err := st.DB() if err != nil { return domainstorage.StoragePoolDetails{}, errors.Trace(err) } + storagePoolsLoader, err := st.storagePoolsLoader(domainstorage.StoragePoolFilter{ + Names: []string{name}, + }) + if err != nil { + return domainstorage.StoragePoolDetails{}, errors.Trace(err) + } + var storagePools []domainstorage.StoragePoolDetails err = db.Txn(ctx, func(ctx context.Context, tx *sqlair.TX) error { var err error - storagePools, err = st.loadStoragePools(ctx, tx, domainstorage.StoragePoolFilter{ - Names: []string{name}, - }) + storagePools, err = storagePoolsLoader(ctx, tx) return errors.Trace(err) }) if err != nil { return domainstorage.StoragePoolDetails{}, errors.Trace(err) } if len(storagePools) == 0 { - return domainstorage.StoragePoolDetails{}, fmt.Errorf("storage pool %q %w", name, errors.NotFound) + return domainstorage.StoragePoolDetails{}, fmt.Errorf("storage pool %q %w", name, storageerrors.PoolNotFoundError) } if len(storagePools) > 1 { return domainstorage.StoragePoolDetails{}, errors.Errorf("expected 1 storage pool, got %d", len(storagePools)) } - return storagePools[0], errors.Trace(err) + return storagePools[0], errors.Trace(domain.CoerceError(err)) } diff --git a/domain/storage/state/state_test.go b/domain/storage/state/state_test.go index 0d7c4f3e372..582c847eff6 100644 --- a/domain/storage/state/state_test.go +++ b/domain/storage/state/state_test.go @@ -12,6 +12,7 @@ import ( "github.com/juju/juju/domain/schema/testing" domainstorage "github.com/juju/juju/domain/storage" + storageerrors "github.com/juju/juju/domain/storage/errors" ) type storagePoolSuite struct { @@ -72,7 +73,7 @@ func (s *storagePoolSuite) TestCreateStoragePoolAlreadyExists(c *gc.C) { c.Assert(err, jc.ErrorIsNil) err = st.CreateStoragePool(ctx, sp) - c.Assert(err, jc.ErrorIs, errors.AlreadyExists) + c.Assert(err, jc.ErrorIs, storageerrors.PoolAlreadyExists) } func (s *storagePoolSuite) TestUpdateCloudCredentialMissingName(c *gc.C) { @@ -83,7 +84,7 @@ func (s *storagePoolSuite) TestUpdateCloudCredentialMissingName(c *gc.C) { } ctx := context.Background() err := st.CreateStoragePool(ctx, sp) - c.Assert(errors.Is(err, errors.NotValid), jc.IsTrue) + c.Assert(errors.Is(err, storageerrors.MissingPoolNameError), jc.IsTrue) } func (s *storagePoolSuite) TestUpdateCloudCredentialMissingProvider(c *gc.C) { @@ -94,7 +95,7 @@ func (s *storagePoolSuite) TestUpdateCloudCredentialMissingProvider(c *gc.C) { } ctx := context.Background() err := st.CreateStoragePool(ctx, sp) - c.Assert(errors.Is(err, errors.NotValid), jc.IsTrue) + c.Assert(errors.Is(err, storageerrors.MissingPoolTypeError), jc.IsTrue) } func (s *storagePoolSuite) TestReplaceStoragePool(c *gc.C) { @@ -166,7 +167,7 @@ func (s *storagePoolSuite) TestReplaceStoragePoolNotFound(c *gc.C) { } ctx := context.Background() err := st.ReplaceStoragePool(ctx, sp) - c.Assert(err, jc.ErrorIs, errors.NotFound) + c.Assert(err, jc.ErrorIs, storageerrors.PoolNotFoundError) } func (s *storagePoolSuite) TestDeleteStoragePool(c *gc.C) { @@ -188,7 +189,7 @@ func (s *storagePoolSuite) TestDeleteStoragePool(c *gc.C) { c.Assert(err, jc.ErrorIsNil) _, err = st.GetStoragePoolByName(ctx, "ebs-fast") - c.Assert(err, jc.ErrorIs, errors.NotFound) + c.Assert(err, jc.ErrorIs, storageerrors.PoolNotFoundError) } func (s *storagePoolSuite) TestDeleteStoragePoolNotFound(c *gc.C) { @@ -196,7 +197,7 @@ func (s *storagePoolSuite) TestDeleteStoragePoolNotFound(c *gc.C) { ctx := context.Background() err := st.DeleteStoragePool(ctx, "ebs-fast") - c.Assert(err, jc.ErrorIs, errors.NotFound) + c.Assert(err, jc.ErrorIs, storageerrors.PoolNotFoundError) } func (s *storagePoolSuite) TestListStoragePools(c *gc.C) {