gitee.com/leisunstar/runtime@v0.0.0-20200521203717-5cef3e7b53f9/virtcontainers/kata_agent_test.go (about) 1 // Copyright (c) 2018 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package virtcontainers 7 8 import ( 9 "bufio" 10 "context" 11 "fmt" 12 "io/ioutil" 13 "net" 14 "os" 15 "path" 16 "path/filepath" 17 "reflect" 18 "strings" 19 "syscall" 20 "testing" 21 22 vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations" 23 24 gpb "github.com/gogo/protobuf/types" 25 specs "github.com/opencontainers/runtime-spec/specs-go" 26 "github.com/stretchr/testify/assert" 27 "google.golang.org/grpc" 28 29 aTypes "github.com/kata-containers/agent/pkg/types" 30 pb "github.com/kata-containers/agent/protocols/grpc" 31 "github.com/kata-containers/runtime/virtcontainers/device/api" 32 "github.com/kata-containers/runtime/virtcontainers/device/config" 33 "github.com/kata-containers/runtime/virtcontainers/device/drivers" 34 "github.com/kata-containers/runtime/virtcontainers/device/manager" 35 "github.com/kata-containers/runtime/virtcontainers/persist" 36 "github.com/kata-containers/runtime/virtcontainers/pkg/mock" 37 "github.com/kata-containers/runtime/virtcontainers/pkg/rootless" 38 vcTypes "github.com/kata-containers/runtime/virtcontainers/pkg/types" 39 "github.com/kata-containers/runtime/virtcontainers/types" 40 ) 41 42 var ( 43 testKataProxyURLTempl = "unix://%s/kata-proxy-test.sock" 44 testBlockDeviceCtrPath = "testBlockDeviceCtrPath" 45 testPCIAddr = "04/02" 46 ) 47 48 func proxyHandlerDiscard(c net.Conn) { 49 buf := make([]byte, 1024) 50 c.Read(buf) 51 } 52 53 func testGenerateKataProxySockDir() (string, error) { 54 dir, err := ioutil.TempDir("", "kata-proxy-test") 55 if err != nil { 56 return "", err 57 } 58 59 return dir, nil 60 } 61 62 func TestKataAgentConnect(t *testing.T) { 63 assert := assert.New(t) 64 proxy := mock.ProxyUnixMock{ 65 ClientHandler: proxyHandlerDiscard, 66 } 67 68 sockDir, err := testGenerateKataProxySockDir() 69 assert.NoError(err) 70 defer os.RemoveAll(sockDir) 71 72 testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir) 73 err = proxy.Start(testKataProxyURL) 74 assert.NoError(err) 75 defer proxy.Stop() 76 77 k := &kataAgent{ 78 ctx: context.Background(), 79 state: KataAgentState{ 80 URL: testKataProxyURL, 81 }, 82 } 83 84 err = k.connect() 85 assert.NoError(err) 86 assert.NotNil(k.client) 87 } 88 89 func TestKataAgentDisconnect(t *testing.T) { 90 assert := assert.New(t) 91 proxy := mock.ProxyUnixMock{ 92 ClientHandler: proxyHandlerDiscard, 93 } 94 95 sockDir, err := testGenerateKataProxySockDir() 96 assert.NoError(err) 97 defer os.RemoveAll(sockDir) 98 99 testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir) 100 err = proxy.Start(testKataProxyURL) 101 assert.NoError(err) 102 defer proxy.Stop() 103 104 k := &kataAgent{ 105 ctx: context.Background(), 106 state: KataAgentState{ 107 URL: testKataProxyURL, 108 }, 109 } 110 111 assert.NoError(k.connect()) 112 assert.NoError(k.disconnect()) 113 assert.Nil(k.client) 114 } 115 116 type gRPCProxy struct{} 117 118 var emptyResp = &gpb.Empty{} 119 120 func (p *gRPCProxy) CreateContainer(ctx context.Context, req *pb.CreateContainerRequest) (*gpb.Empty, error) { 121 return emptyResp, nil 122 } 123 124 func (p *gRPCProxy) StartContainer(ctx context.Context, req *pb.StartContainerRequest) (*gpb.Empty, error) { 125 return emptyResp, nil 126 } 127 128 func (p *gRPCProxy) ExecProcess(ctx context.Context, req *pb.ExecProcessRequest) (*gpb.Empty, error) { 129 return emptyResp, nil 130 } 131 132 func (p *gRPCProxy) SignalProcess(ctx context.Context, req *pb.SignalProcessRequest) (*gpb.Empty, error) { 133 return emptyResp, nil 134 } 135 136 func (p *gRPCProxy) WaitProcess(ctx context.Context, req *pb.WaitProcessRequest) (*pb.WaitProcessResponse, error) { 137 return &pb.WaitProcessResponse{}, nil 138 } 139 140 func (p *gRPCProxy) ListProcesses(ctx context.Context, req *pb.ListProcessesRequest) (*pb.ListProcessesResponse, error) { 141 return &pb.ListProcessesResponse{}, nil 142 } 143 144 func (p *gRPCProxy) UpdateContainer(ctx context.Context, req *pb.UpdateContainerRequest) (*gpb.Empty, error) { 145 return emptyResp, nil 146 } 147 148 func (p *gRPCProxy) RemoveContainer(ctx context.Context, req *pb.RemoveContainerRequest) (*gpb.Empty, error) { 149 return emptyResp, nil 150 } 151 152 func (p *gRPCProxy) WriteStdin(ctx context.Context, req *pb.WriteStreamRequest) (*pb.WriteStreamResponse, error) { 153 return &pb.WriteStreamResponse{}, nil 154 } 155 156 func (p *gRPCProxy) ReadStdout(ctx context.Context, req *pb.ReadStreamRequest) (*pb.ReadStreamResponse, error) { 157 return &pb.ReadStreamResponse{}, nil 158 } 159 160 func (p *gRPCProxy) ReadStderr(ctx context.Context, req *pb.ReadStreamRequest) (*pb.ReadStreamResponse, error) { 161 return &pb.ReadStreamResponse{}, nil 162 } 163 164 func (p *gRPCProxy) CloseStdin(ctx context.Context, req *pb.CloseStdinRequest) (*gpb.Empty, error) { 165 return emptyResp, nil 166 } 167 168 func (p *gRPCProxy) TtyWinResize(ctx context.Context, req *pb.TtyWinResizeRequest) (*gpb.Empty, error) { 169 return emptyResp, nil 170 } 171 172 func (p *gRPCProxy) CreateSandbox(ctx context.Context, req *pb.CreateSandboxRequest) (*gpb.Empty, error) { 173 return emptyResp, nil 174 } 175 176 func (p *gRPCProxy) DestroySandbox(ctx context.Context, req *pb.DestroySandboxRequest) (*gpb.Empty, error) { 177 return emptyResp, nil 178 } 179 180 func (p *gRPCProxy) UpdateInterface(ctx context.Context, req *pb.UpdateInterfaceRequest) (*aTypes.Interface, error) { 181 return &aTypes.Interface{}, nil 182 } 183 184 func (p *gRPCProxy) UpdateRoutes(ctx context.Context, req *pb.UpdateRoutesRequest) (*pb.Routes, error) { 185 return &pb.Routes{}, nil 186 } 187 188 func (p *gRPCProxy) ListInterfaces(ctx context.Context, req *pb.ListInterfacesRequest) (*pb.Interfaces, error) { 189 return &pb.Interfaces{}, nil 190 } 191 192 func (p *gRPCProxy) ListRoutes(ctx context.Context, req *pb.ListRoutesRequest) (*pb.Routes, error) { 193 return &pb.Routes{}, nil 194 } 195 196 func (p *gRPCProxy) OnlineCPUMem(ctx context.Context, req *pb.OnlineCPUMemRequest) (*gpb.Empty, error) { 197 return emptyResp, nil 198 } 199 200 func (p *gRPCProxy) StatsContainer(ctx context.Context, req *pb.StatsContainerRequest) (*pb.StatsContainerResponse, error) { 201 return &pb.StatsContainerResponse{}, nil 202 } 203 204 func (p *gRPCProxy) Check(ctx context.Context, req *pb.CheckRequest) (*pb.HealthCheckResponse, error) { 205 return &pb.HealthCheckResponse{}, nil 206 } 207 208 func (p *gRPCProxy) Version(ctx context.Context, req *pb.CheckRequest) (*pb.VersionCheckResponse, error) { 209 return &pb.VersionCheckResponse{}, nil 210 211 } 212 213 func (p *gRPCProxy) PauseContainer(ctx context.Context, req *pb.PauseContainerRequest) (*gpb.Empty, error) { 214 return emptyResp, nil 215 } 216 217 func (p *gRPCProxy) ResumeContainer(ctx context.Context, req *pb.ResumeContainerRequest) (*gpb.Empty, error) { 218 return emptyResp, nil 219 } 220 221 func (p *gRPCProxy) ReseedRandomDev(ctx context.Context, req *pb.ReseedRandomDevRequest) (*gpb.Empty, error) { 222 return emptyResp, nil 223 } 224 225 func (p *gRPCProxy) GetGuestDetails(ctx context.Context, req *pb.GuestDetailsRequest) (*pb.GuestDetailsResponse, error) { 226 return &pb.GuestDetailsResponse{}, nil 227 } 228 229 func (p *gRPCProxy) SetGuestDateTime(ctx context.Context, req *pb.SetGuestDateTimeRequest) (*gpb.Empty, error) { 230 return &gpb.Empty{}, nil 231 } 232 233 func (p *gRPCProxy) CopyFile(ctx context.Context, req *pb.CopyFileRequest) (*gpb.Empty, error) { 234 return &gpb.Empty{}, nil 235 } 236 237 func (p *gRPCProxy) StartTracing(ctx context.Context, req *pb.StartTracingRequest) (*gpb.Empty, error) { 238 return &gpb.Empty{}, nil 239 } 240 241 func (p *gRPCProxy) StopTracing(ctx context.Context, req *pb.StopTracingRequest) (*gpb.Empty, error) { 242 return &gpb.Empty{}, nil 243 } 244 245 func (p *gRPCProxy) MemHotplugByProbe(ctx context.Context, req *pb.MemHotplugByProbeRequest) (*gpb.Empty, error) { 246 return &gpb.Empty{}, nil 247 } 248 249 func (p *gRPCProxy) GetOOMEvent(ctx context.Context, req *pb.GetOOMEventRequest) (*pb.OOMEvent, error) { 250 return &pb.OOMEvent{}, nil 251 } 252 253 func gRPCRegister(s *grpc.Server, srv interface{}) { 254 switch g := srv.(type) { 255 case *gRPCProxy: 256 pb.RegisterAgentServiceServer(s, g) 257 pb.RegisterHealthServer(s, g) 258 } 259 } 260 261 var reqList = []interface{}{ 262 &pb.CreateSandboxRequest{}, 263 &pb.DestroySandboxRequest{}, 264 &pb.ExecProcessRequest{}, 265 &pb.CreateContainerRequest{}, 266 &pb.StartContainerRequest{}, 267 &pb.RemoveContainerRequest{}, 268 &pb.SignalProcessRequest{}, 269 &pb.CheckRequest{}, 270 &pb.WaitProcessRequest{}, 271 &pb.StatsContainerRequest{}, 272 &pb.SetGuestDateTimeRequest{}, 273 } 274 275 func TestKataAgentSendReq(t *testing.T) { 276 assert := assert.New(t) 277 278 impl := &gRPCProxy{} 279 280 proxy := mock.ProxyGRPCMock{ 281 GRPCImplementer: impl, 282 GRPCRegister: gRPCRegister, 283 } 284 285 sockDir, err := testGenerateKataProxySockDir() 286 assert.Nil(err) 287 defer os.RemoveAll(sockDir) 288 289 testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir) 290 err = proxy.Start(testKataProxyURL) 291 assert.Nil(err) 292 defer proxy.Stop() 293 294 k := &kataAgent{ 295 ctx: context.Background(), 296 state: KataAgentState{ 297 URL: testKataProxyURL, 298 }, 299 } 300 301 for _, req := range reqList { 302 _, err = k.sendReq(req) 303 assert.Nil(err) 304 } 305 306 sandbox := &Sandbox{} 307 container := &Container{} 308 execid := "processFooBar" 309 310 err = k.startContainer(sandbox, container) 311 assert.Nil(err) 312 313 err = k.signalProcess(container, execid, syscall.SIGKILL, true) 314 assert.Nil(err) 315 316 err = k.winsizeProcess(container, execid, 100, 200) 317 assert.Nil(err) 318 319 _, err = k.processListContainer(sandbox, Container{}, ProcessListOptions{}) 320 assert.Nil(err) 321 322 err = k.updateContainer(sandbox, Container{}, specs.LinuxResources{}) 323 assert.Nil(err) 324 325 err = k.pauseContainer(sandbox, Container{}) 326 assert.Nil(err) 327 328 err = k.resumeContainer(sandbox, Container{}) 329 assert.Nil(err) 330 331 err = k.onlineCPUMem(1, true) 332 assert.Nil(err) 333 334 _, err = k.statsContainer(sandbox, Container{}) 335 assert.Nil(err) 336 337 err = k.check() 338 assert.Nil(err) 339 340 _, err = k.waitProcess(container, execid) 341 assert.Nil(err) 342 343 _, err = k.writeProcessStdin(container, execid, []byte{'c'}) 344 assert.Nil(err) 345 346 err = k.closeProcessStdin(container, execid) 347 assert.Nil(err) 348 349 _, err = k.readProcessStdout(container, execid, []byte{}) 350 assert.Nil(err) 351 352 _, err = k.readProcessStderr(container, execid, []byte{}) 353 assert.Nil(err) 354 355 _, err = k.getOOMEvent() 356 assert.Nil(err) 357 } 358 359 func TestHandleEphemeralStorage(t *testing.T) { 360 k := kataAgent{} 361 var ociMounts []specs.Mount 362 mountSource := "/tmp/mountPoint" 363 364 mount := specs.Mount{ 365 Type: KataEphemeralDevType, 366 Source: mountSource, 367 } 368 369 ociMounts = append(ociMounts, mount) 370 epheStorages := k.handleEphemeralStorage(ociMounts) 371 372 epheMountPoint := epheStorages[0].GetMountPoint() 373 expected := filepath.Join(ephemeralPath(), filepath.Base(mountSource)) 374 assert.Equal(t, epheMountPoint, expected, 375 "Ephemeral mount point didn't match: got %s, expecting %s", epheMountPoint, expected) 376 } 377 378 func TestHandleLocalStorage(t *testing.T) { 379 k := kataAgent{} 380 var ociMounts []specs.Mount 381 mountSource := "mountPoint" 382 383 mount := specs.Mount{ 384 Type: KataLocalDevType, 385 Source: mountSource, 386 } 387 388 sandboxID := "sandboxid" 389 rootfsSuffix := "rootfs" 390 391 ociMounts = append(ociMounts, mount) 392 localStorages := k.handleLocalStorage(ociMounts, sandboxID, rootfsSuffix) 393 394 assert.NotNil(t, localStorages) 395 assert.Equal(t, len(localStorages), 1) 396 397 localMountPoint := localStorages[0].GetMountPoint() 398 expected := filepath.Join(kataGuestSharedDir(), sandboxID, rootfsSuffix, KataLocalDevType, filepath.Base(mountSource)) 399 assert.Equal(t, localMountPoint, expected) 400 } 401 402 func TestHandleBlockVolume(t *testing.T) { 403 k := kataAgent{} 404 405 c := &Container{ 406 id: "100", 407 } 408 containers := map[string]*Container{} 409 containers[c.id] = c 410 411 // Create a VhostUserBlk device and a DeviceBlock device 412 vDevID := "MockVhostUserBlk" 413 bDevID := "MockDeviceBlock" 414 vDestination := "/VhostUserBlk/destination" 415 bDestination := "/DeviceBlock/destination" 416 vPCIAddr := "0001:01" 417 bPCIAddr := "0002:01" 418 419 vDev := drivers.NewVhostUserBlkDevice(&config.DeviceInfo{ID: vDevID}) 420 bDev := drivers.NewBlockDevice(&config.DeviceInfo{ID: bDevID}) 421 422 vDev.VhostUserDeviceAttrs = &config.VhostUserDeviceAttrs{PCIAddr: vPCIAddr} 423 bDev.BlockDrive = &config.BlockDrive{PCIAddr: bPCIAddr} 424 425 var devices []api.Device 426 devices = append(devices, vDev, bDev) 427 428 // Create a VhostUserBlk mount and a DeviceBlock mount 429 var mounts []Mount 430 vMount := Mount{ 431 BlockDeviceID: vDevID, 432 Destination: vDestination, 433 } 434 bMount := Mount{ 435 BlockDeviceID: bDevID, 436 Destination: bDestination, 437 } 438 mounts = append(mounts, vMount, bMount) 439 440 tmpDir := "/vhost/user/dir" 441 dm := manager.NewDeviceManager(manager.VirtioBlock, true, tmpDir, devices) 442 443 sConfig := SandboxConfig{} 444 sConfig.HypervisorConfig.BlockDeviceDriver = manager.VirtioBlock 445 sandbox := Sandbox{ 446 id: "100", 447 containers: containers, 448 hypervisor: &mockHypervisor{}, 449 devManager: dm, 450 ctx: context.Background(), 451 config: &sConfig, 452 } 453 containers[c.id].sandbox = &sandbox 454 containers[c.id].mounts = mounts 455 456 volumeStorages, err := k.handleBlockVolumes(c) 457 assert.Nil(t, err, "Error while handling block volumes") 458 459 vStorage := &pb.Storage{ 460 MountPoint: vDestination, 461 Fstype: "bind", 462 Options: []string{"bind"}, 463 Driver: kataBlkDevType, 464 Source: vPCIAddr, 465 } 466 bStorage := &pb.Storage{ 467 MountPoint: bDestination, 468 Fstype: "bind", 469 Options: []string{"bind"}, 470 Driver: kataBlkDevType, 471 Source: bPCIAddr, 472 } 473 474 assert.Equal(t, vStorage, volumeStorages[0], "Error while handle VhostUserBlk type block volume") 475 assert.Equal(t, bStorage, volumeStorages[1], "Error while handle BlockDevice type block volume") 476 } 477 478 func TestAppendDevicesEmptyContainerDeviceList(t *testing.T) { 479 k := kataAgent{} 480 481 devList := []*pb.Device{} 482 expected := []*pb.Device{} 483 ctrDevices := []ContainerDevice{} 484 485 c := &Container{ 486 sandbox: &Sandbox{ 487 devManager: manager.NewDeviceManager("virtio-scsi", false, "", nil), 488 }, 489 devices: ctrDevices, 490 } 491 updatedDevList := k.appendDevices(devList, c) 492 assert.True(t, reflect.DeepEqual(updatedDevList, expected), 493 "Device lists didn't match: got %+v, expecting %+v", 494 updatedDevList, expected) 495 } 496 497 func TestAppendDevices(t *testing.T) { 498 k := kataAgent{} 499 500 id := "test-append-block" 501 ctrDevices := []api.Device{ 502 &drivers.BlockDevice{ 503 GenericDevice: &drivers.GenericDevice{ 504 ID: id, 505 }, 506 BlockDrive: &config.BlockDrive{ 507 PCIAddr: testPCIAddr, 508 }, 509 }, 510 } 511 512 sandboxConfig := &SandboxConfig{ 513 HypervisorConfig: HypervisorConfig{ 514 BlockDeviceDriver: config.VirtioBlock, 515 }, 516 } 517 518 c := &Container{ 519 sandbox: &Sandbox{ 520 devManager: manager.NewDeviceManager("virtio-blk", false, "", ctrDevices), 521 config: sandboxConfig, 522 }, 523 } 524 c.devices = append(c.devices, ContainerDevice{ 525 ID: id, 526 ContainerPath: testBlockDeviceCtrPath, 527 }) 528 529 devList := []*pb.Device{} 530 expected := []*pb.Device{ 531 { 532 Type: kataBlkDevType, 533 ContainerPath: testBlockDeviceCtrPath, 534 Id: testPCIAddr, 535 }, 536 } 537 updatedDevList := k.appendDevices(devList, c) 538 assert.True(t, reflect.DeepEqual(updatedDevList, expected), 539 "Device lists didn't match: got %+v, expecting %+v", 540 updatedDevList, expected) 541 } 542 543 func TestAppendVhostUserBlkDevices(t *testing.T) { 544 k := kataAgent{} 545 546 id := "test-append-vhost-user-blk" 547 ctrDevices := []api.Device{ 548 &drivers.VhostUserBlkDevice{ 549 GenericDevice: &drivers.GenericDevice{ 550 ID: id, 551 }, 552 VhostUserDeviceAttrs: &config.VhostUserDeviceAttrs{ 553 Type: config.VhostUserBlk, 554 PCIAddr: testPCIAddr, 555 }, 556 }, 557 } 558 559 sandboxConfig := &SandboxConfig{ 560 HypervisorConfig: HypervisorConfig{ 561 BlockDeviceDriver: config.VirtioBlock, 562 }, 563 } 564 565 testVhostUserStorePath := "/test/vhost/user/store/path" 566 c := &Container{ 567 sandbox: &Sandbox{ 568 devManager: manager.NewDeviceManager("virtio-blk", true, testVhostUserStorePath, ctrDevices), 569 config: sandboxConfig, 570 }, 571 } 572 c.devices = append(c.devices, ContainerDevice{ 573 ID: id, 574 ContainerPath: testBlockDeviceCtrPath, 575 }) 576 577 devList := []*pb.Device{} 578 expected := []*pb.Device{ 579 { 580 Type: kataBlkDevType, 581 ContainerPath: testBlockDeviceCtrPath, 582 Id: testPCIAddr, 583 }, 584 } 585 updatedDevList := k.appendDevices(devList, c) 586 assert.True(t, reflect.DeepEqual(updatedDevList, expected), 587 "Device lists didn't match: got %+v, expecting %+v", 588 updatedDevList, expected) 589 } 590 591 func TestConstraintGRPCSpec(t *testing.T) { 592 assert := assert.New(t) 593 expectedCgroupPath := "/foo/bar" 594 595 g := &pb.Spec{ 596 Hooks: &pb.Hooks{}, 597 Mounts: []pb.Mount{ 598 {Destination: "/dev/shm"}, 599 }, 600 Linux: &pb.Linux{ 601 Seccomp: &pb.LinuxSeccomp{}, 602 Namespaces: []pb.LinuxNamespace{ 603 { 604 Type: specs.NetworkNamespace, 605 Path: "/abc/123", 606 }, 607 { 608 Type: specs.MountNamespace, 609 Path: "/abc/123", 610 }, 611 }, 612 Resources: &pb.LinuxResources{ 613 Devices: []pb.LinuxDeviceCgroup{}, 614 Memory: &pb.LinuxMemory{}, 615 CPU: &pb.LinuxCPU{}, 616 Pids: &pb.LinuxPids{}, 617 BlockIO: &pb.LinuxBlockIO{}, 618 HugepageLimits: []pb.LinuxHugepageLimit{}, 619 Network: &pb.LinuxNetwork{}, 620 }, 621 CgroupsPath: "system.slice:foo:bar", 622 Devices: []pb.LinuxDevice{ 623 { 624 Path: "/dev/vfio/1", 625 Type: "c", 626 }, 627 { 628 Path: "/dev/vfio/2", 629 Type: "c", 630 }, 631 }, 632 }, 633 Process: &pb.Process{ 634 SelinuxLabel: "foo", 635 }, 636 } 637 638 k := kataAgent{} 639 k.constraintGRPCSpec(g, true) 640 641 // check nil fields 642 assert.Nil(g.Hooks) 643 assert.NotNil(g.Linux.Seccomp) 644 assert.Nil(g.Linux.Resources.Devices) 645 assert.NotNil(g.Linux.Resources.Memory) 646 assert.Nil(g.Linux.Resources.Pids) 647 assert.Nil(g.Linux.Resources.BlockIO) 648 assert.Nil(g.Linux.Resources.HugepageLimits) 649 assert.Nil(g.Linux.Resources.Network) 650 assert.NotNil(g.Linux.Resources.CPU) 651 assert.Equal(g.Process.SelinuxLabel, "") 652 653 // check namespaces 654 assert.Len(g.Linux.Namespaces, 1) 655 assert.Empty(g.Linux.Namespaces[0].Path) 656 657 // check mounts 658 assert.Len(g.Mounts, 1) 659 660 // check cgroup path 661 assert.Equal(expectedCgroupPath, g.Linux.CgroupsPath) 662 663 // check Linux devices 664 assert.Empty(g.Linux.Devices) 665 } 666 667 func TestHandleShm(t *testing.T) { 668 assert := assert.New(t) 669 k := kataAgent{} 670 sandbox := &Sandbox{ 671 shmSize: 8192, 672 } 673 674 var ociMounts []specs.Mount 675 676 mount := specs.Mount{ 677 Type: "bind", 678 Destination: "/dev/shm", 679 } 680 681 ociMounts = append(ociMounts, mount) 682 k.handleShm(ociMounts, sandbox) 683 684 assert.Len(ociMounts, 1) 685 assert.NotEmpty(ociMounts[0].Destination) 686 assert.Equal(ociMounts[0].Destination, "/dev/shm") 687 assert.Equal(ociMounts[0].Type, "bind") 688 assert.NotEmpty(ociMounts[0].Source, filepath.Join(kataGuestSharedDir(), shmDir)) 689 assert.Equal(ociMounts[0].Options, []string{"rbind"}) 690 691 sandbox.shmSize = 0 692 k.handleShm(ociMounts, sandbox) 693 694 assert.Len(ociMounts, 1) 695 assert.Equal(ociMounts[0].Destination, "/dev/shm") 696 assert.Equal(ociMounts[0].Type, "tmpfs") 697 assert.Equal(ociMounts[0].Source, "shm") 698 sizeOption := fmt.Sprintf("size=%d", DefaultShmSize) 699 assert.Equal(ociMounts[0].Options, []string{"noexec", "nosuid", "nodev", "mode=1777", sizeOption}) 700 701 // In case the type of mount is ephemeral, the container mount is not 702 // shared with the sandbox shm. 703 ociMounts[0].Type = KataEphemeralDevType 704 mountSource := "/tmp/mountPoint" 705 ociMounts[0].Source = mountSource 706 k.handleShm(ociMounts, sandbox) 707 708 assert.Len(ociMounts, 1) 709 assert.Equal(ociMounts[0].Type, KataEphemeralDevType) 710 assert.NotEmpty(ociMounts[0].Source, mountSource) 711 712 epheStorages := k.handleEphemeralStorage(ociMounts) 713 epheMountPoint := epheStorages[0].GetMountPoint() 714 expected := filepath.Join(ephemeralPath(), filepath.Base(mountSource)) 715 assert.Equal(epheMountPoint, expected, 716 "Ephemeral mount point didn't match: got %s, expecting %s", epheMountPoint, expected) 717 718 } 719 720 func testIsPidNamespacePresent(grpcSpec *pb.Spec) bool { 721 for _, ns := range grpcSpec.Linux.Namespaces { 722 if ns.Type == string(specs.PIDNamespace) { 723 return true 724 } 725 } 726 727 return false 728 } 729 730 func TestHandlePidNamespace(t *testing.T) { 731 assert := assert.New(t) 732 733 g := &pb.Spec{ 734 Linux: &pb.Linux{ 735 Namespaces: []pb.LinuxNamespace{ 736 { 737 Type: specs.NetworkNamespace, 738 Path: "/abc/123", 739 }, 740 { 741 Type: specs.MountNamespace, 742 Path: "/abc/123", 743 }, 744 }, 745 }, 746 } 747 748 sandbox := &Sandbox{} 749 750 k := kataAgent{} 751 752 sharedPid := k.handlePidNamespace(g, sandbox) 753 assert.False(sharedPid) 754 assert.False(testIsPidNamespacePresent(g)) 755 756 pidNs := pb.LinuxNamespace{ 757 Type: string(specs.PIDNamespace), 758 Path: "", 759 } 760 761 utsNs := pb.LinuxNamespace{ 762 Type: specs.UTSNamespace, 763 Path: "", 764 } 765 766 g.Linux.Namespaces = append(g.Linux.Namespaces, pidNs) 767 g.Linux.Namespaces = append(g.Linux.Namespaces, utsNs) 768 769 sharedPid = k.handlePidNamespace(g, sandbox) 770 assert.False(sharedPid) 771 assert.False(testIsPidNamespacePresent(g)) 772 773 pidNs = pb.LinuxNamespace{ 774 Type: string(specs.PIDNamespace), 775 Path: "/proc/112/ns/pid", 776 } 777 g.Linux.Namespaces = append(g.Linux.Namespaces, pidNs) 778 779 sharedPid = k.handlePidNamespace(g, sandbox) 780 assert.True(sharedPid) 781 assert.False(testIsPidNamespacePresent(g)) 782 } 783 784 func TestAgentPathAPI(t *testing.T) { 785 assert := assert.New(t) 786 787 k1 := &kataAgent{} 788 k2 := &kataAgent{} 789 id := "foobar" 790 791 // getSharePath 792 path1 := k1.getSharePath(id) 793 path2 := k2.getSharePath(id) 794 assert.Equal(path1, path2) 795 } 796 797 func TestAgentConfigure(t *testing.T) { 798 assert := assert.New(t) 799 800 dir, err := ioutil.TempDir("", "kata-agent-test") 801 assert.Nil(err) 802 defer os.RemoveAll(dir) 803 804 k := &kataAgent{} 805 h := &mockHypervisor{} 806 c := KataAgentConfig{} 807 id := "foobar" 808 809 err = k.configure(h, id, dir, true, c) 810 assert.Nil(err) 811 812 err = k.configure(h, id, dir, true, c) 813 assert.Nil(err) 814 assert.Empty(k.state.URL) 815 816 err = k.configure(h, id, dir, false, c) 817 assert.Nil(err) 818 } 819 820 func TestCmdToKataProcess(t *testing.T) { 821 assert := assert.New(t) 822 823 cmd := types.Cmd{ 824 Args: strings.Split("foo", " "), 825 Envs: []types.EnvVar{}, 826 WorkDir: "/", 827 User: "1000", 828 PrimaryGroup: "1000", 829 } 830 _, err := cmdToKataProcess(cmd) 831 assert.Nil(err) 832 833 cmd1 := cmd 834 cmd1.User = "foobar" 835 _, err = cmdToKataProcess(cmd1) 836 assert.Error(err) 837 838 cmd1 = cmd 839 cmd1.PrimaryGroup = "foobar" 840 _, err = cmdToKataProcess(cmd1) 841 assert.Error(err) 842 843 cmd1 = cmd 844 cmd1.User = "foobar:1000" 845 _, err = cmdToKataProcess(cmd1) 846 assert.Error(err) 847 848 cmd1 = cmd 849 cmd1.User = "1000:2000" 850 _, err = cmdToKataProcess(cmd1) 851 assert.Nil(err) 852 853 cmd1 = cmd 854 cmd1.SupplementaryGroups = []string{"foo"} 855 _, err = cmdToKataProcess(cmd1) 856 assert.Error(err) 857 858 cmd1 = cmd 859 cmd1.SupplementaryGroups = []string{"4000"} 860 _, err = cmdToKataProcess(cmd1) 861 assert.Nil(err) 862 } 863 864 func TestAgentCreateContainer(t *testing.T) { 865 assert := assert.New(t) 866 867 sandbox := &Sandbox{ 868 ctx: context.Background(), 869 id: "foobar", 870 config: &SandboxConfig{ 871 ID: "foobar", 872 HypervisorType: MockHypervisor, 873 HypervisorConfig: HypervisorConfig{ 874 KernelPath: "foo", 875 ImagePath: "bar", 876 }, 877 }, 878 hypervisor: &mockHypervisor{}, 879 } 880 881 newStore, err := persist.GetDriver() 882 assert.NoError(err) 883 assert.NotNil(newStore) 884 sandbox.newStore = newStore 885 886 container := &Container{ 887 ctx: sandbox.ctx, 888 id: "barfoo", 889 sandboxID: "foobar", 890 sandbox: sandbox, 891 state: types.ContainerState{ 892 Fstype: "xfs", 893 }, 894 config: &ContainerConfig{ 895 CustomSpec: &specs.Spec{}, 896 Annotations: map[string]string{}, 897 }, 898 } 899 900 impl := &gRPCProxy{} 901 902 proxy := mock.ProxyGRPCMock{ 903 GRPCImplementer: impl, 904 GRPCRegister: gRPCRegister, 905 } 906 907 sockDir, err := testGenerateKataProxySockDir() 908 assert.Nil(err) 909 defer os.RemoveAll(sockDir) 910 911 testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir) 912 err = proxy.Start(testKataProxyURL) 913 assert.Nil(err) 914 defer proxy.Stop() 915 916 k := &kataAgent{ 917 ctx: context.Background(), 918 state: KataAgentState{ 919 URL: testKataProxyURL, 920 }, 921 } 922 923 dir, err := ioutil.TempDir("", "kata-agent-test") 924 assert.Nil(err) 925 defer os.RemoveAll(dir) 926 927 err = k.configure(&mockHypervisor{}, sandbox.id, dir, true, KataAgentConfig{}) 928 assert.Nil(err) 929 930 // We'll fail on container metadata file creation, but it helps increasing coverage... 931 _, err = k.createContainer(sandbox, container) 932 assert.Error(err) 933 } 934 935 func TestAgentNetworkOperation(t *testing.T) { 936 assert := assert.New(t) 937 938 impl := &gRPCProxy{} 939 940 proxy := mock.ProxyGRPCMock{ 941 GRPCImplementer: impl, 942 GRPCRegister: gRPCRegister, 943 } 944 945 sockDir, err := testGenerateKataProxySockDir() 946 assert.NoError(err) 947 defer os.RemoveAll(sockDir) 948 949 testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir) 950 assert.NoError(proxy.Start(testKataProxyURL)) 951 defer proxy.Stop() 952 953 k := &kataAgent{ 954 ctx: context.Background(), 955 state: KataAgentState{ 956 URL: testKataProxyURL, 957 }, 958 } 959 960 _, err = k.updateInterface(nil) 961 assert.Nil(err) 962 963 _, err = k.listInterfaces() 964 assert.Nil(err) 965 966 _, err = k.updateRoutes([]*vcTypes.Route{}) 967 assert.Nil(err) 968 969 _, err = k.listRoutes() 970 assert.Nil(err) 971 } 972 973 func TestKataAgentSetProxy(t *testing.T) { 974 assert := assert.New(t) 975 976 k := &kataAgent{ctx: context.Background()} 977 p := &kataBuiltInProxy{} 978 s := &Sandbox{ 979 ctx: context.Background(), 980 id: "foobar", 981 } 982 983 err := k.setProxy(s, p, 0, "") 984 assert.Error(err) 985 } 986 987 func TestKataGetAgentUrl(t *testing.T) { 988 assert := assert.New(t) 989 var err error 990 991 k := &kataAgent{vmSocket: types.Socket{HostPath: "/abc"}} 992 assert.NoError(err) 993 url, err := k.getAgentURL() 994 assert.Nil(err) 995 assert.NotEmpty(url) 996 997 k.vmSocket = types.VSock{} 998 assert.NoError(err) 999 url, err = k.getAgentURL() 1000 assert.Nil(err) 1001 assert.NotEmpty(url) 1002 } 1003 1004 func TestKataCopyFile(t *testing.T) { 1005 assert := assert.New(t) 1006 1007 impl := &gRPCProxy{} 1008 1009 proxy := mock.ProxyGRPCMock{ 1010 GRPCImplementer: impl, 1011 GRPCRegister: gRPCRegister, 1012 } 1013 1014 sockDir, err := testGenerateKataProxySockDir() 1015 assert.NoError(err) 1016 defer os.RemoveAll(sockDir) 1017 1018 testKataProxyURL := fmt.Sprintf(testKataProxyURLTempl, sockDir) 1019 err = proxy.Start(testKataProxyURL) 1020 assert.NoError(err) 1021 defer proxy.Stop() 1022 1023 k := &kataAgent{ 1024 ctx: context.Background(), 1025 state: KataAgentState{ 1026 URL: testKataProxyURL, 1027 }, 1028 } 1029 1030 err = k.copyFile("/abc/xyz/123", "/tmp") 1031 assert.Error(err) 1032 1033 src, err := ioutil.TempFile("", "src") 1034 assert.NoError(err) 1035 defer os.Remove(src.Name()) 1036 1037 data := []byte("abcdefghi123456789") 1038 _, err = src.Write(data) 1039 assert.NoError(err) 1040 assert.NoError(src.Close()) 1041 1042 dst, err := ioutil.TempFile("", "dst") 1043 assert.NoError(err) 1044 assert.NoError(dst.Close()) 1045 defer os.Remove(dst.Name()) 1046 1047 orgGrpcMaxDataSize := grpcMaxDataSize 1048 grpcMaxDataSize = 1 1049 defer func() { 1050 grpcMaxDataSize = orgGrpcMaxDataSize 1051 }() 1052 1053 err = k.copyFile(src.Name(), dst.Name()) 1054 assert.NoError(err) 1055 } 1056 1057 func TestKataCleanupSandbox(t *testing.T) { 1058 assert := assert.New(t) 1059 1060 kataHostSharedDirSaved := kataHostSharedDir 1061 kataHostSharedDir = func() string { 1062 td, _ := ioutil.TempDir("", "kata-cleanup") 1063 return td 1064 } 1065 defer func() { 1066 kataHostSharedDir = kataHostSharedDirSaved 1067 }() 1068 1069 s := Sandbox{ 1070 id: "testFoo", 1071 } 1072 1073 dir := kataHostSharedDir() 1074 defer os.RemoveAll(dir) 1075 err := os.MkdirAll(path.Join(dir, s.id), 0777) 1076 assert.Nil(err) 1077 1078 k := &kataAgent{ctx: context.Background()} 1079 k.cleanup(&s) 1080 1081 _, err = os.Stat(dir) 1082 assert.False(os.IsExist(err)) 1083 } 1084 1085 func TestKataAgentKernelParams(t *testing.T) { 1086 assert := assert.New(t) 1087 1088 type testData struct { 1089 debug bool 1090 trace bool 1091 containerPipeSize uint32 1092 traceMode string 1093 traceType string 1094 expectedParams []Param 1095 } 1096 1097 debugParam := Param{Key: "agent.log", Value: "debug"} 1098 1099 traceIsolatedParam := Param{Key: "agent.trace", Value: "isolated"} 1100 traceCollatedParam := Param{Key: "agent.trace", Value: "collated"} 1101 1102 traceFooParam := Param{Key: "agent.trace", Value: "foo"} 1103 1104 containerPipeSizeParam := Param{Key: vcAnnotations.ContainerPipeSizeKernelParam, Value: "2097152"} 1105 1106 data := []testData{ 1107 {false, false, 0, "", "", []Param{}}, 1108 {true, false, 0, "", "", []Param{debugParam}}, 1109 1110 {false, false, 0, "foo", "", []Param{}}, 1111 {false, false, 0, "foo", "", []Param{}}, 1112 {false, false, 0, "", "foo", []Param{}}, 1113 {false, false, 0, "", "foo", []Param{}}, 1114 {false, false, 0, "foo", "foo", []Param{}}, 1115 {false, true, 0, "foo", "foo", []Param{}}, 1116 1117 {false, false, 0, agentTraceModeDynamic, "", []Param{}}, 1118 {false, false, 0, agentTraceModeStatic, "", []Param{}}, 1119 {false, false, 0, "", agentTraceTypeIsolated, []Param{}}, 1120 {false, false, 0, "", agentTraceTypeCollated, []Param{}}, 1121 {false, false, 0, "foo", agentTraceTypeIsolated, []Param{}}, 1122 {false, false, 0, "foo", agentTraceTypeCollated, []Param{}}, 1123 1124 {false, false, 0, agentTraceModeDynamic, agentTraceTypeIsolated, []Param{}}, 1125 {false, false, 0, agentTraceModeDynamic, agentTraceTypeCollated, []Param{}}, 1126 1127 {false, false, 0, agentTraceModeStatic, agentTraceTypeCollated, []Param{}}, 1128 {false, false, 0, agentTraceModeStatic, agentTraceTypeCollated, []Param{}}, 1129 1130 {false, true, 0, agentTraceModeDynamic, agentTraceTypeIsolated, []Param{}}, 1131 {false, true, 0, agentTraceModeDynamic, agentTraceTypeCollated, []Param{}}, 1132 {true, true, 0, agentTraceModeDynamic, agentTraceTypeCollated, []Param{debugParam}}, 1133 1134 {false, true, 0, "", agentTraceTypeIsolated, []Param{}}, 1135 {false, true, 0, "", agentTraceTypeCollated, []Param{}}, 1136 {true, true, 0, "", agentTraceTypeIsolated, []Param{debugParam}}, 1137 {true, true, 0, "", agentTraceTypeCollated, []Param{debugParam}}, 1138 {false, true, 0, "foo", agentTraceTypeIsolated, []Param{}}, 1139 {false, true, 0, "foo", agentTraceTypeCollated, []Param{}}, 1140 {true, true, 0, "foo", agentTraceTypeIsolated, []Param{debugParam}}, 1141 {true, true, 0, "foo", agentTraceTypeCollated, []Param{debugParam}}, 1142 1143 {false, true, 0, agentTraceModeStatic, agentTraceTypeIsolated, []Param{traceIsolatedParam}}, 1144 {false, true, 0, agentTraceModeStatic, agentTraceTypeCollated, []Param{traceCollatedParam}}, 1145 {true, true, 0, agentTraceModeStatic, agentTraceTypeIsolated, []Param{traceIsolatedParam, debugParam}}, 1146 {true, true, 0, agentTraceModeStatic, agentTraceTypeCollated, []Param{traceCollatedParam, debugParam}}, 1147 1148 {false, true, 0, agentTraceModeStatic, "foo", []Param{traceFooParam}}, 1149 {true, true, 0, agentTraceModeStatic, "foo", []Param{debugParam, traceFooParam}}, 1150 1151 {false, false, 0, "", "", []Param{}}, 1152 {false, false, 2097152, "", "", []Param{containerPipeSizeParam}}, 1153 } 1154 1155 for i, d := range data { 1156 config := KataAgentConfig{ 1157 Debug: d.debug, 1158 Trace: d.trace, 1159 TraceMode: d.traceMode, 1160 TraceType: d.traceType, 1161 ContainerPipeSize: d.containerPipeSize, 1162 } 1163 1164 count := len(d.expectedParams) 1165 1166 params := KataAgentKernelParams(config) 1167 1168 if count == 0 { 1169 assert.Emptyf(params, "test %d (%+v)", i, d) 1170 continue 1171 } 1172 1173 assert.Len(params, count) 1174 1175 for _, p := range d.expectedParams { 1176 assert.Containsf(params, p, "test %d (%+v)", i, d) 1177 } 1178 } 1179 } 1180 1181 func TestKataAgentHandleTraceSettings(t *testing.T) { 1182 assert := assert.New(t) 1183 1184 type testData struct { 1185 traceMode string 1186 trace bool 1187 expectDisableVMShutdown bool 1188 expectDynamicTracing bool 1189 } 1190 1191 data := []testData{ 1192 {"", false, false, false}, 1193 {"", true, false, false}, 1194 {agentTraceModeStatic, true, true, false}, 1195 {agentTraceModeDynamic, true, false, true}, 1196 } 1197 1198 for i, d := range data { 1199 k := &kataAgent{} 1200 1201 config := KataAgentConfig{ 1202 Trace: d.trace, 1203 TraceMode: d.traceMode, 1204 } 1205 1206 disableVMShutdown := k.handleTraceSettings(config) 1207 1208 if d.expectDisableVMShutdown { 1209 assert.Truef(disableVMShutdown, "test %d (%+v)", i, d) 1210 } else { 1211 assert.Falsef(disableVMShutdown, "test %d (%+v)", i, d) 1212 } 1213 1214 if d.expectDynamicTracing { 1215 assert.Truef(k.dynamicTracing, "test %d (%+v)", i, d) 1216 } else { 1217 assert.Falsef(k.dynamicTracing, "test %d (%+v)", i, d) 1218 } 1219 } 1220 } 1221 1222 func TestKataAgentSetDefaultTraceConfigOptions(t *testing.T) { 1223 assert := assert.New(t) 1224 1225 type testData struct { 1226 traceMode string 1227 traceType string 1228 trace bool 1229 expectDefaultTraceMode bool 1230 expectDefaultTraceType bool 1231 expectError bool 1232 } 1233 1234 data := []testData{ 1235 {"", "", false, false, false, false}, 1236 {agentTraceModeDynamic, agentTraceTypeCollated, false, false, false, false}, 1237 {agentTraceModeDynamic, agentTraceTypeIsolated, false, false, false, false}, 1238 {agentTraceModeStatic, agentTraceTypeCollated, false, false, false, false}, 1239 {agentTraceModeStatic, agentTraceTypeIsolated, false, false, false, false}, 1240 1241 {agentTraceModeDynamic, agentTraceTypeCollated, true, false, false, false}, 1242 {agentTraceModeDynamic, agentTraceTypeIsolated, true, false, false, false}, 1243 1244 {agentTraceModeStatic, agentTraceTypeCollated, true, false, false, false}, 1245 {agentTraceModeStatic, agentTraceTypeIsolated, true, false, false, false}, 1246 1247 {agentTraceModeDynamic, "", true, false, true, false}, 1248 {agentTraceModeDynamic, "invalid", true, false, false, true}, 1249 1250 {agentTraceModeStatic, "", true, false, true, false}, 1251 {agentTraceModeStatic, "invalid", true, false, false, true}, 1252 1253 {"", agentTraceTypeIsolated, true, true, false, false}, 1254 {"invalid", agentTraceTypeIsolated, true, false, false, true}, 1255 1256 {"", agentTraceTypeCollated, true, true, false, false}, 1257 {"invalid", agentTraceTypeCollated, true, false, false, true}, 1258 1259 {"", "", true, true, true, false}, 1260 {"invalid", "invalid", true, false, false, true}, 1261 } 1262 1263 for i, d := range data { 1264 config := &KataAgentConfig{ 1265 Trace: d.trace, 1266 TraceMode: d.traceMode, 1267 TraceType: d.traceType, 1268 } 1269 1270 err := KataAgentSetDefaultTraceConfigOptions(config) 1271 if d.expectError { 1272 assert.Error(err, "test %d (%+v)", i, d) 1273 continue 1274 } else { 1275 assert.NoError(err, "test %d (%+v)", i, d) 1276 } 1277 1278 if d.expectDefaultTraceMode { 1279 assert.Equalf(config.TraceMode, defaultAgentTraceMode, "test %d (%+v)", i, d) 1280 } 1281 1282 if d.expectDefaultTraceType { 1283 assert.Equalf(config.TraceType, defaultAgentTraceType, "test %d (%+v)", i, d) 1284 } 1285 } 1286 } 1287 1288 func TestKataAgentDirs(t *testing.T) { 1289 assert := assert.New(t) 1290 1291 uidmapFile, err := os.OpenFile("/proc/self/uid_map", os.O_RDONLY, 0) 1292 assert.NoError(err) 1293 1294 line, err := bufio.NewReader(uidmapFile).ReadBytes('\n') 1295 assert.NoError(err) 1296 1297 uidmap := strings.Fields(string(line)) 1298 expectedRootless := (uidmap[0] == "0" && uidmap[1] != "0") 1299 assert.Equal(expectedRootless, rootless.IsRootless()) 1300 1301 if expectedRootless { 1302 assert.Equal(kataHostSharedDir(), os.Getenv("XDG_RUNTIME_DIR")+defaultKataHostSharedDir) 1303 assert.Equal(kataGuestSharedDir(), os.Getenv("XDG_RUNTIME_DIR")+defaultKataGuestSharedDir) 1304 assert.Equal(kataGuestSandboxDir(), os.Getenv("XDG_RUNTIME_DIR")+defaultKataGuestSandboxDir) 1305 assert.Equal(ephemeralPath(), os.Getenv("XDG_RUNTIME_DIR")+defaultEphemeralPath) 1306 } else { 1307 assert.Equal(kataHostSharedDir(), defaultKataHostSharedDir) 1308 assert.Equal(kataGuestSharedDir(), defaultKataGuestSharedDir) 1309 assert.Equal(kataGuestSandboxDir(), defaultKataGuestSandboxDir) 1310 assert.Equal(ephemeralPath(), defaultEphemeralPath) 1311 } 1312 }