pkg/cgroups: implement functions to get information from a host device

Add functions to convert a host device to a cgroup device or linux device,
the first one is used to update the device cgroup and the second one to
update the resources in the OCI spec.

Signed-off-by: Julio Montes <julio.montes@intel.com>
Signed-off-by: Peng Tao <bergwolf@hyper.sh>
This commit is contained in:
Julio Montes 2020-05-26 00:27:30 -07:00 committed by Peng Tao
parent 387d3d34dc
commit 045c7ae9a3
2 changed files with 114 additions and 0 deletions

View File

@ -7,8 +7,13 @@ package cgroups
import ( import (
"fmt" "fmt"
"os"
"path/filepath" "path/filepath"
"regexp" "regexp"
"github.com/opencontainers/runc/libcontainer/configs"
"github.com/opencontainers/runtime-spec/specs-go"
"golang.org/x/sys/unix"
) )
// prepend a kata specific string to oci cgroup path to // prepend a kata specific string to oci cgroup path to
@ -63,3 +68,53 @@ func IsSystemdCgroup(cgroupPath string) bool {
// it's a correct systemd cgroup path. // it's a correct systemd cgroup path.
return found != nil && cgroupPath[found[0]:found[1]] == cgroupPath return found != nil && cgroupPath[found[0]:found[1]] == cgroupPath
} }
func DeviceToCgroupDevice(device string) (*configs.Device, error) {
var st unix.Stat_t
linuxDevice := configs.Device{
Allow: true,
Permissions: "rwm",
Path: device,
}
if err := unix.Stat(device, &st); err != nil {
return nil, err
}
devType := st.Mode & unix.S_IFMT
switch devType {
case unix.S_IFCHR:
linuxDevice.Type = 'c'
case unix.S_IFBLK:
linuxDevice.Type = 'b'
default:
return nil, fmt.Errorf("unsupported device type: %v", devType)
}
major := int64(unix.Major(st.Rdev))
minor := int64(unix.Minor(st.Rdev))
linuxDevice.Major = major
linuxDevice.Minor = minor
linuxDevice.Gid = st.Gid
linuxDevice.Uid = st.Uid
linuxDevice.FileMode = os.FileMode(st.Mode)
return &linuxDevice, nil
}
func DeviceToLinuxDevice(device string) (specs.LinuxDeviceCgroup, error) {
dev, err := DeviceToCgroupDevice(device)
if err != nil {
return specs.LinuxDeviceCgroup{}, err
}
return specs.LinuxDeviceCgroup{
Allow: dev.Allow,
Type: string(dev.Type),
Major: &dev.Major,
Minor: &dev.Minor,
Access: dev.Permissions,
}, nil
}

View File

@ -6,6 +6,8 @@
package cgroups package cgroups
import ( import (
"io/ioutil"
"os"
"path/filepath" "path/filepath"
"strings" "strings"
"testing" "testing"
@ -102,3 +104,60 @@ func TestValidCgroupPath(t *testing.T) {
} }
} }
func TestDeviceToCgroupDevice(t *testing.T) {
assert := assert.New(t)
f, err := ioutil.TempFile("", "device")
assert.NoError(err)
f.Close()
// fail: regular file to device
dev, err := DeviceToCgroupDevice(f.Name())
assert.Error(err)
assert.Nil(dev)
// fail: no such file
os.Remove(f.Name())
dev, err = DeviceToCgroupDevice(f.Name())
assert.Error(err)
assert.Nil(dev)
devPath := "/dev/null"
if _, err := os.Stat(devPath); os.IsNotExist(err) {
t.Skipf("no such device: %v", devPath)
return
}
dev, err = DeviceToCgroupDevice(devPath)
assert.NoError(err)
assert.NotNil(dev)
assert.Equal(dev.Type, 'c')
assert.Equal(dev.Path, devPath)
assert.NotZero(dev.Major)
assert.NotZero(dev.Minor)
assert.NotEmpty(dev.Permissions)
assert.NotZero(dev.FileMode)
assert.Zero(dev.Uid)
assert.Zero(dev.Gid)
assert.True(dev.Allow)
}
func TestDeviceToLinuxDevice(t *testing.T) {
assert := assert.New(t)
devPath := "/dev/null"
if _, err := os.Stat(devPath); os.IsNotExist(err) {
t.Skipf("no such device: %v", devPath)
return
}
dev, err := DeviceToLinuxDevice(devPath)
assert.NoError(err)
assert.NotNil(dev)
assert.Equal(dev.Type, "c")
assert.NotNil(dev.Major)
assert.NotZero(*dev.Major)
assert.NotNil(dev.Minor)
assert.NotZero(*dev.Minor)
assert.NotEmpty(dev.Access)
assert.True(dev.Allow)
}