mirror of
https://github.com/containers/podman.git
synced 2025-07-03 17:27:18 +08:00
Merge pull request #5152 from QiWang19/device-cgroup-rule
support device-cgroup-rule
This commit is contained in:
@ -256,6 +256,10 @@ func getCreateFlags(c *cliconfig.PodmanCommand) {
|
||||
"device", []string{},
|
||||
"Add a host device to the container (default [])",
|
||||
)
|
||||
createFlags.StringSlice(
|
||||
"device-cgroup-rule", []string{},
|
||||
"Add a rule to the cgroup allowed devices list",
|
||||
)
|
||||
createFlags.StringSlice(
|
||||
"device-read-bps", []string{},
|
||||
"Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)",
|
||||
|
@ -758,6 +758,7 @@ func ParseCreateOpts(ctx context.Context, c *GenericCLIResults, runtime *libpod.
|
||||
CPURtPeriod: c.Uint64("cpu-rt-period"),
|
||||
CPURtRuntime: c.Int64("cpu-rt-runtime"),
|
||||
CPUs: c.Float64("cpus"),
|
||||
DeviceCgroupRules: c.StringSlice("device-cgroup-rule"),
|
||||
DeviceReadBps: c.StringSlice("device-read-bps"),
|
||||
DeviceReadIOps: c.StringSlice("device-read-iops"),
|
||||
DeviceWriteBps: c.StringSlice("device-write-bps"),
|
||||
|
@ -386,6 +386,7 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
|
||||
m["detach"] = newCRBool(c, "detach")
|
||||
m["detach-keys"] = newCRString(c, "detach-keys")
|
||||
m["device"] = newCRStringSlice(c, "device")
|
||||
m["device-cgroup-rule"] = newCRStringSlice(c, "device-cgroup-rule")
|
||||
m["device-read-bps"] = newCRStringSlice(c, "device-read-bps")
|
||||
m["device-read-iops"] = newCRStringSlice(c, "device-read-iops")
|
||||
m["device-write-bps"] = newCRStringSlice(c, "device-write-bps")
|
||||
|
@ -1873,6 +1873,7 @@ _podman_container_run() {
|
||||
--cpuset-mems
|
||||
--cpu-shares -c
|
||||
--device
|
||||
--device-cgroup-rule
|
||||
--device-read-bps
|
||||
--device-read-iops
|
||||
--device-write-bps
|
||||
|
@ -209,6 +209,13 @@ Note: if the user only has access rights via a group then accessing the device
|
||||
from inside a rootless container will fail. The `crun` runtime offers a
|
||||
workaround for this by adding the option `--annotation run.oci.keep_original_groups=1`.
|
||||
|
||||
**--device-cgroup-rule**="type major:minor mode"
|
||||
|
||||
Add a rule to the cgroup allowed devices list. The rule is expected to be in the format specified in the Linux kernel documentation (Documentation/cgroup-v1/devices.txt):
|
||||
- type: a (all), c (char), or b (block);
|
||||
- major and minor: either a number, or * for all;
|
||||
- mode: a composition of r (read), w (write), and m (mknod(2)).
|
||||
|
||||
**--device-read-bps**=*path*
|
||||
|
||||
Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)
|
||||
|
@ -7,6 +7,7 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/containers/libpod/pkg/rootless"
|
||||
@ -90,6 +91,42 @@ func devicesFromPath(g *generate.Generator, devicePath string) error {
|
||||
return addDevice(g, strings.Join(append([]string{resolvedDevicePath}, devs[1:]...), ":"))
|
||||
}
|
||||
|
||||
func deviceCgroupRules(g *generate.Generator, deviceCgroupRules []string) error {
|
||||
for _, deviceCgroupRule := range deviceCgroupRules {
|
||||
if err := validateDeviceCgroupRule(deviceCgroupRule); err != nil {
|
||||
return err
|
||||
}
|
||||
ss := parseDeviceCgroupRule(deviceCgroupRule)
|
||||
if len(ss[0]) != 5 {
|
||||
return errors.Errorf("invalid device cgroup rule format: '%s'", deviceCgroupRule)
|
||||
}
|
||||
matches := ss[0]
|
||||
var major, minor *int64
|
||||
if matches[2] == "*" {
|
||||
majorDev := int64(-1)
|
||||
major = &majorDev
|
||||
} else {
|
||||
majorDev, err := strconv.ParseInt(matches[2], 10, 64)
|
||||
if err != nil {
|
||||
return errors.Errorf("invalid major value in device cgroup rule format: '%s'", deviceCgroupRule)
|
||||
}
|
||||
major = &majorDev
|
||||
}
|
||||
if matches[3] == "*" {
|
||||
minorDev := int64(-1)
|
||||
minor = &minorDev
|
||||
} else {
|
||||
minorDev, err := strconv.ParseInt(matches[2], 10, 64)
|
||||
if err != nil {
|
||||
return errors.Errorf("invalid major value in device cgroup rule format: '%s'", deviceCgroupRule)
|
||||
}
|
||||
minor = &minorDev
|
||||
}
|
||||
g.AddLinuxResourcesDevice(true, matches[1], major, minor, matches[4])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func addDevice(g *generate.Generator, device string) error {
|
||||
src, dst, permissions, err := ParseDevice(device)
|
||||
if err != nil {
|
||||
|
@ -30,3 +30,7 @@ func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrott
|
||||
func devicesFromPath(g *generate.Generator, devicePath string) error {
|
||||
return errors.New("function not implemented")
|
||||
}
|
||||
|
||||
func deviceCgroupRules(g *generate.Generator, deviceCgroupRules []string) error {
|
||||
return errors.New("function not implemented")
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ type CreateResourceConfig struct {
|
||||
CPUs float64 // cpus
|
||||
CPUsetCPUs string
|
||||
CPUsetMems string // cpuset-mems
|
||||
DeviceCgroupRules []string //device-cgroup-rule
|
||||
DeviceReadBps []string // device-read-bps
|
||||
DeviceReadIOps []string // device-read-iops
|
||||
DeviceWriteBps []string // device-write-bps
|
||||
|
@ -2,12 +2,17 @@ package createconfig
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/go-units"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// deviceCgroupRulegex defines the valid format of device-cgroup-rule
|
||||
var deviceCgroupRuleRegex = regexp.MustCompile(`^([acb]) ([0-9]+|\*):([0-9]+|\*) ([rwm]{1,3})$`)
|
||||
|
||||
// Pod signifies a kernel namespace is being shared
|
||||
// by a container with the pod it is associated with
|
||||
const Pod = "pod"
|
||||
@ -205,3 +210,16 @@ func IsValidDeviceMode(mode string) bool {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// validateDeviceCgroupRule validates the format of deviceCgroupRule
|
||||
func validateDeviceCgroupRule(deviceCgroupRule string) error {
|
||||
if !deviceCgroupRuleRegex.MatchString(deviceCgroupRule) {
|
||||
return errors.Errorf("invalid device cgroup rule format: '%s'", deviceCgroupRule)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// parseDeviceCgroupRule matches and parses the deviceCgroupRule into slice
|
||||
func parseDeviceCgroupRule(deviceCgroupRule string) [][]string {
|
||||
return deviceCgroupRuleRegex.FindAllStringSubmatch(deviceCgroupRule, -1)
|
||||
}
|
||||
|
@ -232,6 +232,12 @@ func (config *CreateConfig) createConfigToOCISpec(runtime *libpod.Runtime, userM
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if len(config.Resources.DeviceCgroupRules) != 0 {
|
||||
if err := deviceCgroupRules(&g, config.Resources.DeviceCgroupRules); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
addedResources = true
|
||||
}
|
||||
}
|
||||
|
||||
// SECURITY OPTS
|
||||
|
@ -999,4 +999,16 @@ USER mail`
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
||||
})
|
||||
|
||||
It("podman run --device-cgroup-rule", func() {
|
||||
SkipIfRemote()
|
||||
SkipIfRootless()
|
||||
deviceCgroupRule := "c 42:* rwm"
|
||||
session := podmanTest.Podman([]string{"run", "--name", "test", "-d", "--device-cgroup-rule", deviceCgroupRule, ALPINE, "top"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
session = podmanTest.Podman([]string{"exec", "test", "mknod", "newDev", "c", "42", "1"})
|
||||
session.WaitWithDefaultTimeout()
|
||||
Expect(session.ExitCode()).To(Equal(0))
|
||||
})
|
||||
})
|
||||
|
Reference in New Issue
Block a user