Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions cmd/oci-runtime-tool/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ var generateFlags = []cli.Flag{
cli.StringSliceFlag{Name: "cap-drop", Usage: "drop Linux capabilities"},
cli.StringFlag{Name: "cgroups-path", Usage: "specify the path to the cgroups"},
cli.StringFlag{Name: "cwd", Value: "/", Usage: "current working directory for the process"},
cli.StringSliceFlag{Name: "device", Usage: "specifies a device which must be made available in the container"},
cli.StringSliceFlag{Name: "device-add", Usage: "add a device which must be made available in the container"},
cli.StringSliceFlag{Name: "device-remove", Usage: "remove a device which must be made available in the container"},
cli.BoolFlag{Name: "device-remove-all", Usage: "remove all devices which must be made available in the container"},
cli.BoolFlag{Name: "disable-oom-kill", Usage: "disable OOM Killer"},
cli.StringSliceFlag{Name: "env", Usage: "add environment variable e.g. key=value"},
cli.StringSliceFlag{Name: "env-file", Usage: "read in a file of environment variables"},
Expand Down Expand Up @@ -502,15 +504,31 @@ func setupSpec(g *generate.Generator, context *cli.Context) error {
g.ClearProcessRlimits()
}

if context.IsSet("device") {
devices := context.StringSlice("device")
if context.IsSet("device-add") {
devices := context.StringSlice("device-add")
for _, deviceArg := range devices {
err := addDevice(deviceArg, g)
dev, err := parseDevice(deviceArg, g)
if err != nil {
return err
}
g.AddDevice(dev)
}
}

if context.IsSet("device-remove") {
devices := context.StringSlice("device-remove")
for _, device := range devices {
err := g.RemoveDevice(device)
if err != nil {
return err
}
}
}

if context.Bool("device-remove-all") {
g.ClearLinuxDevices()
}

err := addSeccomp(context, g)
return err
}
Expand Down Expand Up @@ -642,33 +660,33 @@ var deviceType = map[string]bool{
"p": true, // a FIFO
}

// addDevice takes the raw string passed with the --device flag, parses it, and add it
func addDevice(device string, g *generate.Generator) error {
// parseDevice takes the raw string passed with the --device-add flag
func parseDevice(device string, g *generate.Generator) (rspec.LinuxDevice, error) {
dev := rspec.LinuxDevice{}

// The required part and optional part are separated by ":"
argsParts := strings.Split(device, ":")
if len(argsParts) < 4 {
return fmt.Errorf("Incomplete device arguments: %s", device)
return dev, fmt.Errorf("Incomplete device arguments: %s", device)
}
requiredPart := argsParts[0:4]
optionalPart := argsParts[4:]

// The required part must contain type, major, minor, and path
dev.Type = requiredPart[0]
if !deviceType[dev.Type] {
return fmt.Errorf("Invalid device type: %s", dev.Type)
return dev, fmt.Errorf("Invalid device type: %s", dev.Type)
}

i, err := strconv.ParseInt(requiredPart[1], 10, 64)
if err != nil {
return err
return dev, err
}
dev.Major = i

i, err = strconv.ParseInt(requiredPart[2], 10, 64)
if err != nil {
return err
return dev, err
}
dev.Minor = i
dev.Path = requiredPart[3]
Expand All @@ -678,7 +696,7 @@ func addDevice(device string, g *generate.Generator) error {
parts := strings.SplitN(s, "=", 2)

if len(parts) != 2 {
return fmt.Errorf("Incomplete device arguments: %s", s)
return dev, fmt.Errorf("Incomplete device arguments: %s", s)
}

name, value := parts[0], parts[1]
Expand All @@ -687,33 +705,31 @@ func addDevice(device string, g *generate.Generator) error {
case "fileMode":
i, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
return dev, err
}
mode := os.FileMode(i)
dev.FileMode = &mode
case "uid":
i, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
return dev, err
}
uid := uint32(i)
dev.UID = &uid

case "gid":
i, err := strconv.ParseInt(value, 10, 32)
if err != nil {
return err
return dev, err
}
gid := uint32(i)
dev.GID = &gid
default:
return fmt.Errorf("'%s' is not supported by device section", name)
return dev, fmt.Errorf("'%s' is not supported by device section", name)
}
}

g.AddDevice(dev.Path, dev.Type, dev.Major, dev.Minor, dev.FileMode, dev.UID, dev.GID)

return nil
return dev, nil
}

