Merge pull request #5152 from QiWang19/device-cgroup-rule

support device-cgroup-rule
This commit is contained in:
OpenShift Merge Robot
2020-02-13 02:34:42 +01:00
committed by GitHub
11 changed files with 92 additions and 0 deletions

View File

@ -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)",

View File

@ -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"),

View File

@ -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")

View File

@ -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

View File

@ -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)

View File

@ -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 {

View File

@ -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")
}

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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))
})
}) })