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