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  }