gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/pkg/katautils/config_test.go (about) 1 // Copyright (c) 2018 Intel Corporation 2 // Copyright (c) 2018 HyperHQ Inc. 3 // 4 // SPDX-License-Identifier: Apache-2.0 5 // 6 7 package katautils 8 9 import ( 10 "bytes" 11 "fmt" 12 "io/ioutil" 13 "os" 14 "path" 15 "path/filepath" 16 "reflect" 17 goruntime "runtime" 18 "strings" 19 "syscall" 20 "testing" 21 22 ktu "github.com/kata-containers/runtime/pkg/katatestutils" 23 vc "github.com/kata-containers/runtime/virtcontainers" 24 "github.com/kata-containers/runtime/virtcontainers/pkg/oci" 25 "github.com/kata-containers/runtime/virtcontainers/utils" 26 "github.com/stretchr/testify/assert" 27 ) 28 29 var ( 30 hypervisorDebug = false 31 proxyDebug = false 32 runtimeDebug = false 33 runtimeTrace = false 34 shimDebug = false 35 netmonDebug = false 36 agentDebug = false 37 agentTrace = false 38 ) 39 40 type testRuntimeConfig struct { 41 RuntimeConfig oci.RuntimeConfig 42 RuntimeConfigFile string 43 ConfigPath string 44 ConfigPathLink string 45 LogDir string 46 LogPath string 47 } 48 49 func createConfig(configPath string, fileData string) error { 50 51 err := ioutil.WriteFile(configPath, []byte(fileData), testFileMode) 52 if err != nil { 53 fmt.Fprintf(os.Stderr, "Unable to create config file %s %v\n", configPath, err) 54 return err 55 } 56 57 return nil 58 } 59 60 // createAllRuntimeConfigFiles creates all files necessary to call 61 // loadConfiguration(). 62 func createAllRuntimeConfigFiles(dir, hypervisor string) (config testRuntimeConfig, err error) { 63 if dir == "" { 64 return config, fmt.Errorf("BUG: need directory") 65 } 66 67 if hypervisor == "" { 68 return config, fmt.Errorf("BUG: need hypervisor") 69 } 70 71 hypervisorPath := path.Join(dir, "hypervisor") 72 kernelPath := path.Join(dir, "kernel") 73 kernelParams := "foo=bar xyz" 74 imagePath := path.Join(dir, "image") 75 shimPath := path.Join(dir, "shim") 76 proxyPath := path.Join(dir, "proxy") 77 netmonPath := path.Join(dir, "netmon") 78 logDir := path.Join(dir, "logs") 79 logPath := path.Join(logDir, "runtime.log") 80 machineType := "machineType" 81 disableBlockDevice := true 82 blockDeviceDriver := "virtio-scsi" 83 enableIOThreads := true 84 hotplugVFIOOnRootBus := true 85 pcieRootPort := uint32(2) 86 disableNewNetNs := false 87 sharedFS := "virtio-9p" 88 89 configFileOptions := ktu.RuntimeConfigOptions{ 90 Hypervisor: "qemu", 91 HypervisorPath: hypervisorPath, 92 KernelPath: kernelPath, 93 ImagePath: imagePath, 94 KernelParams: kernelParams, 95 MachineType: machineType, 96 ShimPath: shimPath, 97 ProxyPath: proxyPath, 98 NetmonPath: netmonPath, 99 LogPath: logPath, 100 DefaultGuestHookPath: defaultGuestHookPath, 101 DisableBlock: disableBlockDevice, 102 BlockDeviceDriver: blockDeviceDriver, 103 EnableIOThreads: enableIOThreads, 104 HotplugVFIOOnRootBus: hotplugVFIOOnRootBus, 105 PCIeRootPort: pcieRootPort, 106 DisableNewNetNs: disableNewNetNs, 107 DefaultVCPUCount: defaultVCPUCount, 108 DefaultMaxVCPUCount: defaultMaxVCPUCount, 109 DefaultMemSize: defaultMemSize, 110 DefaultMsize9p: defaultMsize9p, 111 HypervisorDebug: hypervisorDebug, 112 RuntimeDebug: runtimeDebug, 113 RuntimeTrace: runtimeTrace, 114 ProxyDebug: proxyDebug, 115 ShimDebug: shimDebug, 116 NetmonDebug: netmonDebug, 117 AgentDebug: agentDebug, 118 AgentTrace: agentTrace, 119 SharedFS: sharedFS, 120 } 121 122 runtimeConfigFileData := ktu.MakeRuntimeConfigFileData(configFileOptions) 123 124 configPath := path.Join(dir, "runtime.toml") 125 err = createConfig(configPath, runtimeConfigFileData) 126 if err != nil { 127 return config, err 128 } 129 130 configPathLink := path.Join(filepath.Dir(configPath), "link-to-configuration.toml") 131 132 // create a link to the config file 133 err = syscall.Symlink(configPath, configPathLink) 134 if err != nil { 135 return config, err 136 } 137 138 files := []string{hypervisorPath, kernelPath, imagePath, shimPath, proxyPath} 139 140 for _, file := range files { 141 // create the resource (which must be >0 bytes) 142 err := WriteFile(file, "foo", testFileMode) 143 if err != nil { 144 return config, err 145 } 146 } 147 148 hypervisorConfig := vc.HypervisorConfig{ 149 HypervisorPath: hypervisorPath, 150 KernelPath: kernelPath, 151 ImagePath: imagePath, 152 KernelParams: vc.DeserializeParams(strings.Fields(kernelParams)), 153 HypervisorMachineType: machineType, 154 NumVCPUs: defaultVCPUCount, 155 DefaultMaxVCPUs: uint32(goruntime.NumCPU()), 156 MemorySize: defaultMemSize, 157 DisableBlockDeviceUse: disableBlockDevice, 158 BlockDeviceDriver: defaultBlockDeviceDriver, 159 DefaultBridges: defaultBridgesCount, 160 Mlock: !defaultEnableSwap, 161 EnableIOThreads: enableIOThreads, 162 HotplugVFIOOnRootBus: hotplugVFIOOnRootBus, 163 PCIeRootPort: pcieRootPort, 164 Msize9p: defaultMsize9p, 165 MemSlots: defaultMemSlots, 166 EntropySource: defaultEntropySource, 167 GuestHookPath: defaultGuestHookPath, 168 VhostUserStorePath: defaultVhostUserStorePath, 169 SharedFS: sharedFS, 170 VirtioFSDaemon: "/path/to/virtiofsd", 171 VirtioFSCache: defaultVirtioFSCacheMode, 172 } 173 174 agentConfig := vc.KataAgentConfig{} 175 176 proxyConfig := vc.ProxyConfig{ 177 Path: proxyPath, 178 } 179 180 shimConfig := vc.ShimConfig{ 181 Path: shimPath, 182 } 183 184 netmonConfig := vc.NetmonConfig{ 185 Path: netmonPath, 186 Debug: false, 187 Enable: false, 188 } 189 190 factoryConfig := oci.FactoryConfig{ 191 TemplatePath: defaultTemplatePath, 192 VMCacheEndpoint: defaultVMCacheEndpoint, 193 } 194 195 runtimeConfig := oci.RuntimeConfig{ 196 HypervisorType: defaultHypervisor, 197 HypervisorConfig: hypervisorConfig, 198 199 AgentType: defaultAgent, 200 AgentConfig: agentConfig, 201 202 ProxyType: defaultProxy, 203 ProxyConfig: proxyConfig, 204 205 ShimType: defaultShim, 206 ShimConfig: shimConfig, 207 208 NetmonConfig: netmonConfig, 209 DisableNewNetNs: disableNewNetNs, 210 211 FactoryConfig: factoryConfig, 212 } 213 214 err = SetKernelParams(&runtimeConfig) 215 if err != nil { 216 return config, err 217 } 218 219 config = testRuntimeConfig{ 220 RuntimeConfig: runtimeConfig, 221 RuntimeConfigFile: configPath, 222 ConfigPath: configPath, 223 ConfigPathLink: configPathLink, 224 LogDir: logDir, 225 LogPath: logPath, 226 } 227 228 return config, nil 229 } 230 231 // testLoadConfiguration accepts an optional function that can be used 232 // to modify the test: if a function is specified, it indicates if the 233 // subsequent call to loadConfiguration() is expected to fail by 234 // returning a bool. If the function itself fails, that is considered an 235 // error. 236 func testLoadConfiguration(t *testing.T, dir string, 237 fn func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error)) { 238 subDir := path.Join(dir, "test") 239 240 for _, hypervisor := range []string{"qemu"} { 241 Loop: 242 for _, ignoreLogging := range []bool{true, false} { 243 err := os.RemoveAll(subDir) 244 assert.NoError(t, err) 245 246 err = os.MkdirAll(subDir, testDirMode) 247 assert.NoError(t, err) 248 249 testConfig, err := createAllRuntimeConfigFiles(subDir, hypervisor) 250 assert.NoError(t, err) 251 252 configFiles := []string{testConfig.ConfigPath, testConfig.ConfigPathLink, ""} 253 254 // override 255 defaultRuntimeConfiguration = testConfig.ConfigPath 256 defaultSysConfRuntimeConfiguration = "" 257 258 for _, file := range configFiles { 259 var err error 260 expectFail := false 261 262 if fn != nil { 263 expectFail, err = fn(testConfig, file, ignoreLogging) 264 assert.NoError(t, err) 265 } 266 267 resolvedConfigPath, config, err := LoadConfiguration(file, ignoreLogging, false) 268 if expectFail { 269 assert.Error(t, err) 270 271 // no point proceeding in the error scenario. 272 break Loop 273 } else { 274 assert.NoError(t, err) 275 } 276 277 if file == "" { 278 assert.Equal(t, defaultRuntimeConfiguration, resolvedConfigPath) 279 } else { 280 assert.Equal(t, testConfig.ConfigPath, resolvedConfigPath) 281 } 282 283 assert.Equal(t, defaultRuntimeConfiguration, resolvedConfigPath) 284 result := reflect.DeepEqual(config, testConfig.RuntimeConfig) 285 if !result { 286 t.Fatalf("Expected\n%+v\nGot\n%+v", config, testConfig.RuntimeConfig) 287 } 288 assert.True(t, result) 289 290 err = os.RemoveAll(testConfig.LogDir) 291 assert.NoError(t, err) 292 } 293 } 294 } 295 } 296 297 func TestConfigLoadConfiguration(t *testing.T) { 298 tmpdir, err := ioutil.TempDir(testDir, "load-config-") 299 assert.NoError(t, err) 300 defer os.RemoveAll(tmpdir) 301 302 testLoadConfiguration(t, tmpdir, nil) 303 } 304 305 func TestConfigLoadConfigurationFailBrokenSymLink(t *testing.T) { 306 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 307 assert.NoError(t, err) 308 defer os.RemoveAll(tmpdir) 309 310 testLoadConfiguration(t, tmpdir, 311 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 312 expectFail := false 313 314 if configFile == config.ConfigPathLink { 315 // break the symbolic link 316 err = os.Remove(config.ConfigPathLink) 317 if err != nil { 318 return expectFail, err 319 } 320 321 expectFail = true 322 } 323 324 return expectFail, nil 325 }) 326 } 327 328 func TestConfigLoadConfigurationFailSymLinkLoop(t *testing.T) { 329 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 330 assert.NoError(t, err) 331 defer os.RemoveAll(tmpdir) 332 333 testLoadConfiguration(t, tmpdir, 334 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 335 expectFail := false 336 337 if configFile == config.ConfigPathLink { 338 // remove the config file 339 err = os.Remove(config.ConfigPath) 340 if err != nil { 341 return expectFail, err 342 } 343 344 // now, create a sym-link loop 345 err := os.Symlink(config.ConfigPathLink, config.ConfigPath) 346 if err != nil { 347 return expectFail, err 348 } 349 350 expectFail = true 351 } 352 353 return expectFail, nil 354 }) 355 } 356 357 func TestConfigLoadConfigurationFailMissingHypervisor(t *testing.T) { 358 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 359 assert.NoError(t, err) 360 defer os.RemoveAll(tmpdir) 361 362 testLoadConfiguration(t, tmpdir, 363 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 364 expectFail := true 365 366 err = os.Remove(config.RuntimeConfig.HypervisorConfig.HypervisorPath) 367 if err != nil { 368 return expectFail, err 369 } 370 371 return expectFail, nil 372 }) 373 } 374 375 func TestConfigLoadConfigurationFailMissingImage(t *testing.T) { 376 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 377 assert.NoError(t, err) 378 defer os.RemoveAll(tmpdir) 379 380 testLoadConfiguration(t, tmpdir, 381 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 382 expectFail := true 383 384 err = os.Remove(config.RuntimeConfig.HypervisorConfig.ImagePath) 385 if err != nil { 386 return expectFail, err 387 } 388 389 return expectFail, nil 390 }) 391 } 392 393 func TestConfigLoadConfigurationFailMissingKernel(t *testing.T) { 394 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 395 assert.NoError(t, err) 396 defer os.RemoveAll(tmpdir) 397 398 testLoadConfiguration(t, tmpdir, 399 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 400 expectFail := true 401 402 err = os.Remove(config.RuntimeConfig.HypervisorConfig.KernelPath) 403 if err != nil { 404 return expectFail, err 405 } 406 407 return expectFail, nil 408 }) 409 } 410 411 func TestConfigLoadConfigurationFailMissingShim(t *testing.T) { 412 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 413 assert.NoError(t, err) 414 defer os.RemoveAll(tmpdir) 415 416 testLoadConfiguration(t, tmpdir, 417 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 418 expectFail := true 419 420 shimConfig, ok := config.RuntimeConfig.ShimConfig.(vc.ShimConfig) 421 if !ok { 422 return expectFail, fmt.Errorf("cannot determine shim config") 423 } 424 err = os.Remove(shimConfig.Path) 425 if err != nil { 426 return expectFail, err 427 } 428 429 return expectFail, nil 430 }) 431 } 432 433 func TestConfigLoadConfigurationFailUnreadableConfig(t *testing.T) { 434 if tc.NotValid(ktu.NeedNonRoot()) { 435 t.Skip(ktu.TestDisabledNeedNonRoot) 436 } 437 438 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 439 assert.NoError(t, err) 440 defer os.RemoveAll(tmpdir) 441 442 testLoadConfiguration(t, tmpdir, 443 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 444 expectFail := true 445 446 // make file unreadable by non-root user 447 err = os.Chmod(config.ConfigPath, 0000) 448 if err != nil { 449 return expectFail, err 450 } 451 452 return expectFail, nil 453 }) 454 } 455 456 func TestConfigLoadConfigurationFailTOMLConfigFileInvalidContents(t *testing.T) { 457 if tc.NotValid(ktu.NeedNonRoot()) { 458 t.Skip(ktu.TestDisabledNeedNonRoot) 459 } 460 461 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 462 assert.NoError(t, err) 463 defer os.RemoveAll(tmpdir) 464 465 testLoadConfiguration(t, tmpdir, 466 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 467 expectFail := true 468 469 err := createFile(config.ConfigPath, 470 `<?xml version="1.0"?> 471 <foo>I am not TOML! ;-)</foo> 472 <bar>I am invalid XML!`) 473 474 if err != nil { 475 return expectFail, err 476 } 477 478 return expectFail, nil 479 }) 480 } 481 482 func TestConfigLoadConfigurationFailTOMLConfigFileDuplicatedData(t *testing.T) { 483 if tc.NotValid(ktu.NeedNonRoot()) { 484 t.Skip(ktu.TestDisabledNeedNonRoot) 485 } 486 487 tmpdir, err := ioutil.TempDir(testDir, "runtime-config-") 488 assert.NoError(t, err) 489 defer os.RemoveAll(tmpdir) 490 491 testLoadConfiguration(t, tmpdir, 492 func(config testRuntimeConfig, configFile string, ignoreLogging bool) (bool, error) { 493 expectFail := true 494 495 text, err := GetFileContents(config.ConfigPath) 496 if err != nil { 497 return expectFail, err 498 } 499 500 // create a config file containing two sets of 501 // data. 502 err = createFile(config.ConfigPath, fmt.Sprintf("%s\n%s\n", text, text)) 503 if err != nil { 504 return expectFail, err 505 } 506 507 return expectFail, nil 508 }) 509 } 510 511 func TestMinimalRuntimeConfig(t *testing.T) { 512 dir, err := ioutil.TempDir(testDir, "minimal-runtime-config-") 513 if err != nil { 514 t.Fatal(err) 515 } 516 defer os.RemoveAll(dir) 517 518 shimPath := path.Join(dir, "shim") 519 proxyPath := path.Join(dir, "proxy") 520 hypervisorPath := path.Join(dir, "hypervisor") 521 defaultHypervisorPath = hypervisorPath 522 jailerPath := path.Join(dir, "jailer") 523 defaultJailerPath = jailerPath 524 netmonPath := path.Join(dir, "netmon") 525 526 imagePath := path.Join(dir, "image.img") 527 initrdPath := path.Join(dir, "initrd.img") 528 529 kernelPath := path.Join(dir, "kernel") 530 531 savedDefaultImagePath := defaultImagePath 532 savedDefaultInitrdPath := defaultInitrdPath 533 savedDefaultHypervisorPath := defaultHypervisorPath 534 savedDefaultJailerPath := defaultJailerPath 535 savedDefaultKernelPath := defaultKernelPath 536 537 defer func() { 538 defaultImagePath = savedDefaultImagePath 539 defaultInitrdPath = savedDefaultInitrdPath 540 defaultHypervisorPath = savedDefaultHypervisorPath 541 defaultJailerPath = savedDefaultJailerPath 542 defaultKernelPath = savedDefaultKernelPath 543 }() 544 545 // Temporarily change the defaults to avoid this test using the real 546 // resource files that might be installed on the system! 547 defaultImagePath = imagePath 548 defaultInitrdPath = initrdPath 549 defaultHypervisorPath = hypervisorPath 550 defaultJailerPath = jailerPath 551 defaultKernelPath = kernelPath 552 553 for _, file := range []string{defaultImagePath, defaultInitrdPath, defaultHypervisorPath, defaultJailerPath, defaultKernelPath} { 554 err = WriteFile(file, "foo", testFileMode) 555 if err != nil { 556 t.Fatal(err) 557 } 558 } 559 560 runtimeMinimalConfig := ` 561 # Runtime configuration file 562 563 [proxy.kata] 564 path = "` + proxyPath + `" 565 566 [shim.kata] 567 path = "` + shimPath + `" 568 569 [agent.kata] 570 571 [netmon] 572 path = "` + netmonPath + `" 573 ` 574 575 configPath := path.Join(dir, "runtime.toml") 576 err = createConfig(configPath, runtimeMinimalConfig) 577 if err != nil { 578 t.Fatal(err) 579 } 580 581 _, config, err := LoadConfiguration(configPath, false, false) 582 if err == nil { 583 t.Fatalf("Expected loadConfiguration to fail as shim path does not exist: %+v", config) 584 } 585 586 err = createEmptyFile(shimPath) 587 if err != nil { 588 t.Error(err) 589 } 590 591 err = createEmptyFile(proxyPath) 592 if err != nil { 593 t.Error(err) 594 } 595 596 err = createEmptyFile(hypervisorPath) 597 if err != nil { 598 t.Error(err) 599 } 600 601 err = createEmptyFile(jailerPath) 602 if err != nil { 603 t.Error(err) 604 } 605 606 err = createEmptyFile(netmonPath) 607 if err != nil { 608 t.Error(err) 609 } 610 611 _, config, err = LoadConfiguration(configPath, false, false) 612 if err != nil { 613 t.Fatal(err) 614 } 615 616 expectedHypervisorConfig := vc.HypervisorConfig{ 617 HypervisorPath: defaultHypervisorPath, 618 JailerPath: defaultJailerPath, 619 KernelPath: defaultKernelPath, 620 ImagePath: defaultImagePath, 621 InitrdPath: defaultInitrdPath, 622 HypervisorMachineType: defaultMachineType, 623 NumVCPUs: defaultVCPUCount, 624 DefaultMaxVCPUs: defaultMaxVCPUCount, 625 MemorySize: defaultMemSize, 626 DisableBlockDeviceUse: defaultDisableBlockDeviceUse, 627 DefaultBridges: defaultBridgesCount, 628 Mlock: !defaultEnableSwap, 629 BlockDeviceDriver: defaultBlockDeviceDriver, 630 Msize9p: defaultMsize9p, 631 GuestHookPath: defaultGuestHookPath, 632 VhostUserStorePath: defaultVhostUserStorePath, 633 VirtioFSCache: defaultVirtioFSCacheMode, 634 } 635 636 expectedAgentConfig := vc.KataAgentConfig{} 637 638 expectedProxyConfig := vc.ProxyConfig{ 639 Path: proxyPath, 640 } 641 642 expectedShimConfig := vc.ShimConfig{ 643 Path: shimPath, 644 } 645 646 expectedNetmonConfig := vc.NetmonConfig{ 647 Path: netmonPath, 648 Debug: false, 649 Enable: false, 650 } 651 652 expectedFactoryConfig := oci.FactoryConfig{ 653 TemplatePath: defaultTemplatePath, 654 VMCacheEndpoint: defaultVMCacheEndpoint, 655 } 656 657 expectedConfig := oci.RuntimeConfig{ 658 HypervisorType: defaultHypervisor, 659 HypervisorConfig: expectedHypervisorConfig, 660 661 AgentType: defaultAgent, 662 AgentConfig: expectedAgentConfig, 663 664 ProxyType: defaultProxy, 665 ProxyConfig: expectedProxyConfig, 666 667 ShimType: defaultShim, 668 ShimConfig: expectedShimConfig, 669 670 NetmonConfig: expectedNetmonConfig, 671 672 FactoryConfig: expectedFactoryConfig, 673 } 674 err = SetKernelParams(&expectedConfig) 675 if err != nil { 676 t.Fatal(err) 677 } 678 679 if reflect.DeepEqual(config, expectedConfig) == false { 680 t.Fatalf("Got %+v\n expecting %+v", config, expectedConfig) 681 } 682 } 683 684 func TestMinimalRuntimeConfigWithVsock(t *testing.T) { 685 dir, err := ioutil.TempDir(testDir, "minimal-runtime-config-") 686 if err != nil { 687 t.Fatal(err) 688 } 689 defer os.RemoveAll(dir) 690 691 imagePath := path.Join(dir, "image.img") 692 initrdPath := path.Join(dir, "initrd.img") 693 proxyPath := path.Join(dir, "proxy") 694 shimPath := path.Join(dir, "shim") 695 hypervisorPath := path.Join(dir, "hypervisor") 696 kernelPath := path.Join(dir, "kernel") 697 698 savedDefaultImagePath := defaultImagePath 699 savedDefaultInitrdPath := defaultInitrdPath 700 savedDefaultHypervisorPath := defaultHypervisorPath 701 savedDefaultKernelPath := defaultKernelPath 702 703 defer func() { 704 defaultImagePath = savedDefaultImagePath 705 defaultInitrdPath = savedDefaultInitrdPath 706 defaultHypervisorPath = savedDefaultHypervisorPath 707 defaultKernelPath = savedDefaultKernelPath 708 }() 709 710 // Temporarily change the defaults to avoid this test using the real 711 // resource files that might be installed on the system! 712 defaultImagePath = imagePath 713 defaultInitrdPath = initrdPath 714 defaultHypervisorPath = hypervisorPath 715 defaultKernelPath = kernelPath 716 717 for _, file := range []string{proxyPath, shimPath, hypervisorPath, kernelPath, imagePath} { 718 err = WriteFile(file, "foo", testFileMode) 719 if err != nil { 720 t.Fatal(err) 721 } 722 } 723 724 // minimal config with vsock enabled 725 runtimeMinimalConfig := ` 726 # Runtime configuration file 727 [hypervisor.qemu] 728 use_vsock = true 729 image = "` + imagePath + `" 730 731 [proxy.kata] 732 path = "` + proxyPath + `" 733 734 [shim.kata] 735 path = "` + shimPath + `" 736 737 [agent.kata] 738 ` 739 orgVHostVSockDevicePath := utils.VHostVSockDevicePath 740 defer func() { 741 utils.VHostVSockDevicePath = orgVHostVSockDevicePath 742 }() 743 utils.VHostVSockDevicePath = "/dev/null" 744 745 configPath := path.Join(dir, "runtime.toml") 746 err = createConfig(configPath, runtimeMinimalConfig) 747 if err != nil { 748 t.Fatal(err) 749 } 750 751 _, config, err := LoadConfiguration(configPath, false, false) 752 if err != nil { 753 t.Fatal(err) 754 } 755 756 if config.ProxyType != vc.NoProxyType { 757 t.Fatalf("Proxy type must be NoProxy, got %+v", config.ProxyType) 758 } 759 760 if !reflect.DeepEqual(config.ProxyConfig, vc.ProxyConfig{}) { 761 t.Fatalf("Got %+v\n expecting %+v", config.ProxyConfig, vc.ProxyConfig{}) 762 } 763 764 if config.HypervisorConfig.UseVSock != true { 765 t.Fatalf("use_vsock must be true, got %v", config.HypervisorConfig.UseVSock) 766 } 767 } 768 769 func TestNewQemuHypervisorConfig(t *testing.T) { 770 dir, err := ioutil.TempDir(testDir, "hypervisor-config-") 771 if err != nil { 772 t.Fatal(err) 773 } 774 defer os.RemoveAll(dir) 775 776 hypervisorPath := path.Join(dir, "hypervisor") 777 kernelPath := path.Join(dir, "kernel") 778 imagePath := path.Join(dir, "image") 779 machineType := "machineType" 780 disableBlock := true 781 enableIOThreads := true 782 hotplugVFIOOnRootBus := true 783 pcieRootPort := uint32(2) 784 orgVHostVSockDevicePath := utils.VHostVSockDevicePath 785 defer func() { 786 utils.VHostVSockDevicePath = orgVHostVSockDevicePath 787 }() 788 utils.VHostVSockDevicePath = "/dev/abc/xyz" 789 790 hypervisor := hypervisor{ 791 Path: hypervisorPath, 792 Kernel: kernelPath, 793 Image: imagePath, 794 MachineType: machineType, 795 DisableBlockDeviceUse: disableBlock, 796 EnableIOThreads: enableIOThreads, 797 HotplugVFIOOnRootBus: hotplugVFIOOnRootBus, 798 PCIeRootPort: pcieRootPort, 799 UseVSock: true, 800 } 801 802 files := []string{hypervisorPath, kernelPath, imagePath} 803 filesLen := len(files) 804 805 for i, file := range files { 806 _, err := newQemuHypervisorConfig(hypervisor) 807 if err == nil { 808 t.Fatalf("Expected newQemuHypervisorConfig to fail as not all paths exist (not created %v)", 809 strings.Join(files[i:filesLen], ",")) 810 } 811 812 // create the resource 813 err = createEmptyFile(file) 814 if err != nil { 815 t.Error(err) 816 } 817 } 818 819 // falling back to legacy serial port 820 config, err := newQemuHypervisorConfig(hypervisor) 821 if err != nil { 822 t.Fatal(err) 823 } 824 825 utils.VHostVSockDevicePath = "/dev/null" 826 827 // all paths exist now 828 config, err = newQemuHypervisorConfig(hypervisor) 829 if err != nil { 830 t.Fatal(err) 831 } 832 833 if config.HypervisorPath != hypervisor.Path { 834 t.Errorf("Expected hypervisor path %v, got %v", hypervisor.Path, config.HypervisorPath) 835 } 836 837 if config.KernelPath != hypervisor.Kernel { 838 t.Errorf("Expected kernel path %v, got %v", hypervisor.Kernel, config.KernelPath) 839 } 840 841 if config.ImagePath != hypervisor.Image { 842 t.Errorf("Expected image path %v, got %v", hypervisor.Image, config.ImagePath) 843 } 844 845 if config.DisableBlockDeviceUse != disableBlock { 846 t.Errorf("Expected value for disable block usage %v, got %v", disableBlock, config.DisableBlockDeviceUse) 847 } 848 849 if config.EnableIOThreads != enableIOThreads { 850 t.Errorf("Expected value for enable IOThreads %v, got %v", enableIOThreads, config.EnableIOThreads) 851 } 852 853 if config.HotplugVFIOOnRootBus != hotplugVFIOOnRootBus { 854 t.Errorf("Expected value for HotplugVFIOOnRootBus %v, got %v", hotplugVFIOOnRootBus, config.HotplugVFIOOnRootBus) 855 } 856 857 if config.PCIeRootPort != pcieRootPort { 858 t.Errorf("Expected value for PCIeRootPort %v, got %v", pcieRootPort, config.PCIeRootPort) 859 } 860 } 861 862 func TestNewQemuHypervisorConfigImageAndInitrd(t *testing.T) { 863 assert := assert.New(t) 864 865 tmpdir, err := ioutil.TempDir(testDir, "") 866 assert.NoError(err) 867 defer os.RemoveAll(tmpdir) 868 869 imagePath := filepath.Join(tmpdir, "image") 870 initrdPath := filepath.Join(tmpdir, "initrd") 871 hypervisorPath := path.Join(tmpdir, "hypervisor") 872 kernelPath := path.Join(tmpdir, "kernel") 873 874 for _, file := range []string{imagePath, initrdPath, hypervisorPath, kernelPath} { 875 err = createEmptyFile(file) 876 assert.NoError(err) 877 } 878 879 machineType := "machineType" 880 disableBlock := true 881 enableIOThreads := true 882 hotplugVFIOOnRootBus := true 883 pcieRootPort := uint32(2) 884 885 hypervisor := hypervisor{ 886 Path: hypervisorPath, 887 Kernel: kernelPath, 888 Image: imagePath, 889 Initrd: initrdPath, 890 MachineType: machineType, 891 DisableBlockDeviceUse: disableBlock, 892 EnableIOThreads: enableIOThreads, 893 HotplugVFIOOnRootBus: hotplugVFIOOnRootBus, 894 PCIeRootPort: pcieRootPort, 895 } 896 897 _, err = newQemuHypervisorConfig(hypervisor) 898 899 // specifying both an image+initrd is invalid 900 assert.Error(err) 901 } 902 903 func TestNewClhHypervisorConfig(t *testing.T) { 904 905 assert := assert.New(t) 906 907 tmpdir, err := ioutil.TempDir(testDir, "") 908 assert.NoError(err) 909 defer os.RemoveAll(tmpdir) 910 911 hypervisorPath := path.Join(tmpdir, "hypervisor") 912 kernelPath := path.Join(tmpdir, "kernel") 913 imagePath := path.Join(tmpdir, "image") 914 virtioFsDaemon := path.Join(tmpdir, "virtiofsd") 915 916 for _, file := range []string{imagePath, hypervisorPath, kernelPath, virtioFsDaemon} { 917 err = createEmptyFile(file) 918 assert.NoError(err) 919 } 920 921 hypervisor := hypervisor{ 922 Path: hypervisorPath, 923 Kernel: kernelPath, 924 Image: imagePath, 925 VirtioFSDaemon: virtioFsDaemon, 926 VirtioFSCache: "always", 927 } 928 config, err := newClhHypervisorConfig(hypervisor) 929 if err != nil { 930 t.Fatal(err) 931 } 932 933 if config.HypervisorPath != hypervisor.Path { 934 t.Errorf("Expected hypervisor path %v, got %v", hypervisor.Path, config.HypervisorPath) 935 } 936 937 if config.KernelPath != hypervisor.Kernel { 938 t.Errorf("Expected kernel path %v, got %v", hypervisor.Kernel, config.KernelPath) 939 } 940 941 if config.ImagePath != hypervisor.Image { 942 t.Errorf("Expected image path %v, got %v", hypervisor.Image, config.ImagePath) 943 } 944 945 if config.ImagePath != hypervisor.Image { 946 t.Errorf("Expected image path %v, got %v", hypervisor.Image, config.ImagePath) 947 } 948 949 if config.UseVSock != true { 950 t.Errorf("Expected UseVSock %v, got %v", true, config.UseVSock) 951 } 952 953 if config.DisableVhostNet != true { 954 t.Errorf("Expected DisableVhostNet %v, got %v", true, config.DisableVhostNet) 955 } 956 957 if config.VirtioFSCache != "always" { 958 t.Errorf("Expected VirtioFSCache %v, got %v", true, config.VirtioFSCache) 959 } 960 961 } 962 963 func TestNewShimConfig(t *testing.T) { 964 dir, err := ioutil.TempDir(testDir, "shim-config-") 965 if err != nil { 966 t.Fatal(err) 967 } 968 defer os.RemoveAll(dir) 969 970 shimPath := path.Join(dir, "shim") 971 972 shim := shim{ 973 Path: shimPath, 974 } 975 976 _, err = newShimConfig(shim) 977 if err == nil { 978 t.Fatalf("Expected newShimConfig to fail as no paths exist") 979 } 980 981 err = createEmptyFile(shimPath) 982 if err != nil { 983 t.Error(err) 984 } 985 986 shConfig, err := newShimConfig(shim) 987 if err != nil { 988 t.Fatalf("newShimConfig failed unexpectedly: %v", err) 989 } 990 991 if shConfig.Path != shimPath { 992 t.Errorf("Expected shim path %v, got %v", shimPath, shConfig.Path) 993 } 994 } 995 996 func TestHypervisorDefaults(t *testing.T) { 997 assert := assert.New(t) 998 999 numCPUs := goruntime.NumCPU() 1000 1001 h := hypervisor{} 1002 1003 assert.Equal(h.machineType(), defaultMachineType, "default hypervisor machine type wrong") 1004 assert.Equal(h.defaultVCPUs(), defaultVCPUCount, "default vCPU number is wrong") 1005 assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong") 1006 assert.Equal(h.defaultMemSz(), defaultMemSize, "default memory size is wrong") 1007 1008 machineType := "foo" 1009 h.MachineType = machineType 1010 assert.Equal(h.machineType(), machineType, "custom hypervisor machine type wrong") 1011 1012 // auto inferring 1013 h.NumVCPUs = -1 1014 assert.Equal(h.defaultVCPUs(), uint32(numCPUs), "default vCPU number is wrong") 1015 1016 h.NumVCPUs = 2 1017 assert.Equal(h.defaultVCPUs(), uint32(2), "default vCPU number is wrong") 1018 1019 h.NumVCPUs = int32(numCPUs) + 1 1020 assert.Equal(h.defaultVCPUs(), uint32(numCPUs), "default vCPU number is wrong") 1021 1022 h.DefaultMaxVCPUs = 2 1023 assert.Equal(h.defaultMaxVCPUs(), uint32(2), "default max vCPU number is wrong") 1024 1025 h.DefaultMaxVCPUs = uint32(numCPUs) + 1 1026 assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong") 1027 1028 maxvcpus := vc.MaxQemuVCPUs() 1029 h.DefaultMaxVCPUs = maxvcpus + 1 1030 assert.Equal(h.defaultMaxVCPUs(), uint32(numCPUs), "default max vCPU number is wrong") 1031 1032 h.MemorySize = 1024 1033 assert.Equal(h.defaultMemSz(), uint32(1024), "default memory size is wrong") 1034 } 1035 1036 func TestHypervisorDefaultsHypervisor(t *testing.T) { 1037 assert := assert.New(t) 1038 1039 tmpdir, err := ioutil.TempDir(testDir, "") 1040 assert.NoError(err) 1041 defer os.RemoveAll(tmpdir) 1042 1043 testHypervisorPath := filepath.Join(tmpdir, "hypervisor") 1044 testHypervisorLinkPath := filepath.Join(tmpdir, "hypervisor-link") 1045 1046 err = createEmptyFile(testHypervisorPath) 1047 assert.NoError(err) 1048 1049 err = syscall.Symlink(testHypervisorPath, testHypervisorLinkPath) 1050 assert.NoError(err) 1051 1052 savedHypervisorPath := defaultHypervisorPath 1053 1054 defer func() { 1055 defaultHypervisorPath = savedHypervisorPath 1056 }() 1057 1058 defaultHypervisorPath = testHypervisorPath 1059 h := hypervisor{} 1060 p, err := h.path() 1061 assert.NoError(err) 1062 assert.Equal(p, defaultHypervisorPath, "default hypervisor path wrong") 1063 1064 // test path resolution 1065 defaultHypervisorPath = testHypervisorLinkPath 1066 h = hypervisor{} 1067 p, err = h.path() 1068 assert.NoError(err) 1069 assert.Equal(p, testHypervisorPath) 1070 } 1071 1072 func TestHypervisorDefaultsKernel(t *testing.T) { 1073 assert := assert.New(t) 1074 1075 tmpdir, err := ioutil.TempDir(testDir, "") 1076 assert.NoError(err) 1077 defer os.RemoveAll(tmpdir) 1078 1079 testKernelPath := filepath.Join(tmpdir, "kernel") 1080 testKernelLinkPath := filepath.Join(tmpdir, "kernel-link") 1081 1082 err = createEmptyFile(testKernelPath) 1083 assert.NoError(err) 1084 1085 err = syscall.Symlink(testKernelPath, testKernelLinkPath) 1086 assert.NoError(err) 1087 1088 savedKernelPath := defaultKernelPath 1089 1090 defer func() { 1091 defaultKernelPath = savedKernelPath 1092 }() 1093 1094 defaultKernelPath = testKernelPath 1095 1096 h := hypervisor{} 1097 p, err := h.kernel() 1098 assert.NoError(err) 1099 assert.Equal(p, defaultKernelPath, "default Kernel path wrong") 1100 1101 // test path resolution 1102 defaultKernelPath = testKernelLinkPath 1103 h = hypervisor{} 1104 p, err = h.kernel() 1105 assert.NoError(err) 1106 assert.Equal(p, testKernelPath) 1107 1108 assert.Equal(h.kernelParams(), defaultKernelParams, "default hypervisor image wrong") 1109 kernelParams := "foo=bar xyz" 1110 h.KernelParams = kernelParams 1111 assert.Equal(h.kernelParams(), kernelParams, "custom hypervisor kernel parameterms wrong") 1112 } 1113 1114 // The default initrd path is not returned by h.initrd() 1115 func TestHypervisorDefaultsInitrd(t *testing.T) { 1116 assert := assert.New(t) 1117 1118 tmpdir, err := ioutil.TempDir(testDir, "") 1119 assert.NoError(err) 1120 defer os.RemoveAll(tmpdir) 1121 1122 testInitrdPath := filepath.Join(tmpdir, "initrd") 1123 testInitrdLinkPath := filepath.Join(tmpdir, "initrd-link") 1124 1125 err = createEmptyFile(testInitrdPath) 1126 assert.NoError(err) 1127 1128 err = syscall.Symlink(testInitrdPath, testInitrdLinkPath) 1129 assert.NoError(err) 1130 1131 savedInitrdPath := defaultInitrdPath 1132 1133 defer func() { 1134 defaultInitrdPath = savedInitrdPath 1135 }() 1136 1137 defaultInitrdPath = testInitrdPath 1138 h := hypervisor{} 1139 p, err := h.initrd() 1140 assert.Error(err) 1141 assert.Equal(p, "", "default Image path wrong") 1142 1143 // test path resolution 1144 defaultInitrdPath = testInitrdLinkPath 1145 h = hypervisor{} 1146 p, err = h.initrd() 1147 assert.Error(err) 1148 assert.Equal(p, "") 1149 } 1150 1151 // The default image path is not returned by h.image() 1152 func TestHypervisorDefaultsImage(t *testing.T) { 1153 assert := assert.New(t) 1154 1155 tmpdir, err := ioutil.TempDir(testDir, "") 1156 assert.NoError(err) 1157 defer os.RemoveAll(tmpdir) 1158 1159 testImagePath := filepath.Join(tmpdir, "image") 1160 testImageLinkPath := filepath.Join(tmpdir, "image-link") 1161 1162 err = createEmptyFile(testImagePath) 1163 assert.NoError(err) 1164 1165 err = syscall.Symlink(testImagePath, testImageLinkPath) 1166 assert.NoError(err) 1167 1168 savedImagePath := defaultImagePath 1169 1170 defer func() { 1171 defaultImagePath = savedImagePath 1172 }() 1173 1174 defaultImagePath = testImagePath 1175 h := hypervisor{} 1176 p, err := h.image() 1177 assert.Error(err) 1178 assert.Equal(p, "", "default Image path wrong") 1179 1180 // test path resolution 1181 defaultImagePath = testImageLinkPath 1182 h = hypervisor{} 1183 p, err = h.image() 1184 assert.Error(err) 1185 assert.Equal(p, "") 1186 } 1187 1188 func TestHypervisorDefaultsGuestHookPath(t *testing.T) { 1189 assert := assert.New(t) 1190 1191 h := hypervisor{} 1192 guestHookPath := h.guestHookPath() 1193 assert.Equal(guestHookPath, defaultGuestHookPath, "default guest hook path wrong") 1194 1195 testGuestHookPath := "/test/guest/hook/path" 1196 h = hypervisor{ 1197 GuestHookPath: testGuestHookPath, 1198 } 1199 guestHookPath = h.guestHookPath() 1200 assert.Equal(guestHookPath, testGuestHookPath, "custom guest hook path wrong") 1201 } 1202 1203 func TestHypervisorDefaultsVhostUserStorePath(t *testing.T) { 1204 assert := assert.New(t) 1205 1206 h := hypervisor{} 1207 vhostUserStorePath := h.vhostUserStorePath() 1208 assert.Equal(vhostUserStorePath, defaultVhostUserStorePath, "default vhost-user store path wrong") 1209 1210 testVhostUserStorePath := "/test/vhost/user/store/path" 1211 h = hypervisor{ 1212 VhostUserStorePath: testVhostUserStorePath, 1213 } 1214 vhostUserStorePath = h.vhostUserStorePath() 1215 assert.Equal(vhostUserStorePath, testVhostUserStorePath, "custom vhost-user store path wrong") 1216 } 1217 1218 func TestProxyDefaults(t *testing.T) { 1219 assert := assert.New(t) 1220 1221 tmpdir, err := ioutil.TempDir(testDir, "") 1222 assert.NoError(err) 1223 defer os.RemoveAll(tmpdir) 1224 1225 testProxyPath := filepath.Join(tmpdir, "proxy") 1226 testProxyLinkPath := filepath.Join(tmpdir, "proxy-link") 1227 1228 err = createEmptyFile(testProxyPath) 1229 assert.NoError(err) 1230 1231 err = syscall.Symlink(testProxyPath, testProxyLinkPath) 1232 assert.NoError(err) 1233 1234 savedProxyPath := defaultProxyPath 1235 1236 defer func() { 1237 defaultProxyPath = savedProxyPath 1238 }() 1239 1240 defaultProxyPath = testProxyPath 1241 p := proxy{} 1242 path, err := p.path() 1243 assert.NoError(err) 1244 assert.Equal(path, defaultProxyPath, "default proxy path wrong") 1245 1246 // test path resolution 1247 defaultProxyPath = testProxyLinkPath 1248 p = proxy{} 1249 path, err = p.path() 1250 assert.NoError(err) 1251 assert.Equal(path, testProxyPath) 1252 1253 assert.False(p.debug()) 1254 p.Debug = true 1255 assert.True(p.debug()) 1256 } 1257 1258 func TestShimDefaults(t *testing.T) { 1259 assert := assert.New(t) 1260 1261 tmpdir, err := ioutil.TempDir(testDir, "") 1262 assert.NoError(err) 1263 defer os.RemoveAll(tmpdir) 1264 1265 testShimPath := filepath.Join(tmpdir, "shim") 1266 testShimLinkPath := filepath.Join(tmpdir, "shim-link") 1267 1268 err = createEmptyFile(testShimPath) 1269 assert.NoError(err) 1270 1271 err = syscall.Symlink(testShimPath, testShimLinkPath) 1272 assert.NoError(err) 1273 1274 savedShimPath := defaultShimPath 1275 1276 defer func() { 1277 defaultShimPath = savedShimPath 1278 }() 1279 1280 defaultShimPath = testShimPath 1281 s := shim{} 1282 p, err := s.path() 1283 assert.NoError(err) 1284 assert.Equal(p, defaultShimPath, "default shim path wrong") 1285 1286 // test path resolution 1287 defaultShimPath = testShimLinkPath 1288 s = shim{} 1289 p, err = s.path() 1290 assert.NoError(err) 1291 assert.Equal(p, testShimPath) 1292 1293 assert.False(s.debug()) 1294 s.Debug = true 1295 assert.True(s.debug()) 1296 1297 assert.False(s.trace()) 1298 s.Tracing = true 1299 assert.True(s.trace()) 1300 } 1301 1302 func TestAgentDefaults(t *testing.T) { 1303 assert := assert.New(t) 1304 1305 a := agent{} 1306 1307 assert.Equal(a.debug(), a.Debug) 1308 1309 a.Debug = true 1310 assert.Equal(a.debug(), a.Debug) 1311 1312 assert.Equal(a.trace(), a.Tracing) 1313 1314 a.Tracing = true 1315 assert.Equal(a.trace(), a.Tracing) 1316 1317 assert.Equal(a.traceMode(), a.TraceMode) 1318 assert.Equal(a.traceType(), a.TraceType) 1319 } 1320 1321 func TestGetDefaultConfigFilePaths(t *testing.T) { 1322 assert := assert.New(t) 1323 1324 results := GetDefaultConfigFilePaths() 1325 // There should be atleast two config file locations 1326 assert.True(len(results) >= 2) 1327 1328 for _, f := range results { 1329 // Paths cannot be empty 1330 assert.NotNil(f) 1331 } 1332 } 1333 1334 func TestGetDefaultConfigFile(t *testing.T) { 1335 assert := assert.New(t) 1336 1337 tmpdir, err := ioutil.TempDir(testDir, "") 1338 assert.NoError(err) 1339 defer os.RemoveAll(tmpdir) 1340 1341 hypervisor := "qemu" 1342 confDir := filepath.Join(tmpdir, "conf") 1343 sysConfDir := filepath.Join(tmpdir, "sysconf") 1344 1345 for _, dir := range []string{confDir, sysConfDir} { 1346 err = os.MkdirAll(dir, testDirMode) 1347 assert.NoError(err) 1348 } 1349 1350 confDirConfig, err := createAllRuntimeConfigFiles(confDir, hypervisor) 1351 assert.NoError(err) 1352 1353 sysConfDirConfig, err := createAllRuntimeConfigFiles(sysConfDir, hypervisor) 1354 assert.NoError(err) 1355 1356 savedConf := defaultRuntimeConfiguration 1357 savedSysConf := defaultSysConfRuntimeConfiguration 1358 1359 defaultRuntimeConfiguration = confDirConfig.ConfigPath 1360 defaultSysConfRuntimeConfiguration = sysConfDirConfig.ConfigPath 1361 1362 defer func() { 1363 defaultRuntimeConfiguration = savedConf 1364 defaultSysConfRuntimeConfiguration = savedSysConf 1365 1366 }() 1367 1368 got, err := getDefaultConfigFile() 1369 assert.NoError(err) 1370 // defaultSysConfRuntimeConfiguration has priority over defaultRuntimeConfiguration 1371 assert.Equal(got, defaultSysConfRuntimeConfiguration) 1372 1373 // force defaultRuntimeConfiguration to be returned 1374 os.Remove(defaultSysConfRuntimeConfiguration) 1375 1376 got, err = getDefaultConfigFile() 1377 assert.NoError(err) 1378 assert.Equal(got, defaultRuntimeConfiguration) 1379 1380 // force error 1381 os.Remove(defaultRuntimeConfiguration) 1382 1383 _, err = getDefaultConfigFile() 1384 assert.Error(err) 1385 } 1386 1387 func TestDefaultBridges(t *testing.T) { 1388 assert := assert.New(t) 1389 1390 h := hypervisor{DefaultBridges: 0} 1391 1392 bridges := h.defaultBridges() 1393 assert.Equal(defaultBridgesCount, bridges) 1394 1395 h.DefaultBridges = maxPCIBridges + 1 1396 bridges = h.defaultBridges() 1397 assert.Equal(maxPCIBridges, bridges) 1398 1399 h.DefaultBridges = maxPCIBridges 1400 bridges = h.defaultBridges() 1401 assert.Equal(maxPCIBridges, bridges) 1402 } 1403 1404 func TestDefaultVirtioFSCache(t *testing.T) { 1405 assert := assert.New(t) 1406 1407 h := hypervisor{VirtioFSCache: ""} 1408 1409 cache := h.defaultVirtioFSCache() 1410 assert.Equal(defaultVirtioFSCacheMode, cache) 1411 1412 h.VirtioFSCache = "always" 1413 cache = h.defaultVirtioFSCache() 1414 assert.Equal("always", cache) 1415 1416 h.VirtioFSCache = "none" 1417 cache = h.defaultVirtioFSCache() 1418 assert.Equal("none", cache) 1419 } 1420 1421 func TestDefaultFirmware(t *testing.T) { 1422 assert := assert.New(t) 1423 1424 // save default firmware path 1425 oldDefaultFirmwarePath := defaultFirmwarePath 1426 1427 f, err := ioutil.TempFile(os.TempDir(), "qboot.bin") 1428 assert.NoError(err) 1429 assert.NoError(f.Close()) 1430 defer os.RemoveAll(f.Name()) 1431 1432 h := hypervisor{} 1433 defaultFirmwarePath = "" 1434 p, err := h.firmware() 1435 assert.NoError(err) 1436 assert.Empty(p) 1437 1438 defaultFirmwarePath = f.Name() 1439 p, err = h.firmware() 1440 assert.NoError(err) 1441 assert.NotEmpty(p) 1442 1443 // restore default firmware path 1444 defaultFirmwarePath = oldDefaultFirmwarePath 1445 } 1446 1447 func TestDefaultMachineAccelerators(t *testing.T) { 1448 assert := assert.New(t) 1449 machineAccelerators := "abc,123,rgb" 1450 h := hypervisor{MachineAccelerators: machineAccelerators} 1451 assert.Equal(machineAccelerators, h.machineAccelerators()) 1452 1453 machineAccelerators = "" 1454 h.MachineAccelerators = machineAccelerators 1455 assert.Equal(machineAccelerators, h.machineAccelerators()) 1456 1457 machineAccelerators = "abc" 1458 h.MachineAccelerators = machineAccelerators 1459 assert.Equal(machineAccelerators, h.machineAccelerators()) 1460 1461 machineAccelerators = "abc,123" 1462 h.MachineAccelerators = "abc,,123" 1463 assert.Equal(machineAccelerators, h.machineAccelerators()) 1464 1465 machineAccelerators = "abc,123" 1466 h.MachineAccelerators = ",,abc,,123,,," 1467 assert.Equal(machineAccelerators, h.machineAccelerators()) 1468 1469 machineAccelerators = "abc,123" 1470 h.MachineAccelerators = "abc,,123,,," 1471 assert.Equal(machineAccelerators, h.machineAccelerators()) 1472 1473 machineAccelerators = "abc" 1474 h.MachineAccelerators = ",,abc," 1475 assert.Equal(machineAccelerators, h.machineAccelerators()) 1476 1477 machineAccelerators = "abc" 1478 h.MachineAccelerators = ", , abc , ," 1479 assert.Equal(machineAccelerators, h.machineAccelerators()) 1480 1481 machineAccelerators = "abc" 1482 h.MachineAccelerators = " abc " 1483 assert.Equal(machineAccelerators, h.machineAccelerators()) 1484 1485 machineAccelerators = "abc,123" 1486 h.MachineAccelerators = ", abc , 123 ," 1487 assert.Equal(machineAccelerators, h.machineAccelerators()) 1488 1489 machineAccelerators = "abc,123" 1490 h.MachineAccelerators = ",, abc ,,, 123 ,," 1491 assert.Equal(machineAccelerators, h.machineAccelerators()) 1492 } 1493 1494 func TestDefaultCPUFeatures(t *testing.T) { 1495 assert := assert.New(t) 1496 cpuFeatures := "abc,123,rgb" 1497 h := hypervisor{CPUFeatures: cpuFeatures} 1498 assert.Equal(cpuFeatures, h.cpuFeatures()) 1499 1500 cpuFeatures = "" 1501 h.CPUFeatures = cpuFeatures 1502 assert.Equal(cpuFeatures, h.cpuFeatures()) 1503 1504 cpuFeatures = "abc" 1505 h.CPUFeatures = cpuFeatures 1506 assert.Equal(cpuFeatures, h.cpuFeatures()) 1507 1508 cpuFeatures = "abc,123" 1509 h.CPUFeatures = "abc,,123" 1510 assert.Equal(cpuFeatures, h.cpuFeatures()) 1511 1512 cpuFeatures = "abc,123" 1513 h.CPUFeatures = ",,abc,,123,,," 1514 assert.Equal(cpuFeatures, h.cpuFeatures()) 1515 1516 cpuFeatures = "abc,123" 1517 h.CPUFeatures = "abc,,123,,," 1518 assert.Equal(cpuFeatures, h.cpuFeatures()) 1519 1520 cpuFeatures = "abc" 1521 h.CPUFeatures = ",,abc," 1522 assert.Equal(cpuFeatures, h.cpuFeatures()) 1523 1524 cpuFeatures = "abc" 1525 h.CPUFeatures = ", , abc , ," 1526 assert.Equal(cpuFeatures, h.cpuFeatures()) 1527 1528 cpuFeatures = "abc" 1529 h.CPUFeatures = " abc " 1530 assert.Equal(cpuFeatures, h.cpuFeatures()) 1531 1532 cpuFeatures = "abc,123" 1533 h.CPUFeatures = ", abc , 123 ," 1534 assert.Equal(cpuFeatures, h.cpuFeatures()) 1535 1536 cpuFeatures = "abc,123" 1537 h.CPUFeatures = ",, abc ,,, 123 ,," 1538 assert.Equal(cpuFeatures, h.cpuFeatures()) 1539 } 1540 1541 func TestUpdateRuntimeConfiguration(t *testing.T) { 1542 assert := assert.New(t) 1543 1544 assert.Equal(defaultAgent, vc.KataContainersAgent) 1545 1546 config := oci.RuntimeConfig{} 1547 1548 tomlConf := tomlConfig{ 1549 Agent: map[string]agent{ 1550 // force a non-default value 1551 kataAgentTableType: {}, 1552 }, 1553 } 1554 1555 assert.NotEqual(config.AgentType, vc.AgentType(kataAgentTableType)) 1556 assert.NotEqual(config.AgentConfig, vc.KataAgentConfig{}) 1557 1558 err := updateRuntimeConfig("", tomlConf, &config, false) 1559 assert.NoError(err) 1560 1561 assert.Equal(config.AgentType, vc.AgentType(kataAgentTableType)) 1562 assert.Equal(config.AgentConfig, vc.KataAgentConfig{}) 1563 } 1564 1565 func TestUpdateRuntimeConfigurationVMConfig(t *testing.T) { 1566 assert := assert.New(t) 1567 1568 vcpus := uint(2) 1569 mem := uint32(2048) 1570 1571 config := oci.RuntimeConfig{} 1572 expectedVMConfig := mem 1573 1574 tomlConf := tomlConfig{ 1575 Hypervisor: map[string]hypervisor{ 1576 qemuHypervisorTableType: { 1577 NumVCPUs: int32(vcpus), 1578 MemorySize: mem, 1579 Path: "/", 1580 Kernel: "/", 1581 Image: "/", 1582 Firmware: "/", 1583 }, 1584 }, 1585 } 1586 1587 err := updateRuntimeConfig("", tomlConf, &config, false) 1588 assert.NoError(err) 1589 1590 assert.Equal(expectedVMConfig, config.HypervisorConfig.MemorySize) 1591 } 1592 1593 func TestUpdateRuntimeConfigurationFactoryConfig(t *testing.T) { 1594 assert := assert.New(t) 1595 1596 config := oci.RuntimeConfig{} 1597 expectedFactoryConfig := oci.FactoryConfig{ 1598 Template: true, 1599 TemplatePath: defaultTemplatePath, 1600 VMCacheEndpoint: defaultVMCacheEndpoint, 1601 } 1602 1603 tomlConf := tomlConfig{Factory: factory{Template: true}} 1604 1605 err := updateRuntimeConfig("", tomlConf, &config, false) 1606 assert.NoError(err) 1607 1608 assert.Equal(expectedFactoryConfig, config.FactoryConfig) 1609 } 1610 1611 func TestUpdateRuntimeConfigurationInvalidKernelParams(t *testing.T) { 1612 assert := assert.New(t) 1613 1614 assert.Equal(defaultAgent, vc.KataContainersAgent) 1615 1616 config := oci.RuntimeConfig{} 1617 1618 tomlConf := tomlConfig{} 1619 1620 savedFunc := GetKernelParamsFunc 1621 defer func() { 1622 GetKernelParamsFunc = savedFunc 1623 }() 1624 1625 GetKernelParamsFunc = func(needSystemd, trace bool) []vc.Param { 1626 return []vc.Param{ 1627 { 1628 Key: "", 1629 Value: "", 1630 }, 1631 } 1632 } 1633 1634 err := updateRuntimeConfig("", tomlConf, &config, false) 1635 assert.EqualError(err, "Empty kernel parameter") 1636 } 1637 1638 func TestCheckHypervisorConfig(t *testing.T) { 1639 assert := assert.New(t) 1640 1641 dir, err := ioutil.TempDir(testDir, "") 1642 if err != nil { 1643 t.Fatal(err) 1644 } 1645 defer os.RemoveAll(dir) 1646 1647 // Not created on purpose 1648 imageENOENT := filepath.Join(dir, "image-ENOENT.img") 1649 initrdENOENT := filepath.Join(dir, "initrd-ENOENT.img") 1650 1651 imageEmpty := filepath.Join(dir, "image-empty.img") 1652 initrdEmpty := filepath.Join(dir, "initrd-empty.img") 1653 1654 for _, file := range []string{imageEmpty, initrdEmpty} { 1655 err = createEmptyFile(file) 1656 assert.NoError(err) 1657 } 1658 1659 image := filepath.Join(dir, "image.img") 1660 initrd := filepath.Join(dir, "initrd.img") 1661 1662 mb := uint32(1024 * 1024) 1663 1664 fileSizeMB := uint32(3) 1665 fileSizeBytes := fileSizeMB * mb 1666 1667 fileData := strings.Repeat("X", int(fileSizeBytes)) 1668 1669 for _, file := range []string{image, initrd} { 1670 err = WriteFile(file, fileData, testFileMode) 1671 assert.NoError(err) 1672 } 1673 1674 type testData struct { 1675 imagePath string 1676 initrdPath string 1677 memBytes uint32 1678 expectError bool 1679 expectLogWarning bool 1680 } 1681 1682 // Note that checkHypervisorConfig() does not check to ensure an image 1683 // or an initrd has been specified - that's handled by a separate 1684 // function, hence no test for it here. 1685 1686 data := []testData{ 1687 {"", "", 0, true, false}, 1688 1689 {imageENOENT, "", 2, true, false}, 1690 {"", initrdENOENT, 2, true, false}, 1691 1692 {imageEmpty, "", 2, true, false}, 1693 {"", initrdEmpty, 2, true, false}, 1694 1695 {image, "", fileSizeMB + 2, false, false}, 1696 {image, "", fileSizeMB + 1, false, false}, 1697 {image, "", fileSizeMB + 0, false, true}, 1698 {image, "", fileSizeMB - 1, false, true}, 1699 {image, "", fileSizeMB - 2, false, true}, 1700 1701 {"", initrd, fileSizeMB + 2, false, false}, 1702 {"", initrd, fileSizeMB + 1, false, false}, 1703 {"", initrd, fileSizeMB + 0, true, false}, 1704 {"", initrd, fileSizeMB - 1, true, false}, 1705 {"", initrd, fileSizeMB - 2, true, false}, 1706 } 1707 1708 for i, d := range data { 1709 savedOut := kataUtilsLogger.Logger.Out 1710 1711 // create buffer to save logger output 1712 logBuf := &bytes.Buffer{} 1713 1714 // capture output to buffer 1715 kataUtilsLogger.Logger.Out = logBuf 1716 1717 config := vc.HypervisorConfig{ 1718 ImagePath: d.imagePath, 1719 InitrdPath: d.initrdPath, 1720 MemorySize: d.memBytes, 1721 } 1722 1723 err := checkHypervisorConfig(config) 1724 1725 if d.expectError { 1726 assert.Error(err, "test %d (%+v)", i, d) 1727 } else { 1728 assert.NoError(err, "test %d (%+v)", i, d) 1729 } 1730 1731 if d.expectLogWarning { 1732 assert.True(strings.Contains(logBuf.String(), "warning")) 1733 } else { 1734 assert.Empty(logBuf.String()) 1735 } 1736 1737 // reset logger 1738 kataUtilsLogger.Logger.Out = savedOut 1739 } 1740 } 1741 1742 func TestCheckNetNsConfig(t *testing.T) { 1743 assert := assert.New(t) 1744 1745 config := oci.RuntimeConfig{ 1746 DisableNewNetNs: true, 1747 NetmonConfig: vc.NetmonConfig{ 1748 Enable: true, 1749 }, 1750 } 1751 err := checkNetNsConfig(config) 1752 assert.Error(err) 1753 1754 config = oci.RuntimeConfig{ 1755 DisableNewNetNs: true, 1756 InterNetworkModel: vc.NetXConnectDefaultModel, 1757 } 1758 err = checkNetNsConfig(config) 1759 assert.Error(err) 1760 } 1761 1762 func TestCheckFactoryConfig(t *testing.T) { 1763 assert := assert.New(t) 1764 1765 type testData struct { 1766 factoryEnabled bool 1767 expectError bool 1768 imagePath string 1769 initrdPath string 1770 } 1771 1772 data := []testData{ 1773 {false, false, "", ""}, 1774 {false, false, "image", ""}, 1775 {false, false, "", "initrd"}, 1776 1777 {true, false, "", "initrd"}, 1778 {true, true, "image", ""}, 1779 } 1780 1781 for i, d := range data { 1782 config := oci.RuntimeConfig{ 1783 HypervisorConfig: vc.HypervisorConfig{ 1784 ImagePath: d.imagePath, 1785 InitrdPath: d.initrdPath, 1786 }, 1787 1788 FactoryConfig: oci.FactoryConfig{ 1789 Template: d.factoryEnabled, 1790 }, 1791 } 1792 1793 err := checkFactoryConfig(config) 1794 1795 if d.expectError { 1796 assert.Error(err, "test %d (%+v)", i, d) 1797 } else { 1798 assert.NoError(err, "test %d (%+v)", i, d) 1799 } 1800 } 1801 } 1802 1803 func TestCheckNetNsConfigShimTrace(t *testing.T) { 1804 assert := assert.New(t) 1805 1806 type testData struct { 1807 networkModel vc.NetInterworkingModel 1808 disableNetNs bool 1809 shimTrace bool 1810 expectError bool 1811 } 1812 1813 data := []testData{ 1814 {vc.NetXConnectMacVtapModel, false, false, false}, 1815 {vc.NetXConnectMacVtapModel, false, true, true}, 1816 {vc.NetXConnectMacVtapModel, true, true, true}, 1817 {vc.NetXConnectMacVtapModel, true, false, true}, 1818 {vc.NetXConnectNoneModel, true, false, false}, 1819 {vc.NetXConnectNoneModel, true, true, false}, 1820 } 1821 1822 for i, d := range data { 1823 config := oci.RuntimeConfig{ 1824 DisableNewNetNs: d.disableNetNs, 1825 InterNetworkModel: d.networkModel, 1826 ShimConfig: vc.ShimConfig{ 1827 Trace: d.shimTrace, 1828 }, 1829 } 1830 1831 err := checkNetNsConfig(config) 1832 1833 if d.expectError { 1834 assert.Error(err, "test %d (%+v)", i, d) 1835 } else { 1836 assert.NoError(err, "test %d (%+v)", i, d) 1837 } 1838 } 1839 }