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 }