github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/common/volumes.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package common 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 params.VolumeInfo{ 133 info.VolumeId, 134 info.HardwareId, 135 info.Size, 136 info.Persistent, 137 }, 138 }, nil 139 } 140 141 // VolumeAttachmentFromState converts a state.VolumeAttachment to params.VolumeAttachment. 142 func VolumeAttachmentFromState(v state.VolumeAttachment) (params.VolumeAttachment, error) { 143 info, err := v.Info() 144 if err != nil { 145 return params.VolumeAttachment{}, errors.Trace(err) 146 } 147 return params.VolumeAttachment{ 148 v.Volume().String(), 149 v.Machine().String(), 150 params.VolumeAttachmentInfo{ 151 info.DeviceName, 152 info.BusAddress, 153 info.ReadOnly, 154 }, 155 }, nil 156 } 157 158 // VolumeAttachmentInfosToState converts a map of volume tags to 159 // params.VolumeAttachmentInfo to a map of volume tags to 160 // state.VolumeAttachmentInfo. 161 func VolumeAttachmentInfosToState(in map[string]params.VolumeAttachmentInfo) (map[names.VolumeTag]state.VolumeAttachmentInfo, error) { 162 m := make(map[names.VolumeTag]state.VolumeAttachmentInfo) 163 for k, v := range in { 164 volumeTag, err := names.ParseVolumeTag(k) 165 if err != nil { 166 return nil, errors.Trace(err) 167 } 168 m[volumeTag] = VolumeAttachmentInfoToState(v) 169 } 170 return m, nil 171 } 172 173 // VolumeAttachmentToState converts a params.VolumeAttachment 174 // to a state.VolumeAttachmentInfo and tags. 175 func VolumeAttachmentToState(in params.VolumeAttachment) (names.MachineTag, names.VolumeTag, state.VolumeAttachmentInfo, error) { 176 machineTag, err := names.ParseMachineTag(in.MachineTag) 177 if err != nil { 178 return names.MachineTag{}, names.VolumeTag{}, state.VolumeAttachmentInfo{}, err 179 } 180 volumeTag, err := names.ParseVolumeTag(in.VolumeTag) 181 if err != nil { 182 return names.MachineTag{}, names.VolumeTag{}, state.VolumeAttachmentInfo{}, err 183 } 184 info := VolumeAttachmentInfoToState(in.Info) 185 return machineTag, volumeTag, info, nil 186 } 187 188 // VolumeAttachmentInfoToState converts a params.VolumeAttachmentInfo 189 // to a state.VolumeAttachmentInfo. 190 func VolumeAttachmentInfoToState(in params.VolumeAttachmentInfo) state.VolumeAttachmentInfo { 191 return state.VolumeAttachmentInfo{ 192 in.DeviceName, 193 in.BusAddress, 194 in.ReadOnly, 195 } 196 } 197 198 // ParseVolumeAttachmentIds parses the strings, returning machine storage IDs. 199 func ParseVolumeAttachmentIds(stringIds []string) ([]params.MachineStorageId, error) { 200 ids := make([]params.MachineStorageId, len(stringIds)) 201 for i, s := range stringIds { 202 m, v, err := state.ParseVolumeAttachmentId(s) 203 if err != nil { 204 return nil, err 205 } 206 ids[i] = params.MachineStorageId{ 207 MachineTag: m.String(), 208 AttachmentTag: v.String(), 209 } 210 } 211 return ids, nil 212 }