github.com/mirantis/virtlet@v1.5.2-0.20191204181327-1659b8a48e9b/pkg/libvirttools/root_volumesource_test.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 libvirttools
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  
    23  	libvirtxml "github.com/libvirt/libvirt-go-xml"
    24  	digest "github.com/opencontainers/go-digest"
    25  
    26  	"github.com/Mirantis/virtlet/pkg/fs"
    27  	"github.com/Mirantis/virtlet/pkg/metadata/types"
    28  	"github.com/Mirantis/virtlet/pkg/utils"
    29  	fakeutils "github.com/Mirantis/virtlet/pkg/utils/fake"
    30  	testutils "github.com/Mirantis/virtlet/pkg/utils/testing"
    31  	"github.com/Mirantis/virtlet/pkg/virt"
    32  	"github.com/Mirantis/virtlet/pkg/virt/fake"
    33  	"github.com/Mirantis/virtlet/tests/gm"
    34  )
    35  
    36  const (
    37  	testUUID                 = "77f29a0e-46af-4188-a6af-9ff8b8a65224"
    38  	fakeImageVirtualSize     = 424242
    39  	fakeImageStoreUsedBytes  = 424242
    40  	fakeImageStoreUsedInodes = 424242
    41  	fakeImageDigest          = digest.Digest("sha256:c3ab8ff13720e8ad9047dd39466b3c8974e592c2fa383d4a3960714caef0c4f2")
    42  )
    43  
    44  type fakeImageSpec struct {
    45  	name   string
    46  	path   string
    47  	digest digest.Digest
    48  	size   uint64
    49  }
    50  
    51  type fakeImageManager struct {
    52  	rec      testutils.Recorder
    53  	imageMap map[string]fakeImageSpec
    54  }
    55  
    56  var _ ImageManager = &fakeImageManager{}
    57  
    58  func newFakeImageManager(rec testutils.Recorder, extraImages ...fakeImageSpec) *fakeImageManager {
    59  	m := make(map[string]fakeImageSpec)
    60  	for _, img := range append(extraImages, fakeImageSpec{
    61  		name:   "fake/image1",
    62  		path:   "/fake/volume/path",
    63  		digest: fakeImageDigest,
    64  		size:   fakeImageVirtualSize,
    65  	}) {
    66  		m[img.name] = img
    67  	}
    68  	return &fakeImageManager{
    69  		rec:      rec,
    70  		imageMap: m,
    71  	}
    72  }
    73  
    74  func (im *fakeImageManager) GetImagePathDigestAndVirtualSize(imageName string) (string, digest.Digest, uint64, error) {
    75  	im.rec.Rec("GetImagePathDigestAndVirtualSize", imageName)
    76  	spec, found := im.imageMap[imageName]
    77  	if !found {
    78  		return "", "", 0, fmt.Errorf("image %q not found", imageName)
    79  	}
    80  	return spec.path, spec.digest, spec.size, nil
    81  }
    82  
    83  func (im *fakeImageManager) FilesystemStats() (*types.FilesystemStats, error) {
    84  	return &types.FilesystemStats{
    85  		Mountpoint: "/some/dir",
    86  		UsedBytes:  fakeImageStoreUsedBytes,
    87  		UsedInodes: fakeImageStoreUsedInodes,
    88  	}, nil
    89  }
    90  
    91  func (im *fakeImageManager) BytesUsedBy(path string) (uint64, error) {
    92  	im.rec.Rec("BytesUsedBy", path)
    93  	return fakeImageVirtualSize, nil
    94  }
    95  
    96  func TestRootVolumeNaming(t *testing.T) {
    97  	v := rootVolume{
    98  		volumeBase{
    99  			&types.VMConfig{DomainUUID: testUUID},
   100  			nil,
   101  		},
   102  	}
   103  	expected := "virtlet_root_" + testUUID
   104  	volumeName := v.volumeName()
   105  	if volumeName != expected {
   106  		t.Errorf("Incorrect root volume image name. Expected %s, received %s", expected, volumeName)
   107  	}
   108  }
   109  
   110  func getRootVolumeForTest(t *testing.T, vmConfig *types.VMConfig) (*rootVolume, *testutils.TopLevelRecorder, *fake.FakeStoragePool) {
   111  	rec := testutils.NewToplevelRecorder()
   112  	volumesPoolPath := "/fake/volumes/pool"
   113  	sc := fake.NewFakeStorageConnection(rec)
   114  	spool, err := sc.CreateStoragePool(&libvirtxml.StoragePool{
   115  		Name:   "volumes",
   116  		Target: &libvirtxml.StoragePoolTarget{Path: volumesPoolPath},
   117  	})
   118  	if err != nil {
   119  		t.Fatalf("CreateStoragePool(): %v", err)
   120  	}
   121  	im := newFakeImageManager(rec.Child("image"))
   122  
   123  	volumes, err := GetRootVolume(
   124  		vmConfig,
   125  		newFakeVolumeOwner(sc, spool.(*fake.FakeStoragePool), im, fakeutils.NewCommander(nil, nil)))
   126  	if err != nil {
   127  		t.Fatalf("GetRootVolume returned an error: %v", err)
   128  	}
   129  
   130  	if len(volumes) != 1 {
   131  		t.Fatalf("GetRootVolumes returned non single number of volumes: %d", len(volumes))
   132  	}
   133  
   134  	return volumes[0].(*rootVolume), rec, spool.(*fake.FakeStoragePool)
   135  }
   136  
   137  func TestRootVolumeSize(t *testing.T) {
   138  	for _, tc := range []struct {
   139  		name                    string
   140  		specifiedRootVolumeSize int64
   141  		expectedVolumeSize      int64
   142  	}{
   143  		{
   144  			name:                    "default (zero)",
   145  			specifiedRootVolumeSize: 0,
   146  			expectedVolumeSize:      fakeImageVirtualSize,
   147  		},
   148  		{
   149  			name:                    "negative",
   150  			specifiedRootVolumeSize: -1,
   151  			expectedVolumeSize:      fakeImageVirtualSize,
   152  		},
   153  		{
   154  			name:                    "smaller than fakeImageVirtualSize",
   155  			specifiedRootVolumeSize: fakeImageVirtualSize - 10,
   156  			expectedVolumeSize:      fakeImageVirtualSize,
   157  		},
   158  		{
   159  			name:                    "same as fakeImageVirtualSize",
   160  			specifiedRootVolumeSize: fakeImageVirtualSize,
   161  			expectedVolumeSize:      fakeImageVirtualSize,
   162  		},
   163  		{
   164  			name:                    "greater than fakeImageVirtualSize",
   165  			specifiedRootVolumeSize: fakeImageVirtualSize + 10,
   166  			expectedVolumeSize:      fakeImageVirtualSize + 10,
   167  		},
   168  	} {
   169  		t.Run(tc.name, func(t *testing.T) {
   170  			rootVol, rec, spool := getRootVolumeForTest(t, &types.VMConfig{
   171  				DomainUUID: testUUID,
   172  				Image:      "fake/image1",
   173  				ParsedAnnotations: &types.VirtletAnnotations{
   174  					RootVolumeSize: tc.specifiedRootVolumeSize,
   175  				},
   176  			})
   177  
   178  			_, _, err := rootVol.Setup()
   179  			if err != nil {
   180  				t.Fatalf("Setup returned an error: %v", err)
   181  			}
   182  
   183  			virtVol, err := spool.LookupVolumeByName(rootVol.volumeName())
   184  			if err != nil {
   185  				t.Fatalf("couldn't find volume %q", rootVol.volumeName())
   186  			}
   187  
   188  			size, err := virtVol.Size()
   189  			if err != nil {
   190  				t.Fatalf("couldn't get virt volume size: %v", err)
   191  			}
   192  
   193  			if int64(size) != tc.expectedVolumeSize {
   194  				t.Errorf("bad volume size %d instead of %d", size, tc.expectedVolumeSize)
   195  			}
   196  			gm.Verify(t, gm.NewYamlVerifier(rec.Content()))
   197  		})
   198  	}
   199  }
   200  
   201  func TestRootVolumeLifeCycle(t *testing.T) {
   202  	expectedRootVolumePath := "/fake/volumes/pool/virtlet_root_" + testUUID
   203  	rootVol, rec, _ := getRootVolumeForTest(t, &types.VMConfig{
   204  		DomainUUID:        testUUID,
   205  		Image:             "fake/image1",
   206  		ParsedAnnotations: &types.VirtletAnnotations{},
   207  	})
   208  
   209  	vol, fs, err := rootVol.Setup()
   210  	if err != nil {
   211  		t.Fatalf("Setup returned an error: %v", err)
   212  	}
   213  
   214  	if fs != nil {
   215  		t.Errorf("Didn't expect a filesystem")
   216  	}
   217  
   218  	if vol.Source.File == nil {
   219  		t.Errorf("Expected 'file' volume type")
   220  	}
   221  
   222  	if vol.Device != "disk" {
   223  		t.Errorf("Expected 'disk' as volume device, received: %s", vol.Device)
   224  	}
   225  
   226  	if vol.Source.File.File != expectedRootVolumePath {
   227  		t.Errorf("Expected '%s' as root volume path, received: %s", expectedRootVolumePath, vol.Source.File)
   228  	}
   229  
   230  	out, err := vol.Marshal()
   231  	if err != nil {
   232  		t.Fatalf("error marshalling the volume: %v", err)
   233  	}
   234  	rec.Rec("root disk retuned by virtlet_root_volumesource", out)
   235  
   236  	if err := rootVol.Teardown(); err != nil {
   237  		t.Errorf("Teardown returned an error: %v", err)
   238  	}
   239  
   240  	gm.Verify(t, gm.NewYamlVerifier(rec.Content()))
   241  }
   242  
   243  func TestRootVolumeFiles(t *testing.T) {
   244  	rootVol, rec, _ := getRootVolumeForTest(t, &types.VMConfig{
   245  		DomainUUID: testUUID,
   246  		Image:      "fake/image1",
   247  		ParsedAnnotations: &types.VirtletAnnotations{
   248  			InjectedFiles: map[string][]byte{
   249  				"/foo/bar.txt": []byte("bar"),
   250  				"/foo/baz.txt": []byte("baz"),
   251  			},
   252  		},
   253  	})
   254  
   255  	_, _, err := rootVol.Setup()
   256  	if err != nil {
   257  		t.Fatalf("Setup returned an error: %v", err)
   258  	}
   259  
   260  	gm.Verify(t, gm.NewYamlVerifier(rec.Content()))
   261  }
   262  
   263  type fakeVolumeOwner struct {
   264  	sc           *fake.FakeStorageConnection
   265  	storagePool  *fake.FakeStoragePool
   266  	imageManager *fakeImageManager
   267  	commander    *fakeutils.Commander
   268  }
   269  
   270  var _ volumeOwner = fakeVolumeOwner{}
   271  
   272  func newFakeVolumeOwner(sc *fake.FakeStorageConnection, storagePool *fake.FakeStoragePool, imageManager *fakeImageManager, commander *fakeutils.Commander) *fakeVolumeOwner {
   273  	return &fakeVolumeOwner{
   274  		sc:           sc,
   275  		storagePool:  storagePool,
   276  		imageManager: imageManager,
   277  		commander:    commander,
   278  	}
   279  }
   280  
   281  func (vo fakeVolumeOwner) StoragePool() (virt.StoragePool, error) {
   282  	return vo.storagePool, nil
   283  }
   284  
   285  func (vo fakeVolumeOwner) DomainConnection() virt.DomainConnection {
   286  	return nil
   287  }
   288  
   289  func (vo fakeVolumeOwner) StorageConnection() virt.StorageConnection {
   290  	return vo.sc
   291  }
   292  
   293  func (vo fakeVolumeOwner) ImageManager() ImageManager {
   294  	return vo.imageManager
   295  }
   296  
   297  func (vo fakeVolumeOwner) RawDevices() []string { return nil }
   298  
   299  func (vo fakeVolumeOwner) KubeletRootDir() string { return "" }
   300  
   301  func (vo fakeVolumeOwner) VolumePoolName() string { return "" }
   302  
   303  func (vo fakeVolumeOwner) FileSystem() fs.FileSystem { return fs.NullFileSystem }
   304  
   305  func (vo fakeVolumeOwner) SharedFilesystemPath() string { return "/var/lib/virtlet/fs" }
   306  
   307  func (vo fakeVolumeOwner) Commander() utils.Commander { return vo.commander }