github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/worker/storageprovisioner/common.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storageprovisioner 5 6 import ( 7 "path/filepath" 8 9 "github.com/juju/errors" 10 "gopkg.in/juju/names.v2" 11 12 "github.com/juju/juju/apiserver/params" 13 "github.com/juju/juju/core/watcher" 14 "github.com/juju/juju/storage" 15 ) 16 17 // storageEntityLife queries the lifecycle state of each specified 18 // storage entity (volume or filesystem), and then partitions the 19 // tags by them. 20 func storageEntityLife(ctx *context, tags []names.Tag) (alive, dying, dead []names.Tag, _ error) { 21 lifeResults, err := ctx.config.Life.Life(tags) 22 if err != nil { 23 return nil, nil, nil, errors.Annotate(err, "getting storage entity life") 24 } 25 for i, result := range lifeResults { 26 life := result.Life 27 if result.Error != nil { 28 if !params.IsCodeNotFound(result.Error) { 29 return nil, nil, nil, errors.Annotatef( 30 result.Error, "getting life of %s", 31 names.ReadableString(tags[i]), 32 ) 33 } 34 life = params.Dead 35 } 36 switch life { 37 case params.Alive: 38 alive = append(alive, tags[i]) 39 case params.Dying: 40 dying = append(dying, tags[i]) 41 case params.Dead: 42 dead = append(dead, tags[i]) 43 } 44 } 45 return alive, dying, dead, nil 46 } 47 48 // attachmentLife queries the lifecycle state of each specified 49 // attachment, and then partitions the IDs by them. 50 func attachmentLife(ctx *context, ids []params.MachineStorageId) ( 51 alive, dying, dead []params.MachineStorageId, _ error, 52 ) { 53 lifeResults, err := ctx.config.Life.AttachmentLife(ids) 54 if err != nil { 55 return nil, nil, nil, errors.Annotate(err, "getting machine attachment life") 56 } 57 for i, result := range lifeResults { 58 life := result.Life 59 if result.Error != nil { 60 if !params.IsCodeNotFound(result.Error) { 61 return nil, nil, nil, errors.Annotatef( 62 result.Error, "getting life of %s attached to %s", 63 ids[i].AttachmentTag, ids[i].MachineTag, 64 ) 65 } 66 life = params.Dead 67 } 68 switch life { 69 case params.Alive: 70 alive = append(alive, ids[i]) 71 case params.Dying: 72 dying = append(dying, ids[i]) 73 case params.Dead: 74 dead = append(dead, ids[i]) 75 } 76 } 77 return alive, dying, dead, nil 78 } 79 80 // removeEntities removes each specified Dead entity from state. 81 func removeEntities(ctx *context, tags []names.Tag) error { 82 if len(tags) == 0 { 83 return nil 84 } 85 logger.Debugf("removing entities: %v", tags) 86 errorResults, err := ctx.config.Life.Remove(tags) 87 if err != nil { 88 return errors.Annotate(err, "removing storage entities") 89 } 90 for i, result := range errorResults { 91 if result.Error != nil { 92 return errors.Annotatef(result.Error, "removing %s from state", names.ReadableString(tags[i])) 93 } 94 } 95 return nil 96 } 97 98 // removeAttachments removes each specified attachment from state. 99 func removeAttachments(ctx *context, ids []params.MachineStorageId) error { 100 if len(ids) == 0 { 101 return nil 102 } 103 errorResults, err := ctx.config.Life.RemoveAttachments(ids) 104 if err != nil { 105 return errors.Annotate(err, "removing attachments") 106 } 107 for i, result := range errorResults { 108 if result.Error != nil && !params.IsCodeNotFound(result.Error) { 109 // ignore not found error. 110 return errors.Annotatef( 111 result.Error, "removing attachment of %s to %s from state", 112 ids[i].AttachmentTag, ids[i].MachineTag, 113 ) 114 } 115 } 116 return nil 117 } 118 119 // setStatus sets the given entity statuses, if any. If setting 120 // the status fails the error is logged but otherwise ignored. 121 func setStatus(ctx *context, statuses []params.EntityStatusArgs) { 122 if len(statuses) > 0 { 123 if err := ctx.config.Status.SetStatus(statuses); err != nil { 124 logger.Errorf("failed to set status: %v", err) 125 } 126 } 127 } 128 129 var errNonDynamic = errors.New("non-dynamic storage provider") 130 131 // volumeSource returns a volume source given a name, provider type, 132 // environment config and storage directory. 133 // 134 // TODO(axw) move this to the main storageprovisioner, and have 135 // it watch for changes to storage source configurations, updating 136 // a map in-between calls to the volume/filesystem/attachment 137 // event handlers. 138 func volumeSource( 139 baseStorageDir string, 140 sourceName string, 141 providerType storage.ProviderType, 142 registry storage.ProviderRegistry, 143 ) (storage.VolumeSource, error) { 144 provider, sourceConfig, err := sourceParams(baseStorageDir, sourceName, providerType, registry) 145 if err != nil { 146 return nil, errors.Annotatef(err, "getting storage source %q params", sourceName) 147 } 148 if !provider.Dynamic() { 149 return nil, errNonDynamic 150 } 151 source, err := provider.VolumeSource(sourceConfig) 152 if err != nil { 153 return nil, errors.Annotatef(err, "getting storage source %q", sourceName) 154 } 155 return source, nil 156 } 157 158 // filesystemSource returns a filesystem source given a name, provider type, 159 // environment config and storage directory. 160 // 161 // TODO(axw) move this to the main storageprovisioner, and have 162 // it watch for changes to storage source configurations, updating 163 // a map in-between calls to the volume/filesystem/attachment 164 // event handlers. 165 func filesystemSource( 166 baseStorageDir string, 167 sourceName string, 168 providerType storage.ProviderType, 169 registry storage.ProviderRegistry, 170 ) (storage.FilesystemSource, error) { 171 provider, sourceConfig, err := sourceParams(baseStorageDir, sourceName, providerType, registry) 172 if err != nil { 173 return nil, errors.Annotatef(err, "getting storage source %q params", sourceName) 174 } 175 source, err := provider.FilesystemSource(sourceConfig) 176 if err != nil { 177 return nil, errors.Annotatef(err, "getting storage source %q", sourceName) 178 } 179 return source, nil 180 } 181 182 func sourceParams( 183 baseStorageDir string, 184 sourceName string, 185 providerType storage.ProviderType, 186 registry storage.ProviderRegistry, 187 ) (storage.Provider, *storage.Config, error) { 188 provider, err := registry.StorageProvider(providerType) 189 if err != nil { 190 return nil, nil, errors.Annotate(err, "getting provider") 191 } 192 attrs := make(map[string]interface{}) 193 if baseStorageDir != "" { 194 storageDir := filepath.Join(baseStorageDir, sourceName) 195 attrs[storage.ConfigStorageDir] = storageDir 196 } 197 sourceConfig, err := storage.NewConfig(sourceName, providerType, attrs) 198 if err != nil { 199 return nil, nil, errors.Annotate(err, "getting config") 200 } 201 return provider, sourceConfig, nil 202 } 203 204 func copyMachineStorageIds(src []watcher.MachineStorageId) []params.MachineStorageId { 205 dst := make([]params.MachineStorageId, len(src)) 206 for i, msid := range src { 207 dst[i] = params.MachineStorageId{ 208 MachineTag: msid.MachineTag, 209 AttachmentTag: msid.AttachmentTag, 210 } 211 } 212 return dst 213 }