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