diff options
Diffstat (limited to 'libpod/container.go')
-rw-r--r-- | libpod/container.go | 140 |
1 files changed, 95 insertions, 45 deletions
diff --git a/libpod/container.go b/libpod/container.go index e69037353..31fbbbcc5 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -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 +} |