Add NetMode, UTSMode and IPCMode

Allow kpod create/run to create contianers in different network namespaces, uts namespaces and
IPC Namespaces.

This patch just handles the simple join the host, or another containers namespaces.

Lots more work needed to full integrate  --net

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>

Closes: #64
Approved by: mheon
This commit is contained in:
Daniel J Walsh
2017-11-30 09:37:57 -05:00
committed by Atomic Bot
parent 1f01faf437
commit adf8809521
10 changed files with 310 additions and 73 deletions

View File

@ -81,20 +81,20 @@ type createConfig struct {
groupAdd []uint32 // group-add
hostname string //hostname
image string
interactive bool //interactive
ip6Address string //ipv6
ipAddress string //ip
labels map[string]string //label
linkLocalIP []string // link-local-ip
logDriver string // log-driver
logDriverOpt []string // log-opt
macAddress string //mac-address
name string //name
network string //network
networkAlias []string //network-alias
nsIPC string // ipc
nsNET string //net
pidMode container.PidMode //pid
interactive bool //interactive
ipcMode container.IpcMode //ipc
ip6Address string //ipv6
ipAddress string //ip
labels map[string]string //label
linkLocalIP []string // link-local-ip
logDriver string // log-driver
logDriverOpt []string // log-opt
macAddress string //mac-address
name string //name
netMode container.NetworkMode //net
network string //network
networkAlias []string //network-alias
pidMode container.PidMode //pid
nsUser string
pod string //pod
privileged bool //privileged
@ -102,7 +102,8 @@ type createConfig struct {
publishAll bool //publish-all
readOnlyRootfs bool //read-only
resources createResourceConfig
rm bool //rm
rm bool //rm
shmDir string
sigProxy bool //sig-proxy
stopSignal string // stop-signal
stopTimeout int64 // stop-timeout
@ -112,6 +113,7 @@ type createConfig struct {
tty bool //tty
user uint32 //user
group uint32 // group
utsMode container.UTSMode //uts
volumes []string //volume
volumesFrom []string //volumes-from
workDir string //workdir
@ -201,7 +203,8 @@ func createCmd(c *cli.Context) error {
}
// Gather up the options for NewContainer which consist of With... funcs
options = append(options, libpod.WithRootFSFromImage(imageID, imageName, false))
options = append(options, libpod.WithSELinuxMountLabel(createConfig.mountLabel))
options = append(options, libpod.WithSELinuxLabels(createConfig.processLabel, createConfig.mountLabel))
options = append(options, libpod.WithShmDir(createConfig.shmDir))
ctr, err := runtime.NewContainer(runtimeSpec, options...)
if err != nil {
return err
@ -230,6 +233,26 @@ func parseSecurityOpt(config *createConfig, securityOpts []string) error {
err error
)
if config.pidMode.IsHost() {
labelOpts = append(labelOpts, label.DisableSecOpt()...)
} else if config.pidMode.IsContainer() {
ctr, err := config.runtime.LookupContainer(config.pidMode.Container())
if err != nil {
return errors.Wrapf(err, "container %q not found", config.pidMode.Container())
}
labelOpts = append(labelOpts, label.DupSecOpt(ctr.ProcessLabel())...)
}
if config.ipcMode.IsHost() {
labelOpts = append(labelOpts, label.DisableSecOpt()...)
} else if config.ipcMode.IsContainer() {
ctr, err := config.runtime.LookupContainer(config.ipcMode.Container())
if err != nil {
return errors.Wrapf(err, "container %q not found", config.ipcMode.Container())
}
labelOpts = append(labelOpts, label.DupSecOpt(ctr.ProcessLabel())...)
}
for _, opt := range securityOpts {
if opt == "no-new-privileges" {
config.noNewPrivileges = true
@ -354,6 +377,7 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er
if !c.Bool("detach") && !tty {
tty = true
}
pidMode := container.PidMode(c.String("pid"))
if !pidMode.Valid() {
return nil, errors.Errorf("--pid %q is not valid", c.String("pid"))
@ -363,6 +387,25 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er
return nil, errors.Errorf("--rm and --detach can not be specified together")
}
utsMode := container.UTSMode(c.String("uts"))
if !utsMode.Valid() {
return nil, errors.Errorf("--uts %q is not valid", c.String("uts"))
}
ipcMode := container.IpcMode(c.String("ipc"))
if !ipcMode.Valid() {
return nil, errors.Errorf("--ipc %q is not valid", ipcMode)
}
shmDir := ""
if ipcMode.IsHost() {
shmDir = "/dev/shm"
} else if ipcMode.IsContainer() {
ctr, err := runtime.LookupContainer(ipcMode.Container())
if err != nil {
return nil, errors.Wrapf(err, "container %q not found", ipcMode.Container())
}
shmDir = ctr.ShmDir()
}
config := &createConfig{
runtime: runtime,
capAdd: c.StringSlice("cap-add"),
@ -390,8 +433,9 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er
name: c.String("name"),
network: c.String("network"),
networkAlias: c.StringSlice("network-alias"),
nsIPC: c.String("ipc"),
nsNET: c.String("net"),
ipcMode: ipcMode,
netMode: container.NetworkMode(c.String("network")),
utsMode: utsMode,
pidMode: pidMode,
pod: c.String("pod"),
privileged: c.Bool("privileged"),
@ -426,6 +470,7 @@ func parseCreateOpts(c *cli.Context, runtime *libpod.Runtime) (*createConfig, er
ulimit: c.StringSlice("ulimit"),
},
rm: c.Bool("rm"),
shmDir: shmDir,
sigProxy: c.Bool("sig-proxy"),
stopSignal: c.String("stop-signal"),
stopTimeout: c.Int64("stop-timeout"),

View File

@ -85,9 +85,11 @@ func runCmd(c *cli.Context) error {
if err != nil {
return errors.Wrapf(err, "unable to parse new container options")
}
// Gather up the options for NewContainer which consist of With... funcs
options = append(options, libpod.WithRootFSFromImage(imageID, imageName, false))
options = append(options, libpod.WithSELinuxMountLabel(createConfig.mountLabel))
options = append(options, libpod.WithSELinuxLabels(createConfig.processLabel, createConfig.mountLabel))
options = append(options, libpod.WithShmDir(createConfig.shmDir))
ctr, err := runtime.NewContainer(runtimeSpec, options...)
if err != nil {
return err
@ -130,14 +132,14 @@ func runCmd(c *cli.Context) error {
if err := ctr.Start(); err != nil {
return errors.Wrapf(err, "unable to start container %q", ctr.ID())
}
logrus.Debug("started container ", ctr.ID())
if createConfig.detach {
fmt.Printf("%s\n", ctr.ID())
return nil
}
wg.Wait()
if createConfig.rm {
return runtime.RemoveContainer(ctr, true)
}
return nil
return ctr.CleanupStorage()
}

View File

@ -49,7 +49,7 @@ func blockAccessToKernelFilesystems(config *createConfig, g *generate.Generator)
func addPidNS(config *createConfig, g *generate.Generator) error {
pidMode := config.pidMode
if pidMode.IsHost() {
return g.RemoveLinuxNamespace("pid")
return g.RemoveLinuxNamespace(libpod.PIDNamespace)
}
if pidMode.IsContainer() {
ctr, err := config.runtime.LookupContainer(pidMode.Container())
@ -68,6 +68,65 @@ func addPidNS(config *createConfig, g *generate.Generator) error {
return nil
}
func addNetNS(config *createConfig, g *generate.Generator) error {
netMode := config.netMode
if netMode.IsHost() {
return g.RemoveLinuxNamespace(libpod.NetNamespace)
}
if netMode.IsNone() {
return libpod.ErrNotImplemented
}
if netMode.IsBridge() {
return libpod.ErrNotImplemented
}
if netMode.IsContainer() {
ctr, err := config.runtime.LookupContainer(netMode.ConnectedContainer())
if err != nil {
return errors.Wrapf(err, "container %q not found", netMode.ConnectedContainer())
}
pid, err := ctr.PID()
if err != nil {
return errors.Wrapf(err, "Failed to get pid of container %q", netMode.ConnectedContainer())
}
nsPath := fmt.Sprintf("/proc/%d/ns/net", pid)
if err := g.AddOrReplaceLinuxNamespace(libpod.NetNamespace, nsPath); err != nil {
return err
}
}
return nil
}
func addUTSNS(config *createConfig, g *generate.Generator) error {
utsMode := config.utsMode
if utsMode.IsHost() {
return g.RemoveLinuxNamespace(libpod.UTSNamespace)
}
return nil
}
func addIpcNS(config *createConfig, g *generate.Generator) error {
ipcMode := config.ipcMode
if ipcMode.IsHost() {
return g.RemoveLinuxNamespace(libpod.IPCNamespace)
}
if ipcMode.IsContainer() {
ctr, err := config.runtime.LookupContainer(ipcMode.Container())
if err != nil {
return errors.Wrapf(err, "container %q not found", ipcMode.Container())
}
pid, err := ctr.PID()
if err != nil {
return errors.Wrapf(err, "Failed to get pid of container %q", ipcMode.Container())
}
nsPath := fmt.Sprintf("/proc/%d/ns/ipc", pid)
if err := g.AddOrReplaceLinuxNamespace(libpod.IPCNamespace, nsPath); err != nil {
return err
}
}
return nil
}
func addRlimits(config *createConfig, g *generate.Generator) error {
var (
ul *units.Ulimit
@ -210,6 +269,17 @@ func createConfigToOCISpec(config *createConfig) (*spec.Spec, error) {
return nil, err
}
if err := addNetNS(config, &g); err != nil {
return nil, err
}
if err := addUTSNS(config, &g); err != nil {
return nil, err
}
if err := addIpcNS(config, &g); err != nil {
return nil, err
}
configSpec := g.Spec()
if config.seccompProfilePath != "" && config.seccompProfilePath != "unconfined" {

View File

@ -7,19 +7,25 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strconv"
"sync"
"syscall"
"time"
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/namesgenerator"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/pkg/term"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
crioAnnotations "github.com/projectatomic/libpod/pkg/annotations"
"github.com/sirupsen/logrus"
"github.com/ulule/deepcopier"
"golang.org/x/sys/unix"
"k8s.io/apimachinery/pkg/util/wait"
"k8s.io/client-go/tools/remotecommand"
)
@ -86,7 +92,6 @@ type containerRuntimeInfo struct {
OOMKilled bool `json:"oomKilled,omitempty"`
// PID is the PID of a running container
PID int `json:"pid,omitempty"`
// TODO: Save information about image used in container if one is used
}
@ -101,8 +106,12 @@ type ContainerConfig struct {
RootfsImageID string `json:"rootfsImageID,omitempty"`
RootfsImageName string `json:"rootfsImageName,omitempty"`
UseImageConfig bool `json:"useImageConfig"`
// SELinux process label for container
ProcessLabel string `json:"ProcessLabel,omitempty"`
// SELinux mount label for root filesystem
MountLabel string `json:"MountLabel,omitempty"`
// Src path to be mounted on /dev/shm in container
ShmDir string `json:"ShmDir,omitempty"`
// Static directory for container content that will persist across
// reboot
StaticDir string `json:"staticDir"`
@ -113,6 +122,8 @@ type ContainerConfig struct {
// Labels is a set of key-value pairs providing additional information
// about a container
Labels map[string]string `json:"labels,omitempty"`
// Mounts list contains all additional mounts by the container runtime.
Mounts []string
// StopSignal is the signal that will be used to stop the container
StopSignal uint `json:"stopSignal,omitempty"`
// Shared namespaces with container
@ -120,7 +131,6 @@ type ContainerConfig struct {
SharedNamespaceMap map[string]string `json:"sharedNamespaces"`
// Time container was created
CreatedTime time.Time `json:"createdTime"`
// TODO save log location here and pass into OCI code
// TODO allow overriding of log path
}
@ -155,6 +165,16 @@ func (c *Container) Name() string {
return c.config.Name
}
// ShmDir returns the sources path to be mounted on /dev/shm in container
func (c *Container) ShmDir() string {
return c.config.ShmDir
}
// ProcessLabel returns the selinux ProcessLabel of the container
func (c *Container) ProcessLabel() string {
return c.config.ProcessLabel
}
// Spec returns the container's OCI runtime spec
// The spec returned is the one used to create the container. The running
// spec may differ slightly as mounts are added based on the image
@ -307,7 +327,7 @@ func (c *Container) syncContainer() error {
if err := c.runtime.ociRuntime.updateContainerStatus(c); err != nil {
return err
}
if err := c.runtime.state.SaveContainer(c); err != nil {
if err := c.save(); err != nil {
return err
}
}
@ -376,13 +396,8 @@ func (c *Container) teardownStorage() error {
return errors.Wrapf(ErrCtrStateInvalid, "cannot remove storage for container %s as it is running or paused", c.ID())
}
if c.state.Mounted {
if err := c.runtime.storageService.StopContainer(c.ID()); err != nil {
return errors.Wrapf(err, "error unmounting container %s root filesystem", c.ID())
}
c.state.Mounted = false
c.state.Mountpoint = ""
if err := c.cleanupStorage(); err != nil {
return errors.Wrapf(err, "failed to cleanup container %s storage", c.ID())
}
if err := c.runtime.storageService.DeleteContainer(c.ID()); err != nil {
@ -426,8 +441,10 @@ func (c *Container) Init() (err error) {
}()
// Make the OCI runtime spec we will use
c.runningSpec = new(spec.Spec)
deepcopier.Copy(c.config.Spec).To(c.runningSpec)
g := generate.NewFromSpec(c.config.Spec)
// Mount ShmDir from host into container
g.AddBindMount(c.config.ShmDir, "/dev/shm", []string{"rw"})
c.runningSpec = g.Spec()
c.runningSpec.Root.Path = c.state.Mountpoint
c.runningSpec.Annotations[crioAnnotations.Created] = c.config.CreatedTime.Format(time.RFC3339Nano)
c.runningSpec.Annotations["org.opencontainers.image.stopSignal"] = fmt.Sprintf("%d", c.config.StopSignal)
@ -455,11 +472,7 @@ func (c *Container) Init() (err error) {
c.state.State = ContainerStateCreated
if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}
return nil
return c.save()
}
// Start starts a container
@ -471,6 +484,19 @@ func (c *Container) Start() error {
return err
}
mounted, err := mount.Mounted(c.config.ShmDir)
if err != nil {
return errors.Wrapf(err, "unable to determine if %q is mounted", c.config.ShmDir)
}
if !mounted {
shmOptions := "mode=1777,size=" + strconv.Itoa(DefaultShmSize)
if err := unix.Mount("shm", c.config.ShmDir, "tmpfs", unix.MS_NOEXEC|unix.MS_NOSUID|unix.MS_NODEV,
label.FormatMountLabel(shmOptions, c.config.MountLabel)); err != nil {
return errors.Wrapf(err, "failed to mount shm tmpfs %q", c.config.ShmDir)
}
}
// Container must be created or stopped to be started
if !(c.state.State == ContainerStateCreated || c.state.State == ContainerStateStopped) {
return errors.Wrapf(ErrCtrStateInvalid, "container %s must be in Created or Stopped state to be started", c.ID())
@ -510,11 +536,7 @@ func (c *Container) Start() error {
return err
}
if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}
return nil
return c.save()
}
// Stop uses the container's stop signal (or SIGTERM if no signal was specified)
@ -544,18 +566,7 @@ func (c *Container) Stop(timeout int64) error {
return err
}
// Also unmount storage
if err := c.runtime.storageService.StopContainer(c.ID()); err != nil {
return errors.Wrapf(err, "error unmounting container %s root filesystem", c.ID())
}
c.state.Mountpoint = ""
c.state.Mounted = false
if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}
return nil
return c.cleanupStorage()
}
// Kill sends a signal to a container
@ -638,8 +649,8 @@ func (c *Container) Mount(label string) (string, error) {
c.state.Mounted = true
c.config.MountLabel = mountLabel
if err := c.runtime.state.SaveContainer(c); err != nil {
return "", errors.Wrapf(err, "error saving container %s state", c.ID())
if err := c.save(); err != nil {
return "", err
}
return mountPoint, nil
@ -669,7 +680,7 @@ func (c *Container) Unmount() error {
c.state.Mountpoint = ""
c.state.Mounted = false
return c.runtime.state.SaveContainer(c)
return c.save()
}
// Pause pauses a container
@ -698,10 +709,7 @@ func (c *Container) Pause() error {
return err
}
if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}
return nil
return c.save()
}
// Unpause unpauses a container
@ -727,10 +735,7 @@ func (c *Container) Unpause() error {
return err
}
if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}
return nil
return c.save()
}
// Export exports a container's root filesystem as a tar archive
@ -809,3 +814,48 @@ func (c *Container) isStopped() (bool, error) {
}
return c.state.State == ContainerStateStopped, nil
}
// nil container state to the database
func (c *Container) save() error {
if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}
return nil
}
// CleanupStorage unmounts all mount points in container and cleans up container storage
func (c *Container) CleanupStorage() error {
c.lock.Lock()
defer c.lock.Unlock()
if err := c.syncContainer(); err != nil {
return err
}
return c.cleanupStorage()
}
func (c *Container) cleanupStorage() error {
if c.state.Mounted {
for _, mount := range c.config.Mounts {
if err := unix.Unmount(mount, unix.MNT_DETACH); err != nil {
if err != syscall.EINVAL {
logrus.Warnf("container %s failed to unmount %s : %v", c.ID(), mount, err)
}
}
}
c.config.Mounts = []string{}
// Also unmount storage
if err := c.runtime.storageService.StopContainer(c.ID()); err != nil {
return errors.Wrapf(err, "error unmounting container %s root filesystem", c.ID())
}
}
c.state.Mountpoint = ""
c.state.Mounted = false
if err := c.runtime.state.SaveContainer(c); err != nil {
return errors.Wrapf(err, "error saving container %s state", c.ID())
}
return nil
}

View File

@ -37,6 +37,11 @@ const (
// Timeout before declaring that runc has failed to kill a given container
killContainerTimeout = 5 * time.Second
// DefaultShmSize is the default shm size
DefaultShmSize = 64 * 1024 * 1024
// NsRunDir is the default directory in which running network namespaces
// are stored
NsRunDir = "/var/run/netns"
)
// OCIRuntime represents an OCI-compatible runtime that libpod can call into

View File

@ -21,7 +21,7 @@ const (
// MountNamespace represents the mount namespace
MountNamespace = "mount"
// NetNamespace represents the network namespace
NetNamespace = "net"
NetNamespace = "network"
// PIDNamespace represents the PID namespace
PIDNamespace = "pid"
// UserNamespace represents the user namespace
@ -252,13 +252,26 @@ func WithNoPivotRoot(noPivot bool) RuntimeOption {
// Container Creation Options
// WithSELinuxMountLabel sets the mount label for SELinux
func WithSELinuxMountLabel(mountLabel string) CtrCreateOption {
// WithShmDir sets the directory that should be mounted on /dev/shm
func WithShmDir(dir string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
ctr.config.ShmDir = dir
return nil
}
}
// WithSELinuxLabels sets the mount label for SELinux
func WithSELinuxLabels(processLabel, mountLabel string) CtrCreateOption {
return func(ctr *Container) error {
if ctr.valid {
return ErrCtrFinalized
}
ctr.config.ProcessLabel = processLabel
ctr.config.MountLabel = mountLabel
return nil
}

View File

@ -1,6 +1,9 @@
package libpod
import (
"os"
"path/filepath"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@ -54,6 +57,16 @@ func (r *Runtime) NewContainer(spec *spec.Spec, options ...CtrCreateOption) (c *
}
}()
if ctr.config.ShmDir == "" {
ctr.config.ShmDir = filepath.Join(ctr.bundlePath(), "shm")
if err := os.MkdirAll(ctr.config.ShmDir, 0700); err != nil {
if !os.IsExist(err) {
return nil, errors.Wrapf(err, "unable to create shm %q dir", ctr.config.ShmDir)
}
}
ctr.config.Mounts = append(ctr.config.Mounts, ctr.config.ShmDir)
}
// If the container is in a pod, add it to the pod
if ctr.pod != nil {
if err := ctr.pod.addContainer(ctr); err != nil {

View File

@ -16,7 +16,7 @@ import (
// DBSchema is the current DB schema version
// Increments every time a change is made to the database's tables
const DBSchema = 1
const DBSchema = 2
// SQLState is a state implementation backed by a persistent SQLite3 database
type SQLState struct {
@ -230,7 +230,7 @@ func (s *SQLState) HasContainer(id string) (bool, error) {
func (s *SQLState) AddContainer(ctr *Container) (err error) {
const (
addCtr = `INSERT INTO containers VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?
);`
addCtrState = `INSERT INTO containerState VALUES (
?, ?, ?, ?, ?, ?, ?, ?, ?, ?
@ -265,11 +265,18 @@ func (s *SQLState) AddContainer(ctr *Container) (err error) {
}
}()
mounts, err := json.Marshal(ctr.config.Mounts)
if err != nil {
return errors.Wrapf(err, "error marshaling container %s monunts to JSON", ctr.ID())
}
// Add static container information
_, err = tx.Exec(addCtr,
ctr.ID(),
ctr.Name(),
ctr.config.ProcessLabel,
ctr.config.MountLabel,
string(mounts),
ctr.config.ShmDir,
ctr.config.StaticDir,
boolToSQL(ctr.config.Stdin),
string(labelsJSON),

View File

@ -166,7 +166,10 @@ func prepareDB(db *sql.DB) (err error) {
CREATE TABLE IF NOT EXISTS containers(
Id TEXT NOT NULL PRIMARY KEY,
Name TEXT NOT NULL UNIQUE,
ProcessLabel TEXT NOT NULL,
MountLabel TEXT NOT NULL,
Mounts TEXT NOT NULL,
ShmDir TEXT NOT NULL,
StaticDir TEXT NOT NULL,
Stdin INTEGER NOT NULL,
LabelsJSON TEXT NOT NULL,
@ -267,7 +270,10 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string) (*Contai
var (
id string
name string
processLabel string
mountLabel string
mounts string
shmDir string
staticDir string
stdin int
labelsJSON string
@ -290,7 +296,10 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string) (*Contai
err := row.Scan(
&id,
&name,
&processLabel,
&mountLabel,
&mounts,
&shmDir,
&staticDir,
&stdin,
&labelsJSON,
@ -325,7 +334,12 @@ func ctrFromScannable(row scannable, runtime *Runtime, specsDir string) (*Contai
ctr.config.RootfsImageID = rootfsImageID
ctr.config.RootfsImageName = rootfsImageName
ctr.config.UseImageConfig = boolFromSQL(useImageConfig)
ctr.config.ProcessLabel = processLabel
ctr.config.MountLabel = mountLabel
if err := json.Unmarshal([]byte(mounts), &ctr.config.Mounts); err != nil {
return nil, errors.Wrapf(err, "error parsing container %s mounts JSON", id)
}
ctr.config.ShmDir = shmDir
ctr.config.StaticDir = staticDir
ctr.config.Stdin = boolFromSQL(stdin)
ctr.config.StopSignal = stopSignal

View File

@ -30,3 +30,21 @@ function setup() {
echo $output
[ "$status" -ne 0 ]
}
@test "run ipcns test" {
${KPOD_BINARY} ${KPOD_OPTIONS} pull ${ALPINE}
tmp=$(mktemp /dev/shm/foo.XXXXX)
run ${KPOD_BINARY} ${KPOD_OPTIONS} run --ipc=host ${ALPINE} ls $tmp
echo $output
out=$(echo $output | tr -d '\r')
[ "$status" -eq 0 ]
[ $out != $tmp ]
rm -f $tmp
run ${KPOD_BINARY} ${KPOD_OPTIONS} run --ipc=badpid ${ALPINE} sh -c 'echo $$'
echo $output
[ "$status" -ne 0 ]
}