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