summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/boltdb_state.go33
-rw-r--r--libpod/boltdb_state_internal.go60
-rw-r--r--libpod/boltdb_state_linux.go67
-rw-r--r--libpod/boltdb_state_unsupported.go11
-rw-r--r--libpod/container_inspect.go31
-rw-r--r--libpod/container_internal.go249
-rw-r--r--libpod/container_internal_linux.go265
-rw-r--r--libpod/container_internal_unsupported.go26
-rw-r--r--libpod/container_linux.go38
-rw-r--r--libpod/container_unsupported.go8
-rw-r--r--libpod/finished_64.go2
-rw-r--r--libpod/finished_unsupported.go12
-rw-r--r--libpod/networking_linux.go33
-rw-r--r--libpod/networking_unsupported.go27
-rw-r--r--libpod/oci.go61
-rw-r--r--libpod/oci_linux.go63
-rw-r--r--libpod/oci_unsupported.go15
17 files changed, 573 insertions, 428 deletions
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index d7c950fa0..45d09348e 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -7,7 +7,6 @@ import (
"github.com/boltdb/bolt"
"github.com/pkg/errors"
- "github.com/sirupsen/logrus"
)
// BoltState is a state implementation backed by a Bolt DB
@@ -443,32 +442,7 @@ func (s *BoltState) UpdateContainer(ctr *Container) error {
}
// Do we need to replace the container's netns?
- if netNSPath != "" {
- // Check if the container's old state has a good netns
- if ctr.state.NetNS != nil && netNSPath == ctr.state.NetNS.Path() {
- newState.NetNS = ctr.state.NetNS
- } else {
- // Tear down the existing namespace
- if err := s.runtime.teardownNetNS(ctr); err != nil {
- logrus.Warnf(err.Error())
- }
-
- // Open the new network namespace
- ns, err := joinNetNS(netNSPath)
- if err == nil {
- newState.NetNS = ns
- } else {
- logrus.Errorf("error joining network namespace for container %s", ctr.ID())
- ctr.valid = false
- }
- }
- } else {
- // The container no longer has a network namespace
- // Tear down the old one
- if err := s.runtime.teardownNetNS(ctr); err != nil {
- logrus.Warnf(err.Error())
- }
- }
+ ctr.setNamespace(netNSPath, newState)
// New state compiled successfully, swap it into the current state
ctr.state = newState
@@ -490,10 +464,7 @@ func (s *BoltState) SaveContainer(ctr *Container) error {
if err != nil {
return errors.Wrapf(err, "error marshalling container %s state to JSON", ctr.ID())
}
- netNSPath := ""
- if ctr.state.NetNS != nil {
- netNSPath = ctr.state.NetNS.Path()
- }
+ netNSPath := ctr.setNamespaceStatePath()
ctrID := []byte(ctr.ID())
diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go
index e8aa6860b..69e7bee21 100644
--- a/libpod/boltdb_state_internal.go
+++ b/libpod/boltdb_state_internal.go
@@ -205,60 +205,6 @@ func getRuntimeConfigBucket(tx *bolt.Tx) (*bolt.Bucket, error) {
return bkt, nil
}
-func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.Bucket) error {
- valid := true
- ctrBkt := ctrsBkt.Bucket(id)
- if ctrBkt == nil {
- return errors.Wrapf(ErrNoSuchCtr, "container %s not found in DB", string(id))
- }
-
- configBytes := ctrBkt.Get(configKey)
- if configBytes == nil {
- return errors.Wrapf(ErrInternal, "container %s missing config key in DB", string(id))
- }
-
- stateBytes := ctrBkt.Get(stateKey)
- if stateBytes == nil {
- return errors.Wrapf(ErrInternal, "container %s missing state key in DB", string(id))
- }
-
- netNSBytes := ctrBkt.Get(netNSKey)
-
- if err := json.Unmarshal(configBytes, ctr.config); err != nil {
- return errors.Wrapf(err, "error unmarshalling container %s config", string(id))
- }
-
- if err := json.Unmarshal(stateBytes, ctr.state); err != nil {
- return errors.Wrapf(err, "error unmarshalling container %s state", string(id))
- }
-
- // The container may not have a network namespace, so it's OK if this is
- // nil
- if netNSBytes != nil {
- nsPath := string(netNSBytes)
- netNS, err := joinNetNS(nsPath)
- if err == nil {
- ctr.state.NetNS = netNS
- } else {
- logrus.Errorf("error joining network namespace for container %s", ctr.ID())
- valid = false
- }
- }
-
- // Get the lock
- lockPath := filepath.Join(s.lockDir, string(id))
- lock, err := storage.GetLockfile(lockPath)
- if err != nil {
- return errors.Wrapf(err, "error retrieving lockfile for container %s", string(id))
- }
- ctr.lock = lock
-
- ctr.runtime = s.runtime
- ctr.valid = valid
-
- return nil
-}
-
func (s *BoltState) getPodFromDB(id []byte, pod *Pod, podBkt *bolt.Bucket) error {
podDB := podBkt.Bucket(id)
if podDB == nil {
@@ -310,11 +256,7 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error {
if err != nil {
return errors.Wrapf(err, "error marshalling container %s state to JSON", ctr.ID())
}
- netNSPath := ""
- if ctr.state.NetNS != nil {
- netNSPath = ctr.state.NetNS.Path()
- }
-
+ netNSPath := ctr.setNamespaceStatePath()
dependsCtrs := ctr.Dependencies()
ctrID := []byte(ctr.ID())
diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go
new file mode 100644
index 000000000..ceea955bd
--- /dev/null
+++ b/libpod/boltdb_state_linux.go
@@ -0,0 +1,67 @@
+// +build linux
+
+package libpod
+
+import (
+ "encoding/json"
+ "path/filepath"
+
+ "github.com/boltdb/bolt"
+ "github.com/containers/storage"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.Bucket) error {
+ valid := true
+ ctrBkt := ctrsBkt.Bucket(id)
+ if ctrBkt == nil {
+ return errors.Wrapf(ErrNoSuchCtr, "container %s not found in DB", string(id))
+ }
+
+ configBytes := ctrBkt.Get(configKey)
+ if configBytes == nil {
+ return errors.Wrapf(ErrInternal, "container %s missing config key in DB", string(id))
+ }
+
+ stateBytes := ctrBkt.Get(stateKey)
+ if stateBytes == nil {
+ return errors.Wrapf(ErrInternal, "container %s missing state key in DB", string(id))
+ }
+
+ netNSBytes := ctrBkt.Get(netNSKey)
+
+ if err := json.Unmarshal(configBytes, ctr.config); err != nil {
+ return errors.Wrapf(err, "error unmarshalling container %s config", string(id))
+ }
+
+ if err := json.Unmarshal(stateBytes, ctr.state); err != nil {
+ return errors.Wrapf(err, "error unmarshalling container %s state", string(id))
+ }
+
+ // The container may not have a network namespace, so it's OK if this is
+ // nil
+ if netNSBytes != nil {
+ nsPath := string(netNSBytes)
+ netNS, err := joinNetNS(nsPath)
+ if err == nil {
+ ctr.state.NetNS = netNS
+ } else {
+ logrus.Errorf("error joining network namespace for container %s", ctr.ID())
+ valid = false
+ }
+ }
+
+ // Get the lock
+ lockPath := filepath.Join(s.lockDir, string(id))
+ lock, err := storage.GetLockfile(lockPath)
+ if err != nil {
+ return errors.Wrapf(err, "error retrieving lockfile for container %s", string(id))
+ }
+ ctr.lock = lock
+
+ ctr.runtime = s.runtime
+ ctr.valid = valid
+
+ return nil
+}
diff --git a/libpod/boltdb_state_unsupported.go b/libpod/boltdb_state_unsupported.go
new file mode 100644
index 000000000..8d3749881
--- /dev/null
+++ b/libpod/boltdb_state_unsupported.go
@@ -0,0 +1,11 @@
+// +build !linux
+
+package libpod
+
+import (
+ "github.com/boltdb/bolt"
+)
+
+func (s *BoltState) getContainerFromDB(id []byte, ctr *Container, ctrsBkt *bolt.Bucket) error {
+ return ErrNotImplemented
+}
diff --git a/libpod/container_inspect.go b/libpod/container_inspect.go
index 1381341c2..a1070cf99 100644
--- a/libpod/container_inspect.go
+++ b/libpod/container_inspect.go
@@ -1,9 +1,6 @@
package libpod
import (
- "strconv"
- "strings"
-
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/projectatomic/libpod/pkg/inspect"
"github.com/sirupsen/logrus"
@@ -114,33 +111,7 @@ func (c *Container) getContainerInspectData(size bool, driverData *inspect.Data)
}
// Get information on the container's network namespace (if present)
- if runtimeInfo.NetNS != nil {
- // Go through our IP addresses
- for _, ctrIP := range c.state.IPs {
- ipWithMask := ctrIP.Address.String()
- splitIP := strings.Split(ipWithMask, "/")
- mask, _ := strconv.Atoi(splitIP[1])
- if ctrIP.Version == "4" {
- data.NetworkSettings.IPAddress = splitIP[0]
- data.NetworkSettings.IPPrefixLen = mask
- data.NetworkSettings.Gateway = ctrIP.Gateway.String()
- } else {
- data.NetworkSettings.GlobalIPv6Address = splitIP[0]
- data.NetworkSettings.GlobalIPv6PrefixLen = mask
- data.NetworkSettings.IPv6Gateway = ctrIP.Gateway.String()
- }
- }
-
- // Set network namespace path
- data.NetworkSettings.SandboxKey = runtimeInfo.NetNS.Path()
-
- // Set MAC address of interface linked with network namespace path
- for _, i := range c.state.Interfaces {
- if i.Sandbox == data.NetworkSettings.SandboxKey {
- data.NetworkSettings.MacAddress = i.Mac
- }
- }
- }
+ data = c.getContainerNetworkInfo(data)
if size {
rootFsSize, err := c.rootFsSize()
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 22b398709..452be176c 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -8,7 +8,6 @@ import (
"io"
"io/ioutil"
"os"
- "path"
"path/filepath"
"strings"
"syscall"
@@ -17,14 +16,12 @@ import (
"github.com/containers/storage"
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/chrootarchive"
- "github.com/containers/storage/pkg/idtools"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/stringid"
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/projectatomic/libpod/pkg/chrootuser"
"github.com/projectatomic/libpod/pkg/hooks"
"github.com/projectatomic/libpod/pkg/hooks/exec"
@@ -33,7 +30,6 @@ import (
"github.com/projectatomic/libpod/pkg/util"
"github.com/sirupsen/logrus"
"github.com/ulule/deepcopier"
- "golang.org/x/sys/unix"
"golang.org/x/text/language"
)
@@ -748,9 +744,8 @@ func (c *Container) mountStorage() (err error) {
if !mounted {
shmOptions := fmt.Sprintf("mode=1777,size=%d", c.config.ShmSize)
- 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)
+ if err := c.mountSHM(shmOptions); err != nil {
+ return err
}
if err := os.Chown(c.config.ShmDir, c.RootUID(), c.RootGID()); err != nil {
return errors.Wrapf(err, "failed to chown %s", c.config.ShmDir)
@@ -786,53 +781,6 @@ func (c *Container) mountStorage() (err error) {
return c.save()
}
-// prepare mounts the container and sets up other required resources like net
-// namespaces
-func (c *Container) prepare() (err error) {
- // Mount storage if not mounted
- if err := c.mountStorage(); err != nil {
- return err
- }
-
- // Set up network namespace if not already set up
- if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS {
- if err := c.runtime.createNetNS(c); err != nil {
- // Tear down storage before exiting to make sure we
- // don't leak mounts
- if err2 := c.cleanupStorage(); err2 != nil {
- logrus.Errorf("Error cleaning up storage for container %s: %v", c.ID(), err2)
- }
- return err
- }
- }
-
- return nil
-}
-
-// cleanupNetwork unmounts and cleans up the container's network
-func (c *Container) cleanupNetwork() error {
- if c.state.NetNS == nil {
- logrus.Debugf("Network is already cleaned up, skipping...")
- return nil
- }
-
- // Stop the container's network namespace (if it has one)
- if err := c.runtime.teardownNetNS(c); err != nil {
- logrus.Errorf("unable to cleanup network for container %s: %q", c.ID(), err)
- }
-
- c.state.NetNS = nil
- c.state.IPs = nil
- c.state.Interfaces = nil
- c.state.Routes = nil
-
- if c.valid {
- return c.save()
- }
-
- return nil
-}
-
// cleanupStorage unmounts and cleans up the container's root filesystem
func (c *Container) cleanupStorage() error {
if !c.state.Mounted {
@@ -842,10 +790,8 @@ func (c *Container) cleanupStorage() error {
}
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)
- }
+ if err := c.unmountSHM(mount); err != nil {
+ return err
}
}
if c.config.Rootfs != "" {
@@ -1178,193 +1124,6 @@ func (c *Container) generateHosts() (string, error) {
return c.writeStringToRundir("hosts", hosts)
}
-// Generate spec for a container
-// Accepts a map of the container's dependencies
-func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
- g := generate.NewFromSpec(c.config.Spec)
-
- // If network namespace was requested, add it now
- if c.config.CreateNetNS {
- if c.config.PostConfigureNetNS {
- g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, "")
- } else {
- g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path())
- }
- }
-
- // Remove the default /dev/shm mount to ensure we overwrite it
- g.RemoveMount("/dev/shm")
-
- // Add bind mounts to container
- for dstPath, srcPath := range c.state.BindMounts {
- newMount := spec.Mount{
- Type: "bind",
- Source: srcPath,
- Destination: dstPath,
- Options: []string{"rw", "bind"},
- }
- if !MountExists(g.Mounts(), dstPath) {
- g.AddMount(newMount)
- } else {
- logrus.Warnf("User mount overriding libpod mount at %q", dstPath)
- }
- }
-
- var err error
- if !rootless.IsRootless() {
- if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil {
- return nil, errors.Wrapf(err, "error setting up OCI Hooks")
- }
- }
-
- // Bind builtin image volumes
- if c.config.Rootfs == "" && c.config.ImageVolumes {
- if err := c.addImageVolumes(ctx, &g); err != nil {
- return nil, errors.Wrapf(err, "error mounting image volumes")
- }
- }
-
- if c.config.User != "" {
- if !c.state.Mounted {
- return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID())
- }
- uid, gid, err := chrootuser.GetUser(c.state.Mountpoint, c.config.User)
- if err != nil {
- return nil, err
- }
- // User and Group must go together
- g.SetProcessUID(uid)
- g.SetProcessGID(gid)
- }
-
- // Add addition groups if c.config.GroupAdd is not empty
- if len(c.config.Groups) > 0 {
- if !c.state.Mounted {
- return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to add additional groups", c.ID())
- }
- for _, group := range c.config.Groups {
- gid, err := chrootuser.GetGroup(c.state.Mountpoint, group)
- if err != nil {
- return nil, err
- }
- g.AddProcessAdditionalGid(gid)
- }
- }
-
- // Look up and add groups the user belongs to, if a group wasn't directly specified
- if !rootless.IsRootless() && !strings.Contains(c.config.User, ":") {
- groups, err := chrootuser.GetAdditionalGroupsForUser(c.state.Mountpoint, uint64(g.Config.Process.User.UID))
- if err != nil && errors.Cause(err) != chrootuser.ErrNoSuchUser {
- return nil, err
- }
- for _, gid := range groups {
- g.AddProcessAdditionalGid(gid)
- }
- }
-
- // Add shared namespaces from other containers
- if c.config.IPCNsCtr != "" {
- if err := c.addNamespaceContainer(&g, IPCNS, c.config.IPCNsCtr, spec.IPCNamespace); err != nil {
- return nil, err
- }
- }
- if c.config.MountNsCtr != "" {
- if err := c.addNamespaceContainer(&g, MountNS, c.config.MountNsCtr, spec.MountNamespace); err != nil {
- return nil, err
- }
- }
- if c.config.NetNsCtr != "" {
- if err := c.addNamespaceContainer(&g, NetNS, c.config.NetNsCtr, spec.NetworkNamespace); err != nil {
- return nil, err
- }
- }
- if c.config.PIDNsCtr != "" {
- if err := c.addNamespaceContainer(&g, PIDNS, c.config.PIDNsCtr, string(spec.PIDNamespace)); err != nil {
- return nil, err
- }
- }
- if c.config.UserNsCtr != "" {
- if err := c.addNamespaceContainer(&g, UserNS, c.config.UserNsCtr, spec.UserNamespace); err != nil {
- return nil, err
- }
- }
- if c.config.UTSNsCtr != "" {
- if err := c.addNamespaceContainer(&g, UTSNS, c.config.UTSNsCtr, spec.UTSNamespace); err != nil {
- return nil, err
- }
- }
- if c.config.CgroupNsCtr != "" {
- if err := c.addNamespaceContainer(&g, CgroupNS, c.config.CgroupNsCtr, spec.CgroupNamespace); err != nil {
- return nil, err
- }
- }
-
- if c.config.Rootfs == "" {
- if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil {
- return nil, err
- }
- }
-
- g.SetRootPath(c.state.RealMountpoint)
- g.AddAnnotation(crioAnnotations.Created, c.config.CreatedTime.Format(time.RFC3339Nano))
- g.AddAnnotation("org.opencontainers.image.stopSignal", fmt.Sprintf("%d", c.config.StopSignal))
-
- g.SetHostname(c.Hostname())
- g.AddProcessEnv("HOSTNAME", g.Config.Hostname)
-
- // Only add container environment variable if not already present
- foundContainerEnv := false
- for _, env := range g.Config.Process.Env {
- if strings.HasPrefix(env, "container=") {
- foundContainerEnv = true
- break
- }
- }
- if !foundContainerEnv {
- g.AddProcessEnv("container", "libpod")
- }
-
- if rootless.IsRootless() {
- g.SetLinuxCgroupsPath("")
- } else if c.runtime.config.CgroupManager == SystemdCgroupsManager {
- // When runc is set to use Systemd as a cgroup manager, it
- // expects cgroups to be passed as follows:
- // slice:prefix:name
- systemdCgroups := fmt.Sprintf("%s:libpod:%s", path.Base(c.config.CgroupParent), c.ID())
- logrus.Debugf("Setting CGroups for container %s to %s", c.ID(), systemdCgroups)
- g.SetLinuxCgroupsPath(systemdCgroups)
- } else {
- cgroupPath, err := c.CGroupPath()
- if err != nil {
- return nil, err
- }
- logrus.Debugf("Setting CGroup path for container %s to %s", c.ID(), cgroupPath)
- g.SetLinuxCgroupsPath(cgroupPath)
- }
-
- return g.Config, nil
-}
-
-// Add an existing container's namespace to the spec
-func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr string, specNS string) error {
- nsCtr, err := c.runtime.state.Container(ctr)
- if err != nil {
- return errors.Wrapf(err, "error retrieving dependency %s of container %s from state", ctr, c.ID())
- }
-
- // TODO need unlocked version of this for use in pods
- nsPath, err := nsCtr.NamespacePath(ns)
- if err != nil {
- return err
- }
-
- if err := g.AddOrReplaceLinuxNamespace(specNS, nsPath); err != nil {
- return err
- }
-
- return nil
-}
-
func (c *Container) addImageVolumes(ctx context.Context, g *generate.Generator) error {
mountPoint := c.state.Mountpoint
if !c.state.Mounted {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 41b8a86fc..327c78045 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -3,11 +3,25 @@
package libpod
import (
+ "context"
"fmt"
+ "path"
"path/filepath"
+ "strings"
+ "syscall"
+ "time"
"github.com/containerd/cgroups"
+ "github.com/containers/storage/pkg/idtools"
+ 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/projectatomic/libpod/pkg/chrootuser"
+ "github.com/projectatomic/libpod/pkg/rootless"
"github.com/sirupsen/logrus"
+ "golang.org/x/sys/unix"
)
// cleanupCgroup cleans up residual CGroups after container execution
@@ -50,3 +64,254 @@ func (c *Container) cleanupCgroups() error {
return nil
}
+
+func (c *Container) mountSHM(shmOptions string) error {
+ 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)
+ }
+ return nil
+}
+
+func (c *Container) unmountSHM(mount string) error {
+ 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)
+ }
+ }
+ return nil
+}
+
+// prepare mounts the container and sets up other required resources like net
+// namespaces
+func (c *Container) prepare() (err error) {
+ // Mount storage if not mounted
+ if err := c.mountStorage(); err != nil {
+ return err
+ }
+
+ // Set up network namespace if not already set up
+ if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS {
+ if err := c.runtime.createNetNS(c); err != nil {
+ // Tear down storage before exiting to make sure we
+ // don't leak mounts
+ if err2 := c.cleanupStorage(); err2 != nil {
+ logrus.Errorf("Error cleaning up storage for container %s: %v", c.ID(), err2)
+ }
+ return err
+ }
+ }
+
+ return nil
+}
+
+// cleanupNetwork unmounts and cleans up the container's network
+func (c *Container) cleanupNetwork() error {
+ if c.state.NetNS == nil {
+ logrus.Debugf("Network is already cleaned up, skipping...")
+ return nil
+ }
+
+ // Stop the container's network namespace (if it has one)
+ if err := c.runtime.teardownNetNS(c); err != nil {
+ logrus.Errorf("unable to cleanup network for container %s: %q", c.ID(), err)
+ }
+
+ c.state.NetNS = nil
+ c.state.IPs = nil
+ c.state.Interfaces = nil
+ c.state.Routes = nil
+
+ if c.valid {
+ return c.save()
+ }
+
+ return nil
+}
+
+// Generate spec for a container
+// Accepts a map of the container's dependencies
+func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
+ g := generate.NewFromSpec(c.config.Spec)
+
+ // If network namespace was requested, add it now
+ if c.config.CreateNetNS {
+ if c.config.PostConfigureNetNS {
+ g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, "")
+ } else {
+ g.AddOrReplaceLinuxNamespace(spec.NetworkNamespace, c.state.NetNS.Path())
+ }
+ }
+
+ // Remove the default /dev/shm mount to ensure we overwrite it
+ g.RemoveMount("/dev/shm")
+
+ // Add bind mounts to container
+ for dstPath, srcPath := range c.state.BindMounts {
+ newMount := spec.Mount{
+ Type: "bind",
+ Source: srcPath,
+ Destination: dstPath,
+ Options: []string{"rw", "bind"},
+ }
+ if !MountExists(g.Mounts(), dstPath) {
+ g.AddMount(newMount)
+ } else {
+ logrus.Warnf("User mount overriding libpod mount at %q", dstPath)
+ }
+ }
+
+ var err error
+ if !rootless.IsRootless() {
+ if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil {
+ return nil, errors.Wrapf(err, "error setting up OCI Hooks")
+ }
+ }
+
+ // Bind builtin image volumes
+ if c.config.Rootfs == "" && c.config.ImageVolumes {
+ if err := c.addImageVolumes(ctx, &g); err != nil {
+ return nil, errors.Wrapf(err, "error mounting image volumes")
+ }
+ }
+
+ if c.config.User != "" {
+ if !c.state.Mounted {
+ return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID())
+ }
+ uid, gid, err := chrootuser.GetUser(c.state.Mountpoint, c.config.User)
+ if err != nil {
+ return nil, err
+ }
+ // User and Group must go together
+ g.SetProcessUID(uid)
+ g.SetProcessGID(gid)
+ }
+
+ // Add addition groups if c.config.GroupAdd is not empty
+ if len(c.config.Groups) > 0 {
+ if !c.state.Mounted {
+ return nil, errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to add additional groups", c.ID())
+ }
+ for _, group := range c.config.Groups {
+ gid, err := chrootuser.GetGroup(c.state.Mountpoint, group)
+ if err != nil {
+ return nil, err
+ }
+ g.AddProcessAdditionalGid(gid)
+ }
+ }
+
+ // Look up and add groups the user belongs to, if a group wasn't directly specified
+ if !rootless.IsRootless() && !strings.Contains(c.config.User, ":") {
+ groups, err := chrootuser.GetAdditionalGroupsForUser(c.state.Mountpoint, uint64(g.Config.Process.User.UID))
+ if err != nil && errors.Cause(err) != chrootuser.ErrNoSuchUser {
+ return nil, err
+ }
+ for _, gid := range groups {
+ g.AddProcessAdditionalGid(gid)
+ }
+ }
+
+ // Add shared namespaces from other containers
+ if c.config.IPCNsCtr != "" {
+ if err := c.addNamespaceContainer(&g, IPCNS, c.config.IPCNsCtr, spec.IPCNamespace); err != nil {
+ return nil, err
+ }
+ }
+ if c.config.MountNsCtr != "" {
+ if err := c.addNamespaceContainer(&g, MountNS, c.config.MountNsCtr, spec.MountNamespace); err != nil {
+ return nil, err
+ }
+ }
+ if c.config.NetNsCtr != "" {
+ if err := c.addNamespaceContainer(&g, NetNS, c.config.NetNsCtr, spec.NetworkNamespace); err != nil {
+ return nil, err
+ }
+ }
+ if c.config.PIDNsCtr != "" {
+ if err := c.addNamespaceContainer(&g, PIDNS, c.config.PIDNsCtr, string(spec.PIDNamespace)); err != nil {
+ return nil, err
+ }
+ }
+ if c.config.UserNsCtr != "" {
+ if err := c.addNamespaceContainer(&g, UserNS, c.config.UserNsCtr, spec.UserNamespace); err != nil {
+ return nil, err
+ }
+ }
+ if c.config.UTSNsCtr != "" {
+ if err := c.addNamespaceContainer(&g, UTSNS, c.config.UTSNsCtr, spec.UTSNamespace); err != nil {
+ return nil, err
+ }
+ }
+ if c.config.CgroupNsCtr != "" {
+ if err := c.addNamespaceContainer(&g, CgroupNS, c.config.CgroupNsCtr, spec.CgroupNamespace); err != nil {
+ return nil, err
+ }
+ }
+
+ if c.config.Rootfs == "" {
+ if err := idtools.MkdirAllAs(c.state.RealMountpoint, 0700, c.RootUID(), c.RootGID()); err != nil {
+ return nil, err
+ }
+ }
+
+ g.SetRootPath(c.state.RealMountpoint)
+ g.AddAnnotation(crioAnnotations.Created, c.config.CreatedTime.Format(time.RFC3339Nano))
+ g.AddAnnotation("org.opencontainers.image.stopSignal", fmt.Sprintf("%d", c.config.StopSignal))
+
+ g.SetHostname(c.Hostname())
+ g.AddProcessEnv("HOSTNAME", g.Config.Hostname)
+
+ // Only add container environment variable if not already present
+ foundContainerEnv := false
+ for _, env := range g.Config.Process.Env {
+ if strings.HasPrefix(env, "container=") {
+ foundContainerEnv = true
+ break
+ }
+ }
+ if !foundContainerEnv {
+ g.AddProcessEnv("container", "libpod")
+ }
+
+ if rootless.IsRootless() {
+ g.SetLinuxCgroupsPath("")
+ } else if c.runtime.config.CgroupManager == SystemdCgroupsManager {
+ // When runc is set to use Systemd as a cgroup manager, it
+ // expects cgroups to be passed as follows:
+ // slice:prefix:name
+ systemdCgroups := fmt.Sprintf("%s:libpod:%s", path.Base(c.config.CgroupParent), c.ID())
+ logrus.Debugf("Setting CGroups for container %s to %s", c.ID(), systemdCgroups)
+ g.SetLinuxCgroupsPath(systemdCgroups)
+ } else {
+ cgroupPath, err := c.CGroupPath()
+ if err != nil {
+ return nil, err
+ }
+ logrus.Debugf("Setting CGroup path for container %s to %s", c.ID(), cgroupPath)
+ g.SetLinuxCgroupsPath(cgroupPath)
+ }
+
+ return g.Config, nil
+}
+
+// Add an existing container's namespace to the spec
+func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr string, specNS string) error {
+ nsCtr, err := c.runtime.state.Container(ctr)
+ if err != nil {
+ return errors.Wrapf(err, "error retrieving dependency %s of container %s from state", ctr, c.ID())
+ }
+
+ // TODO need unlocked version of this for use in pods
+ nsPath, err := nsCtr.NamespacePath(ns)
+ if err != nil {
+ return err
+ }
+
+ if err := g.AddOrReplaceLinuxNamespace(specNS, nsPath); err != nil {
+ return err
+ }
+
+ return nil
+}
diff --git a/libpod/container_internal_unsupported.go b/libpod/container_internal_unsupported.go
index 015536850..975d6d714 100644
--- a/libpod/container_internal_unsupported.go
+++ b/libpod/container_internal_unsupported.go
@@ -2,6 +2,32 @@
package libpod
+import (
+ "context"
+
+ spec "github.com/opencontainers/runtime-spec/specs-go"
+)
+
func (c *Container) cleanupCgroups() error {
return ErrOSNotSupported
}
+
+func (c *Container) mountSHM(shmOptions string) error {
+ return ErrNotImplemented
+}
+
+func (c *Container) unmountSHM(mount string) error {
+ return ErrNotImplemented
+}
+
+func (c *Container) prepare() (err error) {
+ return ErrNotImplemented
+}
+
+func (c *Container) cleanupNetwork() error {
+ return ErrNotImplemented
+}
+
+func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
+ return nil, ErrNotImplemented
+}
diff --git a/libpod/container_linux.go b/libpod/container_linux.go
index 823a590dd..2330f27a7 100644
--- a/libpod/container_linux.go
+++ b/libpod/container_linux.go
@@ -4,6 +4,7 @@ package libpod
import (
"github.com/containernetworking/plugins/pkg/ns"
+ "github.com/sirupsen/logrus"
)
type containerPlatformState struct {
@@ -13,3 +14,40 @@ type containerPlatformState struct {
// told to join another container's network namespace
NetNS ns.NetNS `json:"-"`
}
+
+func (ctr *Container) setNamespace(netNSPath string, newState *containerState) error {
+ if netNSPath != "" {
+ // Check if the container's old state has a good netns
+ if ctr.state.NetNS != nil && netNSPath == ctr.state.NetNS.Path() {
+ newState.NetNS = ctr.state.NetNS
+ } else {
+ // Tear down the existing namespace
+ if err := ctr.runtime.teardownNetNS(ctr); err != nil {
+ logrus.Warnf(err.Error())
+ }
+
+ // Open the new network namespace
+ ns, err := joinNetNS(netNSPath)
+ if err == nil {
+ newState.NetNS = ns
+ } else {
+ logrus.Errorf("error joining network namespace for container %s", ctr.ID())
+ ctr.valid = false
+ }
+ }
+ } else {
+ // The container no longer has a network namespace
+ // Tear down the old one
+ if err := ctr.runtime.teardownNetNS(ctr); err != nil {
+ logrus.Warnf(err.Error())
+ }
+ }
+ return nil
+}
+
+func (ctr *Container) setNamespaceStatePath() string {
+ if ctr.state.NetNS != nil {
+ return ctr.state.NetNS.Path()
+ }
+ return ""
+}
diff --git a/libpod/container_unsupported.go b/libpod/container_unsupported.go
index e214b9465..5b923b52a 100644
--- a/libpod/container_unsupported.go
+++ b/libpod/container_unsupported.go
@@ -3,3 +3,11 @@
package libpod
type containerPlatformState struct{}
+
+func (ctr *Container) setNamespace(netNSPath string, newState *containerState) error {
+ return ErrNotImplemented
+}
+
+func (ctr *Container) setNamespaceStatePath() string {
+ return ""
+}
diff --git a/libpod/finished_64.go b/libpod/finished_64.go
index 11dbc9181..3688afa84 100644
--- a/libpod/finished_64.go
+++ b/libpod/finished_64.go
@@ -1,4 +1,4 @@
-// +build !arm,!386
+// +build !arm,!386,linux
package libpod
diff --git a/libpod/finished_unsupported.go b/libpod/finished_unsupported.go
new file mode 100644
index 000000000..a893d668c
--- /dev/null
+++ b/libpod/finished_unsupported.go
@@ -0,0 +1,12 @@
+// +build darwin,!linux
+
+package libpod
+
+import (
+ "os"
+ "time"
+)
+
+func getFinishedTime(fi os.FileInfo) time.Time {
+ return time.Time{}
+}
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index ee90b765c..59666b534 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -8,6 +8,7 @@ import (
"net"
"os"
"path/filepath"
+ "strconv"
"strings"
"syscall"
@@ -15,6 +16,7 @@ import (
"github.com/containernetworking/plugins/pkg/ns"
"github.com/cri-o/ocicni/pkg/ocicni"
"github.com/pkg/errors"
+ "github.com/projectatomic/libpod/pkg/inspect"
"github.com/projectatomic/libpod/utils"
"github.com/sirupsen/logrus"
"github.com/vishvananda/netlink"
@@ -228,3 +230,34 @@ func getContainerNetIO(ctr *Container) (*netlink.LinkStatistics, error) {
})
return netStats, err
}
+
+func (c *Container) getContainerNetworkInfo(data *inspect.ContainerInspectData) *inspect.ContainerInspectData {
+ if c.state.NetNS != nil {
+ // Go through our IP addresses
+ for _, ctrIP := range c.state.IPs {
+ ipWithMask := ctrIP.Address.String()
+ splitIP := strings.Split(ipWithMask, "/")
+ mask, _ := strconv.Atoi(splitIP[1])
+ if ctrIP.Version == "4" {
+ data.NetworkSettings.IPAddress = splitIP[0]
+ data.NetworkSettings.IPPrefixLen = mask
+ data.NetworkSettings.Gateway = ctrIP.Gateway.String()
+ } else {
+ data.NetworkSettings.GlobalIPv6Address = splitIP[0]
+ data.NetworkSettings.GlobalIPv6PrefixLen = mask
+ data.NetworkSettings.IPv6Gateway = ctrIP.Gateway.String()
+ }
+ }
+
+ // Set network namespace path
+ data.NetworkSettings.SandboxKey = c.state.NetNS.Path()
+
+ // Set MAC address of interface linked with network namespace path
+ for _, i := range c.state.Interfaces {
+ if i.Sandbox == data.NetworkSettings.SandboxKey {
+ data.NetworkSettings.MacAddress = i.Mac
+ }
+ }
+ }
+ return data
+}
diff --git a/libpod/networking_unsupported.go b/libpod/networking_unsupported.go
new file mode 100644
index 000000000..4ff8ecd62
--- /dev/null
+++ b/libpod/networking_unsupported.go
@@ -0,0 +1,27 @@
+// +build !linux
+
+package libpod
+
+import (
+ "github.com/projectatomic/libpod/pkg/inspect"
+)
+
+func JoinNetworkNameSpace(netNSBytes []byte) (*Container, bool, error) {
+ return nil, false, ErrNotImplemented
+}
+
+func (r *Runtime) setupNetNS(ctr *Container) (err error) {
+ return ErrNotImplemented
+}
+
+func (r *Runtime) teardownNetNS(ctr *Container) error {
+ return ErrNotImplemented
+}
+
+func (r *Runtime) createNetNS(ctr *Container) (err error) {
+ return ErrNotImplemented
+}
+
+func (c *Container) getContainerNetworkInfo(data *inspect.ContainerInspectData) *inspect.ContainerInspectData {
+ return nil
+}
diff --git a/libpod/oci.go b/libpod/oci.go
index 20d533726..fcb36241b 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -11,11 +11,9 @@ import (
"runtime"
"strconv"
"strings"
- "sync"
"syscall"
"time"
- "github.com/containers/storage/pkg/idtools"
"github.com/coreos/go-systemd/activation"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/selinux/go-selinux"
@@ -110,15 +108,6 @@ func newOCIRuntime(name string, path string, conmonPath string, conmonEnv []stri
return runtime, nil
}
-// newPipe creates a unix socket pair for communication
-func newPipe() (parent *os.File, child *os.File, err error) {
- fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
- if err != nil {
- return nil, nil, err
- }
- return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
-}
-
// Create systemd unit name for cgroup scopes
func createUnitName(prefix string, name string) string {
return fmt.Sprintf("%s-%s.scope", prefix, name)
@@ -187,56 +176,6 @@ func waitPidsStop(pids []int, timeout time.Duration) error {
}
}
-// CreateContainer creates a container in the OCI runtime
-// TODO terminal support for container
-// Presently just ignoring conmon opts related to it
-func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string) (err error) {
- if ctr.state.UserNSRoot == "" {
- // no need of an intermediate mount ns
- return r.createOCIContainer(ctr, cgroupParent)
- }
- var wg sync.WaitGroup
- wg.Add(1)
- go func() {
- defer wg.Done()
- runtime.LockOSThread()
-
- fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid()))
- if err != nil {
- return
- }
- defer fd.Close()
-
- // create a new mountns on the current thread
- if err = unix.Unshare(unix.CLONE_NEWNS); err != nil {
- return
- }
- defer unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS)
-
- // don't spread our mounts around
- err = unix.Mount("/", "/", "none", unix.MS_REC|unix.MS_SLAVE, "")
- if err != nil {
- return
- }
- err = unix.Mount(ctr.state.Mountpoint, ctr.state.RealMountpoint, "none", unix.MS_BIND, "")
- if err != nil {
- return
- }
- if err := idtools.MkdirAllAs(ctr.state.DestinationRunDir, 0700, ctr.RootUID(), ctr.RootGID()); err != nil {
- return
- }
-
- err = unix.Mount(ctr.state.RunDir, ctr.state.DestinationRunDir, "none", unix.MS_BIND, "")
- if err != nil {
- return
- }
- err = r.createOCIContainer(ctr, cgroupParent)
- }()
- wg.Wait()
-
- return err
-}
-
func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string) (err error) {
var stderrBuf bytes.Buffer
diff --git a/libpod/oci_linux.go b/libpod/oci_linux.go
index 14373cbb2..2128b7481 100644
--- a/libpod/oci_linux.go
+++ b/libpod/oci_linux.go
@@ -7,11 +7,15 @@ import (
"os"
"os/exec"
"path/filepath"
+ "runtime"
+ "sync"
"github.com/containerd/cgroups"
+ "github.com/containers/storage/pkg/idtools"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/projectatomic/libpod/utils"
"github.com/sirupsen/logrus"
+ "golang.org/x/sys/unix"
)
func (r *OCIRuntime) moveConmonToCgroup(ctr *Container, cgroupParent string, cmd *exec.Cmd) error {
@@ -39,3 +43,62 @@ func (r *OCIRuntime) moveConmonToCgroup(ctr *Container, cgroupParent string, cmd
}
return nil
}
+
+// newPipe creates a unix socket pair for communication
+func newPipe() (parent *os.File, child *os.File, err error) {
+ fds, err := unix.Socketpair(unix.AF_LOCAL, unix.SOCK_STREAM|unix.SOCK_CLOEXEC, 0)
+ if err != nil {
+ return nil, nil, err
+ }
+ return os.NewFile(uintptr(fds[1]), "parent"), os.NewFile(uintptr(fds[0]), "child"), nil
+}
+
+// CreateContainer creates a container in the OCI runtime
+// TODO terminal support for container
+// Presently just ignoring conmon opts related to it
+func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string) (err error) {
+ if ctr.state.UserNSRoot == "" {
+ // no need of an intermediate mount ns
+ return r.createOCIContainer(ctr, cgroupParent)
+ }
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ runtime.LockOSThread()
+
+ fd, err := os.Open(fmt.Sprintf("/proc/%d/task/%d/ns/mnt", os.Getpid(), unix.Gettid()))
+ if err != nil {
+ return
+ }
+ defer fd.Close()
+
+ // create a new mountns on the current thread
+ if err = unix.Unshare(unix.CLONE_NEWNS); err != nil {
+ return
+ }
+ defer unix.Setns(int(fd.Fd()), unix.CLONE_NEWNS)
+
+ // don't spread our mounts around
+ err = unix.Mount("/", "/", "none", unix.MS_REC|unix.MS_SLAVE, "")
+ if err != nil {
+ return
+ }
+ err = unix.Mount(ctr.state.Mountpoint, ctr.state.RealMountpoint, "none", unix.MS_BIND, "")
+ if err != nil {
+ return
+ }
+ if err := idtools.MkdirAllAs(ctr.state.DestinationRunDir, 0700, ctr.RootUID(), ctr.RootGID()); err != nil {
+ return
+ }
+
+ err = unix.Mount(ctr.state.RunDir, ctr.state.DestinationRunDir, "none", unix.MS_BIND, "")
+ if err != nil {
+ return
+ }
+ err = r.createOCIContainer(ctr, cgroupParent)
+ }()
+ wg.Wait()
+
+ return err
+}
diff --git a/libpod/oci_unsupported.go b/libpod/oci_unsupported.go
index 6e5601eac..409bb117e 100644
--- a/libpod/oci_unsupported.go
+++ b/libpod/oci_unsupported.go
@@ -2,6 +2,19 @@
package libpod
-func moveConmonToCgroup() error {
+import (
+ "os"
+ "os/exec"
+)
+
+func (r *OCIRuntime) moveConmonToCgroup(ctr *Container, cgroupParent string, cmd *exec.Cmd) error {
return ErrOSNotSupported
}
+
+func newPipe() (parent *os.File, child *os.File, err error) {
+ return nil, nil, ErrNotImplemented
+}
+
+func (r *OCIRuntime) createContainer(ctr *Container, cgroupParent string) (err error) {
+ return ErrNotImplemented
+}