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