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 }