func addSeccomp(context *cli.Context, g *generate.Generator) error {
Expand Down
4 changes: 3 additions & 1 deletion completions/bash/oci-runtime-tool
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,8 @@ _oci-runtime-tool_generate() {
--cap-drop
--cgroups-path
--cwd
--device
--device-add
--device-remove
--env
--env-file
--gid
Expand Down Expand Up @@ -367,6 +368,7 @@ _oci-runtime-tool_generate() {
"

local boolean_options="
--device-remove-all
--disable-oom-kill
--help -h
--linux-namespace-remove-all
Expand Down
42 changes: 33 additions & 9 deletions generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -1015,21 +1015,45 @@ func (g *Generator) RemoveLinuxNamespace(ns string) error {
}

// AddDevice - add a device into g.spec.Linux.Devices
func (g *Generator) AddDevice(path, devType string, major, minor int64, fileMode *os.FileMode, uid, gid *uint32) {
func (g *Generator) AddDevice(device rspec.LinuxDevice) {
g.initSpecLinux()

device := rspec.LinuxDevice{
Path: path,
Type: devType,
Major: major,
Minor: minor,
FileMode: fileMode,
UID: uid,
GID: gid,
for i, dev := range g.spec.Linux.Devices {
if dev.Path == device.Path {
g.spec.Linux.Devices[i] = device
return
}
if dev.Type == device.Type && dev.Major == device.Major && dev.Minor == device.Minor {
fmt.Fprintln(os.Stderr, "WARNING: The same type, major and minor should not be used for multiple devices.")
}
}

g.spec.Linux.Devices = append(g.spec.Linux.Devices, device)
}

//RemoveDevice remove a device from g.spec.Linux.Devices
func (g *Generator) RemoveDevice(path string) error {
if g.spec == nil || g.spec.Linux == nil || g.spec.Linux.Devices == nil {
return nil
}

for i, device := range g.spec.Linux.Devices {
if device.Path == path {
g.spec.Linux.Devices = append(g.spec.Linux.Devices[:i], g.spec.Linux.Devices[i+1:]...)
return nil
}
}
return nil
}

func (g *Generator) ClearLinuxDevices() {
if g.spec == nil || g.spec.Linux == nil || g.spec.Linux.Devices == nil {
return
}

g.spec.Linux.Devices = []rspec.LinuxDevice{}
}

// strPtr returns the pointer pointing to the string s.
func strPtr(s string) *string { return &s }

Expand Down
10 changes: 9 additions & 1 deletion man/oci-runtime-tool-generate.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ read the configuration from `config.json`.
**--cwd**=PATH
Current working directory for the process. The deafult is */*.

**--device**=*TYPE:MAJOR:MINOR:PATH[:OPTIONS...]*
**--device-add**=*TYPE:MAJOR:MINOR:PATH[:OPTIONS...]*
Add a device file in container. e.g. --device=c:10:229:/dev/fuse:fileMode=438:uid=0:gid=0
The *TYPE*, *MAJOR*, *MINOR*, *PATH* are required.
*TYPE* is the device type. The acceptable values are b (block), c (character), u (unbuffered), p (FIFO).
Expand All @@ -60,6 +60,14 @@ read the configuration from `config.json`.
The *fileMode*, *uid*, *gid* are optional.
*fileMode* is the file mode of the device file.
*uid*/*gid* is the user/group id of the device file.
This option can be specified multiple times.

**--device-remove**=*PATH*
Remove a device file in container.
This option can be specified multiple times.

**--device-remove-all**=true|false
Remove all devices for linux inside the container. The default is *false*.

**--disable-oom-kill**=true|false
Whether to disable OOM Killer for the container or not.
Expand Down