summaryrefslogtreecommitdiff
path: root/libpod
diff options
context:
space:
mode:
Diffstat (limited to 'libpod')
-rw-r--r--libpod/container_internal.go22
-rw-r--r--libpod/container_internal_linux.go21
-rw-r--r--libpod/container_internal_unsupported.go4
-rw-r--r--libpod/image/image.go4
-rw-r--r--libpod/image/image_test.go8
-rw-r--r--libpod/info.go10
-rw-r--r--libpod/networking_linux.go68
-rw-r--r--libpod/oci_internal_linux.go15
-rw-r--r--libpod/options.go20
-rw-r--r--libpod/runtime.go7
-rw-r--r--libpod/runtime_pod_infra_linux.go4
11 files changed, 130 insertions, 53 deletions
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 8b96b3f62..a4dcd23be 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -622,7 +622,11 @@ func (c *Container) refresh() error {
return err
}
- return nil
+ if rootless.IsRootless() {
+ return nil
+ }
+
+ return c.refreshCNI()
}
// Remove conmon attach socket and terminal resize FIFO
@@ -646,14 +650,8 @@ func (c *Container) removeConmonFiles() error {
// Remove the exit file so we don't leak memory in tmpfs
exitFile := filepath.Join(c.ociRuntime.exitsDir, c.ID())
- if _, err := os.Stat(exitFile); err != nil {
- if !os.IsNotExist(err) {
- return errors.Wrapf(err, "error running stat on container %s exit file", c.ID())
- }
- } else {
- if err := os.Remove(exitFile); err != nil {
- return errors.Wrapf(err, "error removing container %s exit file", c.ID())
- }
+ if err := os.Remove(exitFile); err != nil && !os.IsNotExist(err) {
+ return errors.Wrapf(err, "error removing container %s exit file", c.ID())
}
return nil
@@ -922,6 +920,12 @@ func (c *Container) init(ctx context.Context, retainRetries bool) error {
span.SetTag("struct", "container")
defer span.Finish()
+ // Unconditionally remove conmon temporary files.
+ // We've been running into far too many issues where they block startup.
+ if err := c.removeConmonFiles(); err != nil {
+ return err
+ }
+
// Generate the OCI newSpec
newSpec, err := c.generateSpec(ctx)
if err != nil {
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 230b5b888..2636fdb6c 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -78,15 +78,21 @@ func (c *Container) prepare() (Err error) {
// Set up network namespace if not already set up
if c.config.CreateNetNS && c.state.NetNS == nil && !c.config.PostConfigureNetNS {
netNS, networkStatus, createNetNSErr = c.runtime.createNetNS(c)
+ if createNetNSErr != nil {
+ return
+ }
tmpStateLock.Lock()
defer tmpStateLock.Unlock()
// Assign NetNS attributes to container
- if createNetNSErr == nil {
- c.state.NetNS = netNS
- c.state.NetworkStatus = networkStatus
- }
+ c.state.NetNS = netNS
+ c.state.NetworkStatus = networkStatus
+ }
+
+ // handle rootless network namespace setup
+ if c.state.NetNS != nil && c.config.NetMode == "slirp4netns" && !c.config.PostConfigureNetNS {
+ createNetNSErr = c.runtime.setupRootlessNetNS(c)
}
}()
// Mount storage if not mounted
@@ -1319,3 +1325,10 @@ func (c *Container) copyOwnerAndPerms(source, dest string) error {
}
return nil
}
+
+// Teardown CNI config on refresh
+func (c *Container) refreshCNI() error {
+ // Let's try and delete any lingering network config...
+ podNetwork := c.runtime.getPodNetwork(c.ID(), c.config.Name, "", c.config.Networks, c.config.PortMappings, c.config.StaticIP)
+ return c.runtime.netPlugin.TearDownPod(podNetwork)
+}
diff --git a/libpod/container_internal_unsupported.go b/libpod/container_internal_unsupported.go
index 6fa19a778..05a587c59 100644
--- a/libpod/container_internal_unsupported.go
+++ b/libpod/container_internal_unsupported.go
@@ -40,3 +40,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
func (c *Container) copyOwnerAndPerms(source, dest string) error {
return nil
}
+
+func (c *Container) refreshCNI() error {
+ return define.ErrNotImplemented
+}
diff --git a/libpod/image/image.go b/libpod/image/image.go
index 0be6eeeb9..855da8611 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -29,7 +29,6 @@ import (
"github.com/containers/libpod/pkg/registries"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
- "github.com/containers/storage/pkg/reexec"
"github.com/opencontainers/go-digest"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -85,9 +84,6 @@ func NewImageRuntimeFromStore(store storage.Store) *Runtime {
// NewImageRuntimeFromOptions creates an Image Runtime including the store given
// store options
func NewImageRuntimeFromOptions(options storage.StoreOptions) (*Runtime, error) {
- if reexec.Init() {
- return nil, errors.Errorf("unable to reexec")
- }
store, err := setStore(options)
if err != nil {
return nil, err
diff --git a/libpod/image/image_test.go b/libpod/image/image_test.go
index 5a6d095f6..ef39d09c3 100644
--- a/libpod/image/image_test.go
+++ b/libpod/image/image_test.go
@@ -11,6 +11,7 @@ import (
"github.com/containers/libpod/libpod/events"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
+ "github.com/containers/storage/pkg/reexec"
"github.com/opencontainers/go-digest"
"github.com/stretchr/testify/assert"
)
@@ -70,6 +71,13 @@ func makeLocalMatrix(b, bg *Image) ([]localImageTest, error) {
}
+func TestMain(m *testing.M) {
+ if reexec.Init() {
+ return
+ }
+ os.Exit(m.Run())
+}
+
// TestImage_NewFromLocal tests finding the image locally by various names,
// tags, and aliases
func TestImage_NewFromLocal(t *testing.T) {
diff --git a/libpod/info.go b/libpod/info.go
index e5132b5f6..297086ebb 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -13,6 +13,7 @@ import (
"time"
"github.com/containers/buildah"
+ "github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/utils"
"github.com/containers/storage"
@@ -29,6 +30,15 @@ func (r *Runtime) hostInfo() (map[string]interface{}, error) {
info["arch"] = runtime.GOARCH
info["cpus"] = runtime.NumCPU()
info["rootless"] = rootless.IsRootless()
+ unified, err := cgroups.IsCgroup2UnifiedMode()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error reading cgroups mode")
+ }
+ cgroupVersion := "v1"
+ if unified {
+ cgroupVersion = "v2"
+ }
+ info["CgroupVersion"] = cgroupVersion
mi, err := system.ReadMemInfo()
if err != nil {
return nil, errors.Wrapf(err, "error reading memory info")
diff --git a/libpod/networking_linux.go b/libpod/networking_linux.go
index 67dd0150b..61ab57d65 100644
--- a/libpod/networking_linux.go
+++ b/libpod/networking_linux.go
@@ -90,9 +90,6 @@ func (r *Runtime) configureNetNS(ctr *Container, ctrNS ns.NetNS) ([]*cnitypes.Re
// Create and configure a new network namespace for a container
func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result, err error) {
- if rootless.IsRootless() {
- return nil, nil, errors.New("cannot configure a new network namespace in rootless mode, only --network=slirp4netns is supported")
- }
ctrNS, err := netns.NewNS()
if err != nil {
return nil, nil, errors.Wrapf(err, "error creating network namespace for container %s", ctr.ID())
@@ -110,7 +107,10 @@ func (r *Runtime) createNetNS(ctr *Container) (n ns.NetNS, q []*cnitypes.Result,
logrus.Debugf("Made network namespace at %s for container %s", ctrNS.Path(), ctr.ID())
- networkStatus, err := r.configureNetNS(ctr, ctrNS)
+ networkStatus := []*cnitypes.Result{}
+ if !rootless.IsRootless() {
+ networkStatus, err = r.configureNetNS(ctr, ctrNS)
+ }
return ctrNS, networkStatus, err
}
@@ -138,9 +138,6 @@ func checkSlirpFlags(path string) (bool, bool, bool, error) {
// Configure the network namespace for a rootless container
func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
- defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
- defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
-
path := r.config.NetworkCmdPath
if path == "" {
@@ -164,7 +161,7 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
cmdArgs := []string{}
if havePortMapping {
- cmdArgs = append(cmdArgs, "--api-socket", apiSocket, fmt.Sprintf("%d", ctr.state.PID))
+ cmdArgs = append(cmdArgs, "--api-socket", apiSocket)
}
dhp, mtu, sandbox, err := checkSlirpFlags(path)
if err != nil {
@@ -179,13 +176,38 @@ func (r *Runtime) setupRootlessNetNS(ctr *Container) (err error) {
if sandbox {
cmdArgs = append(cmdArgs, "--enable-sandbox")
}
- cmdArgs = append(cmdArgs, "-c", "-e", "3", "-r", "4", fmt.Sprintf("%d", ctr.state.PID), "tap0")
- cmd := exec.Command(path, cmdArgs...)
+ // the slirp4netns arguments being passed are describes as follows:
+ // from the slirp4netns documentation: https://github.com/rootless-containers/slirp4netns
+ // -c, --configure Brings up the tap interface
+ // -e, --exit-fd=FD specify the FD for terminating slirp4netns
+ // -r, --ready-fd=FD specify the FD to write to when the initialization steps are finished
+ cmdArgs = append(cmdArgs, "-c", "-e", "3", "-r", "4")
+ if !ctr.config.PostConfigureNetNS {
+ ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
+ if err != nil {
+ return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ }
+ cmdArgs = append(cmdArgs, "--netns-type=path", ctr.state.NetNS.Path(), "tap0")
+ } else {
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
+ cmdArgs = append(cmdArgs, fmt.Sprintf("%d", ctr.state.PID), "tap0")
+ }
+ cmd := exec.Command(path, cmdArgs...)
+ logrus.Debugf("slirp4netns command: %s", strings.Join(cmd.Args, " "))
cmd.SysProcAttr = &syscall.SysProcAttr{
Setpgid: true,
}
+
+ // workaround for https://github.com/rootless-containers/slirp4netns/pull/153
+ if sandbox {
+ cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWNS
+ cmd.SysProcAttr.Unshareflags = syscall.CLONE_NEWNS
+ }
+
+ // Leak one end of the pipe in slirp4netns, the other will be sent to conmon
cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncR, syncW)
if err := cmd.Start(); err != nil {
@@ -388,20 +410,22 @@ func (r *Runtime) teardownNetNS(ctr *Container) error {
logrus.Debugf("Tearing down network namespace at %s for container %s", ctr.state.NetNS.Path(), ctr.ID())
- var requestedIP net.IP
- if ctr.requestedIP != nil {
- requestedIP = ctr.requestedIP
- // cancel request for a specific IP in case the container is reused later
- ctr.requestedIP = nil
- } else {
- requestedIP = ctr.config.StaticIP
- }
+ // rootless containers do not use the CNI plugin
+ if !rootless.IsRootless() {
+ var requestedIP net.IP
+ if ctr.requestedIP != nil {
+ requestedIP = ctr.requestedIP
+ // cancel request for a specific IP in case the container is reused later
+ ctr.requestedIP = nil
+ } else {
+ requestedIP = ctr.config.StaticIP
+ }
- podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
+ podNetwork := r.getPodNetwork(ctr.ID(), ctr.Name(), ctr.state.NetNS.Path(), ctr.config.Networks, ctr.config.PortMappings, requestedIP)
- // The network may have already been torn down, so don't fail here, just log
- if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
- return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
+ if err := r.netPlugin.TearDownPod(podNetwork); err != nil {
+ return errors.Wrapf(err, "error tearing down CNI namespace configuration for container %s", ctr.ID())
+ }
}
// First unmount the namespace
diff --git a/libpod/oci_internal_linux.go b/libpod/oci_internal_linux.go
index a90af32ed..437b7cf4d 100644
--- a/libpod/oci_internal_linux.go
+++ b/libpod/oci_internal_linux.go
@@ -131,9 +131,18 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Containe
}
if ctr.config.NetMode.IsSlirp4netns() {
- ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
- if err != nil {
- return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ if ctr.config.PostConfigureNetNS {
+ ctr.rootlessSlirpSyncR, ctr.rootlessSlirpSyncW, err = os.Pipe()
+ if err != nil {
+ return errors.Wrapf(err, "failed to create rootless network sync pipe")
+ }
+ } else {
+ if ctr.rootlessSlirpSyncR != nil {
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncR)
+ }
+ if ctr.rootlessSlirpSyncW != nil {
+ defer errorhandling.CloseQuiet(ctr.rootlessSlirpSyncW)
+ }
}
// Leak one end in conmon, the other one will be leaked into slirp4netns
cmd.ExtraFiles = append(cmd.ExtraFiles, ctr.rootlessSlirpSyncW)
diff --git a/libpod/options.go b/libpod/options.go
index d28cb3d8c..22ab22a95 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -20,8 +20,8 @@ import (
)
var (
- nameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
- regexError = errors.Wrapf(define.ErrInvalidArg, "names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*")
+ NameRegex = regexp.MustCompile("^[a-zA-Z0-9][a-zA-Z0-9_.-]*$")
+ RegexError = errors.Wrapf(define.ErrInvalidArg, "names must match [a-zA-Z0-9][a-zA-Z0-9_.-]*")
)
// Runtime Creation Options
@@ -648,8 +648,8 @@ func WithName(name string) CtrCreateOption {
}
// Check the name against a regex
- if !nameRegex.MatchString(name) {
- return regexError
+ if !NameRegex.MatchString(name) {
+ return RegexError
}
ctr.config.Name = name
@@ -1426,8 +1426,8 @@ func WithVolumeName(name string) VolumeCreateOption {
}
// Check the name against a regex
- if !nameRegex.MatchString(name) {
- return regexError
+ if !NameRegex.MatchString(name) {
+ return RegexError
}
volume.config.Name = name
@@ -1532,8 +1532,8 @@ func WithPodName(name string) PodCreateOption {
}
// Check the name against a regex
- if !nameRegex.MatchString(name) {
- return regexError
+ if !NameRegex.MatchString(name) {
+ return RegexError
}
pod.config.Name = name
@@ -1550,8 +1550,8 @@ func WithPodHostname(hostname string) PodCreateOption {
}
// Check the hostname against a regex
- if !nameRegex.MatchString(hostname) {
- return regexError
+ if !NameRegex.MatchString(hostname) {
+ return RegexError
}
pod.config.Hostname = hostname
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 675c92b7a..9f3549e00 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -387,6 +387,13 @@ func SetXdgDirs() error {
return errors.Wrapf(err, "cannot set XDG_RUNTIME_DIR")
}
+ if rootless.IsRootless() && os.Getenv("DBUS_SESSION_BUS_ADDRESS") == "" {
+ sessionAddr := filepath.Join(runtimeDir, "bus")
+ if _, err := os.Stat(sessionAddr); err == nil {
+ os.Setenv("DBUS_SESSION_BUS_ADDRESS", fmt.Sprintf("unix:path=%s", sessionAddr))
+ }
+ }
+
// Setup XDG_CONFIG_HOME
if cfgHomeDir := os.Getenv("XDG_CONFIG_HOME"); cfgHomeDir == "" {
if cfgHomeDir, err = util.GetRootlessConfigHomeDir(); err != nil {
diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go
index ad6662f03..6a27c2800 100644
--- a/libpod/runtime_pod_infra_linux.go
+++ b/libpod/runtime_pod_infra_linux.go
@@ -99,7 +99,9 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID
if isRootless {
netmode = "slirp4netns"
}
- options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, isRootless, netmode, networks))
+ // PostConfigureNetNS should not be set since user namespace sharing is not implemented
+ // and rootless networking no longer supports post configuration setup
+ options = append(options, WithNetNS(p.config.InfraContainer.PortBindings, false, netmode, networks))
return r.newContainer(ctx, g.Config, options...)
}