Add support for adding devices to container
Also add --quiet option to kpod create/run since this will help with writing tests. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #140 Approved by: TomSweeneyRedHat
This commit is contained in:
parent
c0432eb0e8
commit
94a8107515
|
@ -362,6 +362,10 @@ var createFlags = []cli.Flag{
|
|||
Name: "publish-all, P",
|
||||
Usage: "Publish all exposed ports to random ports on the host interface",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "quiet, q",
|
||||
Usage: "Suppress output information when pulling images",
|
||||
},
|
||||
cli.BoolFlag{
|
||||
Name: "read-only",
|
||||
Usage: "Make containers root filesystem read-only",
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
@ -14,7 +15,6 @@ import (
|
|||
"github.com/projectatomic/libpod/libpod"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli"
|
||||
pb "k8s.io/kubernetes/pkg/kubelet/apis/cri/v1alpha1/runtime"
|
||||
)
|
||||
|
||||
type mountType string
|
||||
|
@ -72,7 +72,7 @@ type createConfig struct {
|
|||
CgroupParent string // cgroup-parent
|
||||
Command []string
|
||||
Detach bool // detach
|
||||
Devices []*pb.Device // device
|
||||
Devices []string // device
|
||||
DNSOpt []string //dns-opt
|
||||
DNSSearch []string //dns-search
|
||||
DNSServers []string //dns
|
||||
|
@ -101,6 +101,7 @@ type createConfig struct {
|
|||
Privileged bool //privileged
|
||||
Publish []string //publish
|
||||
PublishAll bool //publish-all
|
||||
Quiet bool //quiet
|
||||
ReadOnlyRootfs bool //read-only
|
||||
Resources createResourceConfig
|
||||
Rm bool //rm
|
||||
|
@ -167,8 +168,11 @@ func createCmd(c *cli.Context) error {
|
|||
if createImage.LocalName == "" {
|
||||
// The image wasnt found by the user input'd name or its fqname
|
||||
// Pull the image
|
||||
fmt.Printf("Trying to pull %s...", createImage.PullName)
|
||||
createImage.Pull()
|
||||
var writer io.Writer
|
||||
if !createConfig.Quiet {
|
||||
writer = os.Stdout
|
||||
}
|
||||
createImage.Pull(writer)
|
||||
}
|
||||
|
||||
runtimeSpec, err := createConfigToOCISpec(createConfig)
|
||||
|
@ -419,6 +423,7 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er
|
|||
CgroupParent: c.String("cgroup-parent"),
|
||||
Command: command,
|
||||
Detach: c.Bool("detach"),
|
||||
Devices: c.StringSlice("device"),
|
||||
DNSOpt: c.StringSlice("dns-opt"),
|
||||
DNSSearch: c.StringSlice("dns-search"),
|
||||
DNSServers: c.StringSlice("dns"),
|
||||
|
@ -447,6 +452,7 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er
|
|||
Privileged: c.Bool("privileged"),
|
||||
Publish: c.StringSlice("publish"),
|
||||
PublishAll: c.Bool("publish-all"),
|
||||
Quiet: c.Bool("quiet"),
|
||||
ReadOnlyRootfs: c.Bool("read-only"),
|
||||
Resources: createResourceConfig{
|
||||
BlkioWeight: blkioWeight,
|
||||
|
|
|
@ -2,6 +2,8 @@ package main
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
|
@ -44,7 +46,11 @@ func runCmd(c *cli.Context) error {
|
|||
if createImage.LocalName == "" {
|
||||
// The image wasnt found by the user input'd name or its fqname
|
||||
// Pull the image
|
||||
createImage.Pull()
|
||||
var writer io.Writer
|
||||
if !createConfig.Quiet {
|
||||
writer = os.Stdout
|
||||
}
|
||||
createImage.Pull(writer)
|
||||
}
|
||||
|
||||
runtimeSpec, err := createConfigToOCISpec(createConfig)
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/docker/docker/daemon/caps"
|
||||
"github.com/docker/docker/pkg/mount"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/opencontainers/runc/libcontainer/devices"
|
||||
spec "github.com/opencontainers/runtime-spec/specs-go"
|
||||
"github.com/opencontainers/runtime-tools/generate"
|
||||
"github.com/opencontainers/selinux/go-selinux/label"
|
||||
|
@ -163,6 +164,25 @@ func setupCapabilities(config *createConfig, configSpec *spec.Spec) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func addDevice(g *generate.Generator, device string) error {
|
||||
dev, err := devices.DeviceFromPath(device, "rwm")
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "%s is not a valid device", device)
|
||||
}
|
||||
linuxdev := spec.LinuxDevice{
|
||||
Path: dev.Path,
|
||||
Type: string(dev.Type),
|
||||
Major: dev.Major,
|
||||
Minor: dev.Minor,
|
||||
FileMode: &dev.FileMode,
|
||||
UID: &dev.Uid,
|
||||
GID: &dev.Gid,
|
||||
}
|
||||
g.AddDevice(linuxdev)
|
||||
g.AddLinuxResourcesDevice(true, string(dev.Type), &dev.Major, &dev.Minor, dev.Permissions)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parses information needed to create a container into an OCI runtime spec
|
||||
func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
||||
g := generate.New()
|
||||
|
@ -233,6 +253,13 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
|||
g.SetLinuxResourcesCPUMems(config.Resources.CPUsetMems)
|
||||
}
|
||||
|
||||
// Devices
|
||||
for _, device := range config.Devices {
|
||||
if err := addDevice(&g, device); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// SECURITY OPTS
|
||||
g.SetProcessNoNewPrivileges(config.NoNewPrivileges)
|
||||
g.SetProcessApparmorProfile(config.ApparmorProfile)
|
||||
|
@ -321,7 +348,6 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
|||
Hooks: &configSpec.Hooks{},
|
||||
//Annotations
|
||||
Resources: &configSpec.LinuxResources{
|
||||
Devices: config.GetDefaultDevices(),
|
||||
BlockIO: &blkio,
|
||||
//HugepageLimits:
|
||||
Network: &configSpec.LinuxNetwork{
|
||||
|
@ -331,7 +357,6 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
|
|||
},
|
||||
//CgroupsPath:
|
||||
//Namespaces: []LinuxNamespace
|
||||
//Devices
|
||||
// DefaultAction:
|
||||
// Architectures
|
||||
// Syscalls:
|
||||
|
|
|
@ -1018,6 +1018,7 @@ _podman_container_run() {
|
|||
--oom-kill-disable
|
||||
--privileged
|
||||
--publish-all -P
|
||||
--quiet
|
||||
--read-only
|
||||
--tty -t
|
||||
"
|
||||
|
|
|
@ -373,6 +373,10 @@ port to a random port on the host within an *ephemeral port range* defined by
|
|||
`/proc/sys/net/ipv4/ip_local_port_range`. To find the mapping between the host
|
||||
ports and the exposed ports, use `podman port`.
|
||||
|
||||
**--quiet, -q**
|
||||
|
||||
Suppress output information when pulling images
|
||||
|
||||
**--read-only**=*true*|*false*
|
||||
Mount the container's root filesystem as read only.
|
||||
|
||||
|
|
|
@ -379,6 +379,10 @@ port to a random port on the host within an *ephemeral port range* defined by
|
|||
`/proc/sys/net/ipv4/ip_local_port_range`. To find the mapping between the host
|
||||
ports and the exposed ports, use `podman port`.
|
||||
|
||||
**--quiet, -q**
|
||||
|
||||
Suppress output information when pulling images
|
||||
|
||||
**--read-only**=*true*|*false*
|
||||
Mount the container's root filesystem as read only.
|
||||
|
||||
|
|
|
@ -397,7 +397,7 @@ func (k *Image) HasLatest() (bool, error) {
|
|||
}
|
||||
|
||||
// Pull is a wrapper function to pull and image
|
||||
func (k *Image) Pull() error {
|
||||
func (k *Image) Pull(writer io.Writer) error {
|
||||
// If the image hasn't been decomposed yet
|
||||
if !k.beenDecomposed {
|
||||
err := k.Decompose()
|
||||
|
@ -405,7 +405,7 @@ func (k *Image) Pull() error {
|
|||
return err
|
||||
}
|
||||
}
|
||||
k.runtime.PullImage(k.PullName, CopyOptions{Writer: os.Stdout, SignaturePolicyPath: k.runtime.config.SignaturePolicyPath})
|
||||
k.runtime.PullImage(k.PullName, CopyOptions{Writer: writer, SignaturePolicyPath: k.runtime.config.SignaturePolicyPath})
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#!/usr/bin/env bats
|
||||
|
||||
load helpers
|
||||
|
||||
function teardown() {
|
||||
cleanup_test
|
||||
}
|
||||
|
||||
function setup() {
|
||||
prepare_network_conf
|
||||
copy_images
|
||||
}
|
||||
|
||||
@test "run baddevice test" {
|
||||
run ${PODMAN_BINARY} ${PODMAN_OPTIONS} run -q --device /dev/baddevice ${ALPINE} ls /dev/kmsg
|
||||
echo $output
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "run device test" {
|
||||
run ${PODMAN_BINARY} ${PODMAN_OPTIONS} run -q --device /dev/kmsg ${ALPINE} ls --color=never /dev/kmsg
|
||||
echo "$output"
|
||||
[ "$status" -eq 0 ]
|
||||
device=$(echo $output | tr -d '\r')
|
||||
echo "<$device>"
|
||||
[ "$device" = "/dev/kmsg" ]
|
||||
}
|
|
@ -1,14 +1,14 @@
|
|||
#
|
||||
github.com/sirupsen/logrus v1.0.0
|
||||
github.com/containers/image c8bcd6aa11c62637c5a7da1420f43dd6a15f0e8d
|
||||
github.com/containers/image 9b4510f6d1627c8e53c3303a8fe48ca7842c2ace
|
||||
github.com/docker/docker-credential-helpers d68f9aeca33f5fd3f08eeae5e9d175edf4e731d1
|
||||
github.com/ostreedev/ostree-go master
|
||||
github.com/containers/storage 9e0c323a4b425557f8310ee8d125634acd39d8f5
|
||||
github.com/containers/storage 1824cf917a6b42d8c41179e807bb20a5fd6c0f0a
|
||||
github.com/containernetworking/cni v0.4.0
|
||||
google.golang.org/grpc v1.0.4 https://github.com/grpc/grpc-go
|
||||
github.com/opencontainers/selinux b29023b86e4a69d1b46b7e7b4e2b6fda03f0b9cd
|
||||
github.com/opencontainers/go-digest v1.0.0-rc0
|
||||
github.com/opencontainers/runtime-tools d3f7e9e9e631c7e87552d67dc7c86de33c3fb68a
|
||||
github.com/opencontainers/runtime-tools v0.3.0
|
||||
github.com/opencontainers/runc 45bde006ca8c90e089894508708bcf0e2cdf9e13
|
||||
github.com/mrunalp/fileutils master
|
||||
github.com/vishvananda/netlink master
|
||||
|
@ -97,3 +97,6 @@ github.com/pquerna/ffjson d49c2bc1aa135aad0c6f4fc2056623ec78f5d5ac
|
|||
github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
|
||||
github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2
|
||||
github.com/containerd/continuity master
|
||||
github.com/xeipuuv/gojsonschema master
|
||||
github.com/xeipuuv/gojsonreference master
|
||||
github.com/xeipuuv/gojsonpointer master
|
||||
|
|
100
vendor/github.com/opencontainers/runc/libcontainer/devices/devices_linux.go
generated
vendored
Normal file
100
vendor/github.com/opencontainers/runc/libcontainer/devices/devices_linux.go
generated
vendored
Normal file
|
@ -0,0 +1,100 @@
|
|||
package devices
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/opencontainers/runc/libcontainer/configs"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotADevice = errors.New("not a device node")
|
||||
)
|
||||
|
||||
// Testing dependencies
|
||||
var (
|
||||
unixLstat = unix.Lstat
|
||||
ioutilReadDir = ioutil.ReadDir
|
||||
)
|
||||
|
||||
// Given the path to a device and its cgroup_permissions(which cannot be easily queried) look up the information about a linux device and return that information as a Device struct.
|
||||
func DeviceFromPath(path, permissions string) (*configs.Device, error) {
|
||||
var stat unix.Stat_t
|
||||
err := unixLstat(path, &stat)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var (
|
||||
devType rune
|
||||
mode = stat.Mode
|
||||
)
|
||||
switch {
|
||||
case mode&unix.S_IFBLK == unix.S_IFBLK:
|
||||
devType = 'b'
|
||||
case mode&unix.S_IFCHR == unix.S_IFCHR:
|
||||
devType = 'c'
|
||||
default:
|
||||
return nil, ErrNotADevice
|
||||
}
|
||||
devNumber := int(stat.Rdev)
|
||||
uid := stat.Uid
|
||||
gid := stat.Gid
|
||||
return &configs.Device{
|
||||
Type: devType,
|
||||
Path: path,
|
||||
Major: Major(devNumber),
|
||||
Minor: Minor(devNumber),
|
||||
Permissions: permissions,
|
||||
FileMode: os.FileMode(mode),
|
||||
Uid: uid,
|
||||
Gid: gid,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func HostDevices() ([]*configs.Device, error) {
|
||||
return getDevices("/dev")
|
||||
}
|
||||
|
||||
func getDevices(path string) ([]*configs.Device, error) {
|
||||
files, err := ioutilReadDir(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
out := []*configs.Device{}
|
||||
for _, f := range files {
|
||||
switch {
|
||||
case f.IsDir():
|
||||
switch f.Name() {
|
||||
// ".lxc" & ".lxd-mounts" added to address https://github.com/lxc/lxd/issues/2825
|
||||
case "pts", "shm", "fd", "mqueue", ".lxc", ".lxd-mounts":
|
||||
continue
|
||||
default:
|
||||
sub, err := getDevices(filepath.Join(path, f.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
out = append(out, sub...)
|
||||
continue
|
||||
}
|
||||
case f.Name() == "console":
|
||||
continue
|
||||
}
|
||||
device, err := DeviceFromPath(filepath.Join(path, f.Name()), "rwm")
|
||||
if err != nil {
|
||||
if err == ErrNotADevice {
|
||||
continue
|
||||
}
|
||||
if os.IsNotExist(err) {
|
||||
continue
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
out = append(out, device)
|
||||
}
|
||||
return out, nil
|
||||
}
|
3
vendor/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go
generated
vendored
Normal file
3
vendor/github.com/opencontainers/runc/libcontainer/devices/devices_unsupported.go
generated
vendored
Normal file
|
@ -0,0 +1,3 @@
|
|||
// +build !linux
|
||||
|
||||
package devices
|
24
vendor/github.com/opencontainers/runc/libcontainer/devices/number.go
generated
vendored
Normal file
24
vendor/github.com/opencontainers/runc/libcontainer/devices/number.go
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
// +build linux freebsd
|
||||
|
||||
package devices
|
||||
|
||||
/*
|
||||
|
||||
This code provides support for manipulating linux device numbers. It should be replaced by normal syscall functions once http://code.google.com/p/go/issues/detail?id=8106 is solved.
|
||||
|
||||
You can read what they are here:
|
||||
|
||||
- http://www.makelinux.net/ldd3/chp-3-sect-2
|
||||
- http://www.linux-tutorial.info/modules.php?name=MContent&pageid=94
|
||||
|
||||
Note! These are NOT the same as the MAJOR(dev_t device);, MINOR(dev_t device); and MKDEV(int major, int minor); functions as defined in <linux/kdev_t.h> as the representation of device numbers used by go is different than the one used internally to the kernel! - https://github.com/torvalds/linux/blob/master/include/linux/kdev_t.h#L9
|
||||
|
||||
*/
|
||||
|
||||
func Major(devNumber int) int64 {
|
||||
return int64((devNumber >> 8) & 0xfff)
|
||||
}
|
||||
|
||||
func Minor(devNumber int) int64 {
|
||||
return int64((devNumber & 0xff) | ((devNumber >> 12) & 0xfff00))
|
||||
}
|
Loading…
Reference in New Issue