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 }