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