diff options
Diffstat (limited to 'libpod')
-rw-r--r-- | libpod/container_internal.go | 22 | ||||
-rw-r--r-- | libpod/container_internal_linux.go | 21 | ||||
-rw-r--r-- | libpod/container_internal_unsupported.go | 4 | ||||
-rw-r--r-- | libpod/image/image.go | 4 | ||||
-rw-r--r-- | libpod/image/image_test.go | 8 | ||||
-rw-r--r-- | libpod/info.go | 10 | ||||
-rw-r--r-- | libpod/networking_linux.go | 68 | ||||
-rw-r--r-- | libpod/oci_internal_linux.go | 15 | ||||
-rw-r--r-- | libpod/options.go | 20 | ||||
-rw-r--r-- | libpod/runtime.go | 7 | ||||
-rw-r--r-- | libpod/runtime_pod_infra_linux.go | 4 |
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...) } |