github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/storage/poolmanager/poolmanager.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package poolmanager
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  
     9  	"github.com/juju/juju/storage"
    10  )
    11  
    12  // Pool configuration attribute names.
    13  const (
    14  	Name = "name"
    15  	Type = "type"
    16  )
    17  
    18  var (
    19  	MissingTypeError = errors.New("provider type is missing")
    20  	MissingNameError = errors.New("pool name is missing")
    21  )
    22  
    23  // New returns a PoolManager implementation using the specified state.
    24  func New(settings SettingsManager, registry storage.ProviderRegistry) PoolManager {
    25  	return &poolManager{settings, registry}
    26  }
    27  
    28  var _ PoolManager = (*poolManager)(nil)
    29  
    30  type poolManager struct {
    31  	settings SettingsManager
    32  	registry storage.ProviderRegistry
    33  }
    34  
    35  const globalKeyPrefix = "pool#"
    36  
    37  func globalKey(name string) string {
    38  	return globalKeyPrefix + name
    39  }
    40  
    41  // Create is defined on PoolManager interface.
    42  func (pm *poolManager) Create(name string, providerType storage.ProviderType, attrs map[string]interface{}) (*storage.Config, error) {
    43  	if name == "" {
    44  		return nil, MissingNameError
    45  	}
    46  	if providerType == "" {
    47  		return nil, MissingTypeError
    48  	}
    49  
    50  	cfg, err := pm.validatedConfig(name, providerType, attrs)
    51  	if err != nil {
    52  		return nil, errors.Trace(err)
    53  	}
    54  
    55  	poolAttrs := cfg.Attrs()
    56  	poolAttrs[Name] = name
    57  	poolAttrs[Type] = string(providerType)
    58  	if err := pm.settings.CreateSettings(globalKey(name), poolAttrs); err != nil {
    59  		return nil, errors.Annotatef(err, "creating pool %q", name)
    60  	}
    61  	return cfg, nil
    62  }
    63  
    64  func (pm *poolManager) validatedConfig(name string, providerType storage.ProviderType, attrs map[string]interface{}) (*storage.Config, error) {
    65  	cfg, err := storage.NewConfig(name, providerType, attrs)
    66  	if err != nil {
    67  		return nil, errors.Trace(err)
    68  	}
    69  	p, err := pm.registry.StorageProvider(providerType)
    70  	if err != nil {
    71  		return nil, errors.Trace(err)
    72  	}
    73  	if err := p.ValidateConfig(cfg); err != nil {
    74  		return nil, errors.Annotate(err, "validating storage provider config")
    75  	}
    76  
    77  	return cfg, nil
    78  }
    79  
    80  // Delete is defined on PoolManager interface.
    81  func (pm *poolManager) Delete(name string) error {
    82  	err := pm.settings.RemoveSettings(globalKey(name))
    83  	if errors.IsNotFound(err) {
    84  		return errors.NotFoundf("storage pool %q", name)
    85  	}
    86  	return errors.Annotatef(err, "deleting pool %q", name)
    87  }
    88  
    89  // Replace is defined on PoolManager interface.
    90  func (pm *poolManager) Replace(name, provider string, attrs map[string]interface{}) error {
    91  	if name == "" {
    92  		return MissingNameError
    93  	}
    94  	var providerType storage.ProviderType
    95  	// Use the existing provider type unless explicitly overwritten.
    96  	if provider != "" {
    97  		providerType = storage.ProviderType(provider)
    98  	} else {
    99  		existingConfig, err := pm.Get(name)
   100  		if err != nil {
   101  			return errors.Trace(err)
   102  		}
   103  		providerType = existingConfig.Provider()
   104  	}
   105  	attrs[Type] = providerType
   106  	attrs[Name] = name
   107  	cfg, err := pm.validatedConfig(name, providerType, attrs)
   108  	if err != nil {
   109  		return errors.Trace(err)
   110  	}
   111  	validatedAttrs := cfg.Attrs()
   112  	validatedAttrs[Name] = name
   113  	validatedAttrs[Type] = string(providerType)
   114  	return pm.settings.ReplaceSettings(globalKey(name), attrs)
   115  }
   116  
   117  // Get is defined on PoolManager interface.
   118  func (pm *poolManager) Get(name string) (*storage.Config, error) {
   119  	settings, err := pm.settings.ReadSettings(globalKey(name))
   120  	if err != nil {
   121  		if errors.IsNotFound(err) {
   122  			return nil, errors.NotFoundf("pool %q", name)
   123  		} else {
   124  			return nil, errors.Annotatef(err, "reading pool %q", name)
   125  		}
   126  	}
   127  	return pm.configFromSettings(settings)
   128  }
   129  
   130  // List is defined on PoolManager interface.
   131  func (pm *poolManager) List() ([]*storage.Config, error) {
   132  	settings, err := pm.settings.ListSettings(globalKeyPrefix)
   133  	if err != nil {
   134  		return nil, errors.Annotate(err, "listing pool settings")
   135  	}
   136  	var result []*storage.Config
   137  	for _, attrs := range settings {
   138  		cfg, err := pm.configFromSettings(attrs)
   139  		if err != nil {
   140  			return nil, errors.Trace(err)
   141  		}
   142  		result = append(result, cfg)
   143  	}
   144  	return result, nil
   145  }
   146  
   147  func (pm *poolManager) configFromSettings(settings map[string]interface{}) (*storage.Config, error) {
   148  	providerType := storage.ProviderType(settings[Type].(string))
   149  	name := settings[Name].(string)
   150  	// Ensure returned attributes are stripped of name and type,
   151  	// as these are not user-specified attributes.
   152  	delete(settings, Name)
   153  	delete(settings, Type)
   154  	cfg, err := storage.NewConfig(name, providerType, settings)
   155  	if err != nil {
   156  		return nil, errors.Trace(err)
   157  	}
   158  	p, err := pm.registry.StorageProvider(providerType)
   159  	if err != nil {
   160  		return nil, errors.Trace(err)
   161  	}
   162  	if err := p.ValidateConfig(cfg); err != nil {
   163  		return nil, errors.Trace(err)
   164  	}
   165  	return cfg, nil
   166  }