mirror of
https://github.com/containers/podman.git
synced 2025-07-04 18:27:33 +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{},
|
"device", []string{},
|
||||||
"Add a host device to the container (default [])",
|
"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(
|
createFlags.StringSlice(
|
||||||
"device-read-bps", []string{},
|
"device-read-bps", []string{},
|
||||||
"Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)",
|
"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"),
|
CPURtPeriod: c.Uint64("cpu-rt-period"),
|
||||||
CPURtRuntime: c.Int64("cpu-rt-runtime"),
|
CPURtRuntime: c.Int64("cpu-rt-runtime"),
|
||||||
CPUs: c.Float64("cpus"),
|
CPUs: c.Float64("cpus"),
|
||||||
|
DeviceCgroupRules: c.StringSlice("device-cgroup-rule"),
|
||||||
DeviceReadBps: c.StringSlice("device-read-bps"),
|
DeviceReadBps: c.StringSlice("device-read-bps"),
|
||||||
DeviceReadIOps: c.StringSlice("device-read-iops"),
|
DeviceReadIOps: c.StringSlice("device-read-iops"),
|
||||||
DeviceWriteBps: c.StringSlice("device-write-bps"),
|
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"] = newCRBool(c, "detach")
|
||||||
m["detach-keys"] = newCRString(c, "detach-keys")
|
m["detach-keys"] = newCRString(c, "detach-keys")
|
||||||
m["device"] = newCRStringSlice(c, "device")
|
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-bps"] = newCRStringSlice(c, "device-read-bps")
|
||||||
m["device-read-iops"] = newCRStringSlice(c, "device-read-iops")
|
m["device-read-iops"] = newCRStringSlice(c, "device-read-iops")
|
||||||
m["device-write-bps"] = newCRStringSlice(c, "device-write-bps")
|
m["device-write-bps"] = newCRStringSlice(c, "device-write-bps")
|
||||||
|
@ -1873,6 +1873,7 @@ _podman_container_run() {
|
|||||||
--cpuset-mems
|
--cpuset-mems
|
||||||
--cpu-shares -c
|
--cpu-shares -c
|
||||||
--device
|
--device
|
||||||
|
--device-cgroup-rule
|
||||||
--device-read-bps
|
--device-read-bps
|
||||||
--device-read-iops
|
--device-read-iops
|
||||||
--device-write-bps
|
--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
|
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`.
|
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*
|
**--device-read-bps**=*path*
|
||||||
|
|
||||||
Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)
|
Limit read rate (bytes per second) from a device (e.g. --device-read-bps=/dev/sda:1mb)
|
||||||
|
@ -7,6 +7,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/containers/libpod/pkg/rootless"
|
"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:]...), ":"))
|
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 {
|
func addDevice(g *generate.Generator, device string) error {
|
||||||
src, dst, permissions, err := ParseDevice(device)
|
src, dst, permissions, err := ParseDevice(device)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -30,3 +30,7 @@ func makeThrottleArray(throttleInput []string, rateType int) ([]spec.LinuxThrott
|
|||||||
func devicesFromPath(g *generate.Generator, devicePath string) error {
|
func devicesFromPath(g *generate.Generator, devicePath string) error {
|
||||||
return errors.New("function not implemented")
|
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
|
CPUs float64 // cpus
|
||||||
CPUsetCPUs string
|
CPUsetCPUs string
|
||||||
CPUsetMems string // cpuset-mems
|
CPUsetMems string // cpuset-mems
|
||||||
|
DeviceCgroupRules []string //device-cgroup-rule
|
||||||
DeviceReadBps []string // device-read-bps
|
DeviceReadBps []string // device-read-bps
|
||||||
DeviceReadIOps []string // device-read-iops
|
DeviceReadIOps []string // device-read-iops
|
||||||
DeviceWriteBps []string // device-write-bps
|
DeviceWriteBps []string // device-write-bps
|
||||||
|
@ -2,12 +2,17 @@ package createconfig
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/docker/go-units"
|
"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
|
// Pod signifies a kernel namespace is being shared
|
||||||
// by a container with the pod it is associated with
|
// by a container with the pod it is associated with
|
||||||
const Pod = "pod"
|
const Pod = "pod"
|
||||||
@ -205,3 +210,16 @@ func IsValidDeviceMode(mode string) bool {
|
|||||||
}
|
}
|
||||||
return true
|
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
|
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
|
// SECURITY OPTS
|
||||||
|
@ -999,4 +999,16 @@ USER mail`
|
|||||||
session.WaitWithDefaultTimeout()
|
session.WaitWithDefaultTimeout()
|
||||||
Expect(session.ExitCode()).To(Not(Equal(0)))
|
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