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