diff --git a/.github/workflows/darwin-tests.yaml b/.github/workflows/darwin-tests.yaml new file mode 100644 index 0000000000..5a83add32d --- /dev/null +++ b/.github/workflows/darwin-tests.yaml @@ -0,0 +1,25 @@ +on: + pull_request: + types: + - opened + - edited + - reopened + - synchronize + +name: Darwin tests +jobs: + test: + strategy: + matrix: + go-version: [1.16.x, 1.17.x] + os: [macos-latest] + runs-on: ${{ matrix.os }} + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: ${{ matrix.go-version }} + - name: Checkout code + uses: actions/checkout@v2 + - name: Build utils + run: ./ci/darwin-test.sh diff --git a/ci/darwin-test.sh b/ci/darwin-test.sh new file mode 100755 index 0000000000..92317653be --- /dev/null +++ b/ci/darwin-test.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2022 Apple Inc. +# +# SPDX-License-Identifier: Apache-2.0 + +set -e + +cidir=$(dirname "$0") +runtimedir=$cidir/../src/runtime + +build_working_packages() { + # working packages: + device_api=$runtimedir/virtcontainers/device/api + device_config=$runtimedir/virtcontainers/device/config + device_drivers=$runtimedir/virtcontainers/device/drivers + device_manager=$runtimedir/virtcontainers/device/manager + rc_pkg_dir=$runtimedir/pkg/resourcecontrol/ + utils_pkg_dir=$runtimedir/virtcontainers/utils + + # broken packages :( : + #katautils=$runtimedir/pkg/katautils + #oci=$runtimedir/pkg/oci + #vc=$runtimedir/virtcontainers + + pkgs=( + "$device_api" + "$device_config" + "$device_drivers" + "$device_manager" + "$utils_pkg_dir" + "$rc_pkg_dir") + for pkg in "${pkgs[@]}"; do + echo building "$pkg" + pushd "$pkg" &>/dev/null + go build + go test + popd &>/dev/null + done +} + +build_working_packages diff --git a/src/runtime/pkg/katautils/hook.go b/src/runtime/pkg/katautils/hook.go index 303773e602..50ac95cb85 100644 --- a/src/runtime/pkg/katautils/hook.go +++ b/src/runtime/pkg/katautils/hook.go @@ -16,6 +16,7 @@ import ( "time" "github.com/kata-containers/kata-containers/src/runtime/pkg/katautils/katatrace" + syscallWrapper "github.com/kata-containers/kata-containers/src/runtime/pkg/syscall" "github.com/opencontainers/runtime-spec/specs-go" "github.com/sirupsen/logrus" ) @@ -38,7 +39,7 @@ func runHook(ctx context.Context, spec specs.Spec, hook specs.Hook, cid, bundleP katatrace.AddTags(span, "path", hook.Path, "args", hook.Args) state := specs.State{ - Pid: syscall.Gettid(), + Pid: syscallWrapper.Gettid(), Bundle: bundlePath, ID: cid, Annotations: spec.Annotations, diff --git a/src/runtime/pkg/katautils/network_darwin.go b/src/runtime/pkg/katautils/network_darwin.go new file mode 100644 index 0000000000..d913557cb8 --- /dev/null +++ b/src/runtime/pkg/katautils/network_darwin.go @@ -0,0 +1,22 @@ +// Copyright (c) 2022 Apple Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package katautils + +import ( + vc "github.com/kata-containers/kata-containers/src/runtime/virtcontainers" +) + +func EnterNetNS(networkID string, cb func() error) error { + return nil +} + +func SetupNetworkNamespace(config *vc.NetworkConfig) error { + return nil +} + +func cleanupNetNS(netNSPath string) error { + return nil +} diff --git a/src/runtime/pkg/katautils/network.go b/src/runtime/pkg/katautils/network_linux.go similarity index 100% rename from src/runtime/pkg/katautils/network.go rename to src/runtime/pkg/katautils/network_linux.go diff --git a/src/runtime/pkg/resourcecontrol/utils.go b/src/runtime/pkg/resourcecontrol/utils.go index 9ab592be17..835cb54c47 100644 --- a/src/runtime/pkg/resourcecontrol/utils.go +++ b/src/runtime/pkg/resourcecontrol/utils.go @@ -7,6 +7,7 @@ package resourcecontrol import ( "fmt" + "strings" "github.com/opencontainers/runc/libcontainer/devices" "github.com/opencontainers/runtime-spec/specs-go" @@ -35,8 +36,8 @@ func DeviceToCgroupDeviceRule(device string) (*devices.Rule, error) { return nil, fmt.Errorf("unsupported device type: %v", devType) } - major := int64(unix.Major(st.Rdev)) - minor := int64(unix.Minor(st.Rdev)) + major := int64(unix.Major(uint64(st.Rdev))) + minor := int64(unix.Minor(uint64(st.Rdev))) deviceRule.Major = major deviceRule.Minor = minor @@ -57,3 +58,20 @@ func DeviceToLinuxDevice(device string) (specs.LinuxDeviceCgroup, error) { Access: string(dev.Permissions), }, nil } + +func IsSystemdCgroup(cgroupPath string) bool { + + // If we are utilizing systemd to manage cgroups, we expect to receive a path + // in the format slice:scopeprefix:name. A typical example would be: + // + // system.slice:docker:6b4c4a4d0cc2a12c529dcb13a2b8e438dfb3b2a6af34d548d7d + // + // Based on this, let's split by the ':' delimiter and verify that the first + // section has .slice as a suffix. + parts := strings.Split(cgroupPath, ":") + if len(parts) == 3 && strings.HasSuffix(parts[0], ".slice") { + return true + } + + return false +} diff --git a/src/runtime/pkg/resourcecontrol/utils_linux.go b/src/runtime/pkg/resourcecontrol/utils_linux.go index 7a83db8f00..73d77dc235 100644 --- a/src/runtime/pkg/resourcecontrol/utils_linux.go +++ b/src/runtime/pkg/resourcecontrol/utils_linux.go @@ -43,23 +43,6 @@ func ValidCgroupPath(path string, systemdCgroup bool) (string, error) { return filepath.Join(DefaultResourceControllerID, filepath.Clean("/"+path)), nil } -func IsSystemdCgroup(cgroupPath string) bool { - - // If we are utilizing systemd to manage cgroups, we expect to receive a path - // in the format slice:scopeprefix:name. A typical example would be: - // - // system.slice:docker:6b4c4a4d0cc2a12c529dcb13a2b8e438dfb3b2a6af34d548d7d - // - // Based on this, let's split by the ':' delimiter and verify that the first - // section has .slice as a suffix. - parts := strings.Split(cgroupPath, ":") - if len(parts) == 3 && strings.HasSuffix(parts[0], ".slice") { - return true - } - - return false -} - func newProperty(name string, units interface{}) systemdDbus.Property { return systemdDbus.Property{ Name: name, diff --git a/src/runtime/pkg/syscall/syscall_darwin.go b/src/runtime/pkg/syscall/syscall_darwin.go new file mode 100644 index 0000000000..a5cc79d18b --- /dev/null +++ b/src/runtime/pkg/syscall/syscall_darwin.go @@ -0,0 +1,16 @@ +// Copyright (c) 2022 Apple Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package syscall + +import ( + "syscall" +) + +func Gettid() int { + // There is no equivalent to a thread ID on Darwin. + // We use the PID instead. + return syscall.Getpid() +} diff --git a/src/runtime/pkg/syscall/syscall_linux.go b/src/runtime/pkg/syscall/syscall_linux.go new file mode 100644 index 0000000000..b05fc156d1 --- /dev/null +++ b/src/runtime/pkg/syscall/syscall_linux.go @@ -0,0 +1,14 @@ +// Copyright (c) 2022 Apple Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package syscall + +import ( + "syscall" +) + +func Gettid() int { + return syscall.Gettid() +} diff --git a/src/runtime/virtcontainers/container.go b/src/runtime/virtcontainers/container.go index b57f40e51b..82aae79e37 100644 --- a/src/runtime/virtcontainers/container.go +++ b/src/runtime/virtcontainers/container.go @@ -1,6 +1,3 @@ -//go:build linux -// +build linux - // Copyright (c) 2016 Intel Corporation // Copyright (c) 2014,2015,2016,2017 Docker, Inc. // SPDX-License-Identifier: Apache-2.0 @@ -629,8 +626,8 @@ func (c *Container) createBlockDevices(ctx context.Context) error { HostPath: m.Source, ContainerPath: m.Destination, DevType: "b", - Major: int64(unix.Major(stat.Rdev)), - Minor: int64(unix.Minor(stat.Rdev)), + Major: int64(unix.Major(uint64(stat.Rdev))), + Minor: int64(unix.Minor(uint64(stat.Rdev))), ReadOnly: m.ReadOnly, } // Check whether source can be used as a pmem device @@ -1226,8 +1223,8 @@ func (c *Container) plugDevice(ctx context.Context, devicePath string) error { HostPath: devicePath, ContainerPath: filepath.Join(kataGuestSharedDir(), c.id), DevType: "b", - Major: int64(unix.Major(stat.Rdev)), - Minor: int64(unix.Minor(stat.Rdev)), + Major: int64(unix.Major(uint64(stat.Rdev))), + Minor: int64(unix.Minor(uint64(stat.Rdev))), }) if err != nil { return fmt.Errorf("device manager failed to create rootfs device for %q: %v", devicePath, err) diff --git a/src/runtime/virtcontainers/device/config/config.go b/src/runtime/virtcontainers/device/config/config.go index 835059ed6f..69be4f5832 100644 --- a/src/runtime/virtcontainers/device/config/config.go +++ b/src/runtime/virtcontainers/device/config/config.go @@ -425,8 +425,8 @@ func getVhostUserDevName(dirname string, majorNum, minorNum uint32) (string, err return "", err } - devMajor := unix.Major(devStat.Rdev) - devMinor := unix.Minor(devStat.Rdev) + devMajor := unix.Major(uint64(devStat.Rdev)) + devMinor := unix.Minor(uint64(devStat.Rdev)) if devMajor == majorNum && devMinor == minorNum { return file.Name(), nil } diff --git a/src/runtime/virtcontainers/device/config/pmem.go b/src/runtime/virtcontainers/device/config/pmem.go index 33ce4fdff4..81d1da9b57 100644 --- a/src/runtime/virtcontainers/device/config/pmem.go +++ b/src/runtime/virtcontainers/device/config/pmem.go @@ -51,8 +51,8 @@ func PmemDeviceInfo(source, destination string) (*DeviceInfo, error) { device := &DeviceInfo{ ContainerPath: destination, DevType: "b", - Major: int64(unix.Major(stat.Dev)), - Minor: int64(unix.Minor(stat.Dev)), + Major: int64(unix.Major(uint64(stat.Dev))), + Minor: int64(unix.Minor(uint64(stat.Dev))), Pmem: true, DriverOptions: make(map[string]string), } diff --git a/src/runtime/virtcontainers/device/manager/manager_linux_test.go b/src/runtime/virtcontainers/device/manager/manager_linux_test.go new file mode 100644 index 0000000000..78773fc5c2 --- /dev/null +++ b/src/runtime/virtcontainers/device/manager/manager_linux_test.go @@ -0,0 +1,100 @@ +// Copyright (c) 2017 Intel Corporation +// Copyright (c) 2018 Huawei Corporation +// +// SPDX-License-Identifier: Apache-2.0 +// + +package manager + +import ( + "context" + "fmt" + "os" + "path/filepath" + "testing" + + ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" + "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/api" + "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/config" + "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/drivers" + "github.com/stretchr/testify/assert" + + "golang.org/x/sys/unix" +) + +func TestAttachVhostUserBlkDevice(t *testing.T) { + rootEnabled := true + tc := ktu.NewTestConstraint(false) + if tc.NotValid(ktu.NeedRoot()) { + rootEnabled = false + } + + tmpDir, err := os.MkdirTemp("", "") + dm := &deviceManager{ + blockDriver: VirtioBlock, + devices: make(map[string]api.Device), + vhostUserStoreEnabled: true, + vhostUserStorePath: tmpDir, + } + assert.Nil(t, err) + defer os.RemoveAll(tmpDir) + + vhostUserDevNodePath := filepath.Join(tmpDir, "/block/devices/") + vhostUserSockPath := filepath.Join(tmpDir, "/block/sockets/") + deviceNodePath := filepath.Join(vhostUserDevNodePath, "vhostblk0") + deviceSockPath := filepath.Join(vhostUserSockPath, "vhostblk0") + + err = os.MkdirAll(vhostUserDevNodePath, dirMode) + assert.Nil(t, err) + err = os.MkdirAll(vhostUserSockPath, dirMode) + assert.Nil(t, err) + _, err = os.Create(deviceSockPath) + assert.Nil(t, err) + + // mknod requires root privilege, call mock function for non-root to + // get VhostUserBlk device type. + if rootEnabled == true { + err = unix.Mknod(deviceNodePath, unix.S_IFBLK, int(unix.Mkdev(config.VhostUserBlkMajor, 0))) + assert.Nil(t, err) + } else { + savedFunc := config.GetVhostUserNodeStatFunc + + _, err = os.Create(deviceNodePath) + assert.Nil(t, err) + + config.GetVhostUserNodeStatFunc = func(devNodePath string, + devNodeStat *unix.Stat_t) error { + if deviceNodePath != devNodePath { + return fmt.Errorf("mock GetVhostUserNodeStatFunc error") + } + + devNodeStat.Rdev = unix.Mkdev(config.VhostUserBlkMajor, 0) + return nil + } + + defer func() { + config.GetVhostUserNodeStatFunc = savedFunc + }() + } + + path := "/dev/vda" + deviceInfo := config.DeviceInfo{ + HostPath: deviceNodePath, + ContainerPath: path, + DevType: "b", + Major: config.VhostUserBlkMajor, + Minor: 0, + } + + devReceiver := &api.MockDeviceReceiver{} + device, err := dm.NewDevice(deviceInfo) + assert.Nil(t, err) + _, ok := device.(*drivers.VhostUserBlkDevice) + assert.True(t, ok) + + err = device.Attach(context.Background(), devReceiver) + assert.Nil(t, err) + + err = device.Detach(context.Background(), devReceiver) + assert.Nil(t, err) +} diff --git a/src/runtime/virtcontainers/device/manager/manager_test.go b/src/runtime/virtcontainers/device/manager/manager_test.go index d6fab6d262..f0d7ef974d 100644 --- a/src/runtime/virtcontainers/device/manager/manager_test.go +++ b/src/runtime/virtcontainers/device/manager/manager_test.go @@ -8,19 +8,15 @@ package manager import ( "context" - "fmt" "os" "path/filepath" "strconv" "testing" - ktu "github.com/kata-containers/kata-containers/src/runtime/pkg/katatestutils" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/api" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/config" "github.com/kata-containers/kata-containers/src/runtime/virtcontainers/device/drivers" "github.com/stretchr/testify/assert" - - "golang.org/x/sys/unix" ) const fileMode0640 = os.FileMode(0640) @@ -217,83 +213,6 @@ func TestAttachBlockDevice(t *testing.T) { assert.Nil(t, err) } -func TestAttachVhostUserBlkDevice(t *testing.T) { - rootEnabled := true - tc := ktu.NewTestConstraint(false) - if tc.NotValid(ktu.NeedRoot()) { - rootEnabled = false - } - - tmpDir, err := os.MkdirTemp("", "") - dm := &deviceManager{ - blockDriver: VirtioBlock, - devices: make(map[string]api.Device), - vhostUserStoreEnabled: true, - vhostUserStorePath: tmpDir, - } - assert.Nil(t, err) - defer os.RemoveAll(tmpDir) - - vhostUserDevNodePath := filepath.Join(tmpDir, "/block/devices/") - vhostUserSockPath := filepath.Join(tmpDir, "/block/sockets/") - deviceNodePath := filepath.Join(vhostUserDevNodePath, "vhostblk0") - deviceSockPath := filepath.Join(vhostUserSockPath, "vhostblk0") - - err = os.MkdirAll(vhostUserDevNodePath, dirMode) - assert.Nil(t, err) - err = os.MkdirAll(vhostUserSockPath, dirMode) - assert.Nil(t, err) - _, err = os.Create(deviceSockPath) - assert.Nil(t, err) - - // mknod requires root privilege, call mock function for non-root to - // get VhostUserBlk device type. - if rootEnabled == true { - err = unix.Mknod(deviceNodePath, unix.S_IFBLK, int(unix.Mkdev(config.VhostUserBlkMajor, 0))) - assert.Nil(t, err) - } else { - savedFunc := config.GetVhostUserNodeStatFunc - - _, err = os.Create(deviceNodePath) - assert.Nil(t, err) - - config.GetVhostUserNodeStatFunc = func(devNodePath string, - devNodeStat *unix.Stat_t) error { - if deviceNodePath != devNodePath { - return fmt.Errorf("mock GetVhostUserNodeStatFunc error") - } - - devNodeStat.Rdev = unix.Mkdev(config.VhostUserBlkMajor, 0) - return nil - } - - defer func() { - config.GetVhostUserNodeStatFunc = savedFunc - }() - } - - path := "/dev/vda" - deviceInfo := config.DeviceInfo{ - HostPath: deviceNodePath, - ContainerPath: path, - DevType: "b", - Major: config.VhostUserBlkMajor, - Minor: 0, - } - - devReceiver := &api.MockDeviceReceiver{} - device, err := dm.NewDevice(deviceInfo) - assert.Nil(t, err) - _, ok := device.(*drivers.VhostUserBlkDevice) - assert.True(t, ok) - - err = device.Attach(context.Background(), devReceiver) - assert.Nil(t, err) - - err = device.Detach(context.Background(), devReceiver) - assert.Nil(t, err) -} - func TestAttachDetachDevice(t *testing.T) { dm := NewDeviceManager(VirtioSCSI, false, "", nil) diff --git a/src/runtime/virtcontainers/kata_agent.go b/src/runtime/virtcontainers/kata_agent.go index 1a10543051..47a1c1cc3f 100644 --- a/src/runtime/virtcontainers/kata_agent.go +++ b/src/runtime/virtcontainers/kata_agent.go @@ -2084,7 +2084,7 @@ func (k *kataAgent) copyFile(ctx context.Context, src, dst string) error { cpReq := &grpc.CopyFileRequest{ Path: dst, DirMode: uint32(DirMode), - FileMode: st.Mode, + FileMode: uint32(st.Mode), FileSize: fileSize, Uid: int32(st.Uid), Gid: int32(st.Gid), diff --git a/src/runtime/virtcontainers/mount.go b/src/runtime/virtcontainers/mount.go index 76e5fe3f49..c2879f2135 100644 --- a/src/runtime/virtcontainers/mount.go +++ b/src/runtime/virtcontainers/mount.go @@ -144,8 +144,8 @@ func getDeviceForPath(path string) (device, error) { if isHostDevice(path) { // stat.Rdev describes the device that this file (inode) represents. - devMajor = major(stat.Rdev) - devMinor = minor(stat.Rdev) + devMajor = major(uint64(stat.Rdev)) + devMinor = minor(uint64(stat.Rdev)) return device{ major: devMajor, @@ -154,8 +154,8 @@ func getDeviceForPath(path string) (device, error) { }, nil } // stat.Dev points to the underlying device containing the file - devMajor = major(stat.Dev) - devMinor = minor(stat.Dev) + devMajor = major(uint64(stat.Dev)) + devMinor = minor(uint64(stat.Dev)) path, err = filepath.Abs(path) if err != nil { diff --git a/src/runtime/virtcontainers/utils/utils_darwin.go b/src/runtime/virtcontainers/utils/utils_darwin.go new file mode 100644 index 0000000000..54b2124ce1 --- /dev/null +++ b/src/runtime/virtcontainers/utils/utils_darwin.go @@ -0,0 +1,10 @@ +// Copyright (c) 2022 Apple Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// + +package utils + +func GetDevicePathAndFsTypeOptions(mountPoint string) (devicePath, fsType string, fsOptions []string, err error) { + return +}