github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/virt/fake/fake_storage.go (about) 1 /* 2 Copyright 2017 Mirantis 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package fake 18 19 import ( 20 "fmt" 21 "path" 22 "sort" 23 24 libvirtxml "github.com/libvirt/libvirt-go-xml" 25 26 testutils "github.com/Mirantis/virtlet/pkg/utils/testing" 27 "github.com/Mirantis/virtlet/pkg/virt" 28 ) 29 30 var capacityUnits = map[string]uint64{ 31 "b": 1, 32 "bytes": 1, 33 "KB": 1000, 34 "k": 1024, 35 "KiB": 1024, 36 "": 1024, // libvirt defaults to KiB 37 "MB": 1000000, 38 "M": 1048576, 39 "MiB": 1048576, 40 "GB": 1000000000, 41 "G": 1073741824, 42 "GiB": 1073741824, 43 "TB": 1000000000000, 44 "T": 1099511627776, 45 "TiB": 1099511627776, 46 } 47 48 // FakeStorageConnection is a fake implementation of StorageConnection. 49 type FakeStorageConnection struct { 50 rec testutils.Recorder 51 pools map[string]*FakeStoragePool 52 } 53 54 // NewFakeStorageConnection creates a new FakeStorageConnection using 55 // the specified Recorder to record any changes. 56 func NewFakeStorageConnection(rec testutils.Recorder) *FakeStorageConnection { 57 return &FakeStorageConnection{ 58 rec: rec, 59 pools: make(map[string]*FakeStoragePool), 60 } 61 } 62 63 // CreateStoragePool implements CreateStoragePool method of StorageConnection interface. 64 func (sc *FakeStorageConnection) CreateStoragePool(def *libvirtxml.StoragePool) (virt.StoragePool, error) { 65 sc.rec.Rec("CreateStoragePool", mustMarshal(def)) 66 if _, found := sc.pools[def.Name]; found { 67 return nil, fmt.Errorf("storage pool already exists: %v", def.Name) 68 } 69 p := NewFakeStoragePool(testutils.NewChildRecorder(sc.rec, def.Name), def) 70 sc.pools[def.Name] = p 71 return p, nil 72 } 73 74 // LookupStoragePoolByName implements LookupStoragePoolByName method of StorageConnection interface. 75 func (sc *FakeStorageConnection) LookupStoragePoolByName(name string) (virt.StoragePool, error) { 76 if p, found := sc.pools[name]; found { 77 return p, nil 78 } 79 return nil, virt.ErrStoragePoolNotFound 80 } 81 82 // ListPools implements ListPools method of StorageConnection interface. 83 func (sc *FakeStorageConnection) ListPools() ([]virt.StoragePool, error) { 84 r := make([]virt.StoragePool, len(sc.pools)) 85 names := make([]string, 0, len(sc.pools)) 86 for name := range sc.pools { 87 names = append(names, name) 88 } 89 sort.Strings(names) 90 for n, name := range names { 91 r[n] = sc.pools[name] 92 } 93 return r, nil 94 } 95 96 // PutFiles implements PutFiles method of StorageConnection interface. 97 func (sc *FakeStorageConnection) PutFiles(imagePath string, files map[string][]byte) error { 98 fileStrs := make(map[string]string) 99 for filename, content := range files { 100 fileStrs[filename] = string(content) 101 } 102 sc.rec.Rec("PutFiles", map[string]interface{}{ 103 "imagePath": fixPath(imagePath), 104 "files": fileStrs, 105 }) 106 return nil 107 } 108 109 // FakeStoragePool is a fake implementation of StoragePool interface. 110 type FakeStoragePool struct { 111 rec testutils.Recorder 112 name string 113 path string 114 volumes map[string]*FakeStorageVolume 115 def *libvirtxml.StoragePool 116 } 117 118 // NewFakeStoragePool creates a new StoragePool using the specified 119 // recorder, name and pool path. 120 func NewFakeStoragePool(rec testutils.Recorder, def *libvirtxml.StoragePool) *FakeStoragePool { 121 poolPath := "/" 122 if def.Target != nil { 123 poolPath = def.Target.Path 124 } 125 return &FakeStoragePool{ 126 rec: rec, 127 name: def.Name, 128 path: poolPath, 129 volumes: make(map[string]*FakeStorageVolume), 130 def: def, 131 } 132 } 133 134 func (p *FakeStoragePool) createStorageVol(def *libvirtxml.StorageVolume) (virt.StorageVolume, error) { 135 if _, found := p.volumes[def.Name]; found { 136 return nil, fmt.Errorf("storage volume already exists: %v", def.Name) 137 } 138 v, err := newFakeStorageVolume(testutils.NewChildRecorder(p.rec, def.Name), p, def) 139 if err != nil { 140 return nil, err 141 } 142 p.volumes[def.Name] = v 143 return v, nil 144 } 145 146 // CreateStorageVol implements CreateStorageVol method of StoragePool interface. 147 func (p *FakeStoragePool) CreateStorageVol(def *libvirtxml.StorageVolume) (virt.StorageVolume, error) { 148 p.rec.Rec("CreateStorageVol", mustMarshal(def)) 149 return p.createStorageVol(def) 150 } 151 152 // ListVolumes implements ListVolumes method of StoragePool interface. 153 func (p *FakeStoragePool) ListVolumes() ([]virt.StorageVolume, error) { 154 r := make([]virt.StorageVolume, len(p.volumes)) 155 names := make([]string, 0, len(p.volumes)) 156 for name := range p.volumes { 157 names = append(names, name) 158 } 159 sort.Strings(names) 160 for n, name := range names { 161 r[n] = p.volumes[name] 162 } 163 return r, nil 164 } 165 166 // LookupVolumeByName implements LookupVolumeByName method of StoragePool interface. 167 func (p *FakeStoragePool) LookupVolumeByName(name string) (virt.StorageVolume, error) { 168 if v, found := p.volumes[name]; found { 169 return v, nil 170 } 171 return nil, virt.ErrStorageVolumeNotFound 172 } 173 174 func (p *FakeStoragePool) removeVolumeByName(name string) error { 175 if _, found := p.volumes[name]; !found { 176 return nil 177 } 178 delete(p.volumes, name) 179 return nil 180 } 181 182 // RemoveVolumeByName implements RemoveVolumeByName method of StoragePool interface. 183 func (p *FakeStoragePool) RemoveVolumeByName(name string) error { 184 p.rec.Rec("RemoveVolumeByName", name) 185 return p.removeVolumeByName(name) 186 } 187 188 // XML implements XML method of StoragePool interface. 189 func (p *FakeStoragePool) XML() (*libvirtxml.StoragePool, error) { 190 return p.def, nil 191 } 192 193 // FakeStorageVolume is a fake implementation of StorageVolume interface. 194 type FakeStorageVolume struct { 195 rec testutils.Recorder 196 pool *FakeStoragePool 197 name string 198 path string 199 size uint64 200 def *libvirtxml.StorageVolume 201 } 202 203 func newFakeStorageVolume(rec testutils.Recorder, pool *FakeStoragePool, def *libvirtxml.StorageVolume) (*FakeStorageVolume, error) { 204 volPath := "" 205 if def.Target != nil { 206 volPath = def.Target.Path 207 } 208 if volPath == "" { 209 volPath = path.Join(pool.path, def.Name) 210 } 211 212 v := &FakeStorageVolume{ 213 rec: rec, 214 pool: pool, 215 name: def.Name, 216 path: volPath, 217 def: def, 218 } 219 if def.Capacity != nil { 220 coef, found := capacityUnits[def.Capacity.Unit] 221 if !found { 222 return nil, fmt.Errorf("bad capacity units: %q", def.Capacity.Unit) 223 } 224 v.size = def.Capacity.Value * coef 225 } 226 227 return v, nil 228 } 229 230 func (v *FakeStorageVolume) descriptiveName() string { 231 return v.pool.name + "." + v.name 232 } 233 234 // Name implements Name method of StorageVolume interface. 235 func (v *FakeStorageVolume) Name() string { 236 return v.name 237 } 238 239 // Size implements Size method of StorageVolume interface. 240 func (v *FakeStorageVolume) Size() (uint64, error) { 241 return v.size, nil 242 } 243 244 // Path implements Path method of StorageVolume interface. 245 func (v *FakeStorageVolume) Path() (string, error) { 246 return v.path, nil 247 } 248 249 // Remove implements Remove method of StorageVolume interface. 250 func (v *FakeStorageVolume) Remove() error { 251 v.rec.Rec("Remove", nil) 252 return v.pool.removeVolumeByName(v.name) 253 } 254 255 // Format implements Format method of StorageVolume interface. 256 func (v *FakeStorageVolume) Format() error { 257 v.rec.Rec("Format", nil) 258 return nil 259 } 260 261 // XML implements XML method of StorageVolume interface. 262 func (v *FakeStorageVolume) XML() (*libvirtxml.StorageVolume, error) { 263 return v.def, nil 264 }