github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/apiserver/common/storagecommon/volumes.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package storagecommon 5 6 import ( 7 "github.com/juju/errors" 8 "gopkg.in/juju/names.v2" 9 10 "github.com/juju/juju/apiserver/params" 11 "github.com/juju/juju/environs/config" 12 "github.com/juju/juju/state" 13 "github.com/juju/juju/storage" 14 "github.com/juju/juju/storage/poolmanager" 15 ) 16 17 type volumeAlreadyProvisionedError struct { 18 error 19 } 20 21 // IsVolumeAlreadyProvisioned returns true if the specified error 22 // is caused by a volume already being provisioned. 23 func IsVolumeAlreadyProvisioned(err error) bool { 24 _, ok := err.(*volumeAlreadyProvisionedError) 25 return ok 26 } 27 28 // VolumeParams returns the parameters for creating or destroying 29 // the given volume. 30 func VolumeParams( 31 v state.Volume, 32 storageInstance state.StorageInstance, 33 modelUUID, controllerUUID string, 34 environConfig *config.Config, 35 poolManager poolmanager.PoolManager, 36 registry storage.ProviderRegistry, 37 ) (params.VolumeParams, error) { 38 39 var pool string 40 var size uint64 41 if stateVolumeParams, ok := v.Params(); ok { 42 pool = stateVolumeParams.Pool 43 size = stateVolumeParams.Size 44 } else { 45 volumeInfo, err := v.Info() 46 if err != nil { 47 return params.VolumeParams{}, errors.Trace(err) 48 } 49 pool = volumeInfo.Pool 50 size = volumeInfo.Size 51 } 52 53 volumeTags, err := storageTags(storageInstance, modelUUID, controllerUUID, environConfig) 54 if err != nil { 55 return params.VolumeParams{}, errors.Annotate(err, "computing storage tags") 56 } 57 58 providerType, cfg, err := StoragePoolConfig(pool, poolManager, registry) 59 if err != nil { 60 return params.VolumeParams{}, errors.Trace(err) 61 } 62 return params.VolumeParams{ 63 v.Tag().String(), 64 size, 65 string(providerType), 66 cfg.Attrs(), 67 volumeTags, 68 nil, // attachment params set by the caller 69 }, nil 70 } 71 72 // StoragePoolConfig returns the storage provider type and 73 // configuration for a named storage pool. If there is no 74 // such pool with the specified name, but it identifies a 75 // storage provider, then that type will be returned with a 76 // nil configuration. 77 func StoragePoolConfig(name string, poolManager poolmanager.PoolManager, registry storage.ProviderRegistry) (storage.ProviderType, *storage.Config, error) { 78 pool, err := poolManager.Get(name) 79 if errors.IsNotFound(err) { 80 // If not a storage pool, then maybe a provider type. 81 providerType := storage.ProviderType(name) 82 if _, err1 := registry.StorageProvider(providerType); err1 != nil { 83 return "", nil, errors.Trace(err) 84 } 85 return providerType, &storage.Config{}, nil 86 } else if err != nil { 87 return "", nil, errors.Annotatef(err, "getting pool %q", name) 88 } 89 return pool.Provider(), pool, nil 90 } 91 92 // VolumesToState converts a slice of params.Volume to a mapping 93 // of volume tags to state.VolumeInfo. 94 func VolumesToState(in []params.Volume) (map[names.VolumeTag]state.VolumeInfo, error) { 95 m := make(map[names.VolumeTag]state.VolumeInfo) 96 for _, v := range in { 97 tag, volumeInfo, err := VolumeToState(v) 98 if err != nil { 99 return nil, errors.Trace(err) 100 } 101 m[tag] = volumeInfo 102 } 103 return m, nil 104 } 105 106 // VolumeToState converts a params.Volume to state.VolumeInfo 107 // and names.VolumeTag. 108 func VolumeToState(v params.Volume) (names.VolumeTag, state.VolumeInfo, error) { 109 if v.VolumeTag == "" { 110 return names.VolumeTag{}, state.VolumeInfo{}, errors.New("Tag is empty") 111 } 112 volumeTag, err := names.ParseVolumeTag(v.VolumeTag) 113 if err != nil { 114 return names.VolumeTag{}, state.VolumeInfo{}, errors.Trace(err) 115 } 116 return volumeTag, state.VolumeInfo{ 117 v.Info.HardwareId, 118 v.Info.Size, 119 "", // pool is set by state 120 v.Info.VolumeId, 121 v.Info.Persistent, 122 }, nil 123 } 124 125 // VolumeFromState converts a state.Volume to params.Volume. 126 func VolumeFromState(v state.Volume) (params.Volume, error) { 127 info, err := v.Info() 128 if err != nil { 129 return params.Volume{}, errors.Trace(err) 130 } 131 return params.Volume{ 132 v.VolumeTag().String(), 133 VolumeInfoFromState(info), 134 }, nil 135 } 136 137 // VolumeInfoFromState converts a state.VolumeInfo to params.VolumeInfo. 138 func VolumeInfoFromState(info state.VolumeInfo) params.VolumeInfo { 139 return params.VolumeInfo{ 140 info.VolumeId, 141 info.HardwareId, 142 info.Size, 143 info.Persistent, 144 } 145 } 146 147 // VolumeAttachmentFromState converts a state.VolumeAttachment to params.VolumeAttachment. 148 func VolumeAttachmentFromState(v state.VolumeAttachment) (params.VolumeAttachment, error) { 149 info, err := v.Info() 150 if err != nil { 151 return params.VolumeAttachment{}, errors.Trace(err) 152 } 153 return params.VolumeAttachment{ 154 v.Volume().String(), 155 v.Machine().String(), 156 VolumeAttachmentInfoFromState(info), 157 }, nil 158 } 159 160 // VolumeAttachmentInfoFromState converts a state.VolumeAttachmentInfo to params.VolumeAttachmentInfo. 161 func VolumeAttachmentInfoFromState(info state.VolumeAttachmentInfo) params.VolumeAttachmentInfo { 162 return params.VolumeAttachmentInfo{ 163 info.DeviceName, 164 info.DeviceLink, 165 info.BusAddress, 166 info.ReadOnly, 167 } 168 } 169 170 // VolumeAttachmentInfosToState converts a map of volume tags to 171 // params.VolumeAttachmentInfo to a map of volume tags to 172 // state.VolumeAttachmentInfo. 173 func VolumeAttachmentInfosToState(in map[string]params.VolumeAttachmentInfo) (map[names.VolumeTag]state.VolumeAttachmentInfo, error) { 174 m := make(map[names.VolumeTag]state.VolumeAttachmentInfo) 175 for k, v := range in { 176 volumeTag, err := names.ParseVolumeTag(k) 177 if err != nil { 178 return nil, errors.Trace(err) 179 } 180 m[volumeTag] = VolumeAttachmentInfoToState(v) 181 } 182 return m, nil 183 } 184 185 // VolumeAttachmentToState converts a params.VolumeAttachment 186 // to a state.VolumeAttachmentInfo and tags. 187 func VolumeAttachmentToState(in params.VolumeAttachment) (names.MachineTag, names.VolumeTag, state.VolumeAttachmentInfo, error) { 188 machineTag, err := names.ParseMachineTag(in.MachineTag) 189 if err != nil { 190 return names.MachineTag{}, names.VolumeTag{}, state.VolumeAttachmentInfo{}, err 191 } 192 volumeTag, err := names.ParseVolumeTag(in.VolumeTag) 193 if err != nil { 194 return names.MachineTag{}, names.VolumeTag{}, state.VolumeAttachmentInfo{}, err 195 } 196 info := VolumeAttachmentInfoToState(in.Info) 197 return machineTag, volumeTag, info, nil 198 } 199 200 // VolumeAttachmentInfoToState converts a params.VolumeAttachmentInfo 201 // to a state.VolumeAttachmentInfo. 202 func VolumeAttachmentInfoToState(in params.VolumeAttachmentInfo) state.VolumeAttachmentInfo { 203 return state.VolumeAttachmentInfo{ 204 in.DeviceName, 205 in.DeviceLink, 206 in.BusAddress, 207 in.ReadOnly, 208 } 209 } 210 211 // ParseVolumeAttachmentIds parses the strings, returning machine storage IDs. 212 func ParseVolumeAttachmentIds(stringIds []string) ([]params.MachineStorageId, error) { 213 ids := make([]params.MachineStorageId, len(stringIds)) 214 for i, s := range stringIds { 215 m, v, err := state.ParseVolumeAttachmentId(s) 216 if err != nil { 217 return nil, err 218 } 219 ids[i] = params.MachineStorageId{ 220 MachineTag: m.String(), 221 AttachmentTag: v.String(), 222 } 223 } 224 return ids, nil 225 }