summaryrefslogtreecommitdiff
path: root/libpod/container_internal_linux.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/container_internal_linux.go')
-rw-r--r--libpod/container_internal_linux.go513
1 files changed, 228 insertions, 285 deletions
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index d7683cce9..390e95258 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -5,11 +5,11 @@ package libpod
import (
"context"
+ "errors"
"fmt"
"io"
"io/ioutil"
"math"
- "net"
"os"
"os/user"
"path"
@@ -29,6 +29,7 @@ import (
"github.com/containers/buildah/pkg/overlay"
butil "github.com/containers/buildah/util"
"github.com/containers/common/libnetwork/etchosts"
+ "github.com/containers/common/libnetwork/resolvconf"
"github.com/containers/common/libnetwork/types"
"github.com/containers/common/pkg/apparmor"
"github.com/containers/common/pkg/cgroups"
@@ -36,6 +37,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/subscriptions"
"github.com/containers/common/pkg/umask"
+ cutil "github.com/containers/common/pkg/util"
is "github.com/containers/image/v5/storage"
"github.com/containers/podman/v4/libpod/define"
"github.com/containers/podman/v4/libpod/events"
@@ -43,7 +45,6 @@ import (
"github.com/containers/podman/v4/pkg/checkpoint/crutils"
"github.com/containers/podman/v4/pkg/criu"
"github.com/containers/podman/v4/pkg/lookup"
- "github.com/containers/podman/v4/pkg/resolvconf"
"github.com/containers/podman/v4/pkg/rootless"
"github.com/containers/podman/v4/pkg/util"
"github.com/containers/podman/v4/utils"
@@ -57,7 +58,6 @@ import (
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux"
"github.com/opencontainers/selinux/go-selinux/label"
- "github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
)
@@ -65,7 +65,7 @@ import (
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 fmt.Errorf("failed to mount shm tmpfs %q: %w", c.config.ShmDir, err)
}
return nil
}
@@ -73,7 +73,7 @@ func (c *Container) mountSHM(shmOptions string) error {
func (c *Container) unmountSHM(mount string) error {
if err := unix.Unmount(mount, 0); err != nil {
if err != syscall.EINVAL && err != syscall.ENOENT {
- return errors.Wrapf(err, "error unmounting container %s SHM mount %s", c.ID(), mount)
+ return fmt.Errorf("error unmounting container %s SHM mount %s: %w", c.ID(), mount, err)
}
// If it's just an EINVAL or ENOENT, debug logs only
logrus.Debugf("Container %s failed to unmount %s : %v", c.ID(), mount, err)
@@ -152,7 +152,7 @@ func (c *Container) prepare() error {
// createErr is guaranteed non-nil, so print
// unconditionally
logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
- createErr = errors.Wrapf(err, "error unmounting storage for container %s after network create failure", c.ID())
+ createErr = fmt.Errorf("error unmounting storage for container %s after network create failure: %w", c.ID(), err)
}
}
@@ -161,7 +161,7 @@ func (c *Container) prepare() error {
if createErr != nil {
if err := c.cleanupNetwork(); err != nil {
logrus.Errorf("Preparing container %s: %v", c.ID(), createErr)
- createErr = errors.Wrapf(err, "error cleaning up container %s network after setup failure", c.ID())
+ createErr = fmt.Errorf("error cleaning up container %s network after setup failure: %w", c.ID(), err)
}
}
@@ -251,7 +251,7 @@ func (c *Container) resolveWorkDir() error {
st, err := os.Stat(resolvedWorkdir)
if err == nil {
if !st.IsDir() {
- return errors.Errorf("workdir %q exists on container %s, but is not a directory", workdir, c.ID())
+ return fmt.Errorf("workdir %q exists on container %s, but is not a directory", workdir, c.ID())
}
return nil
}
@@ -265,11 +265,11 @@ func (c *Container) resolveWorkDir() error {
if c.isWorkDirSymlink(resolvedWorkdir) {
return nil
}
- return errors.Errorf("workdir %q does not exist on container %s", workdir, c.ID())
+ return fmt.Errorf("workdir %q does not exist on container %s", workdir, c.ID())
}
// This might be a serious error (e.g., permission), so
// we need to return the full error.
- return errors.Wrapf(err, "error detecting workdir %q on container %s", workdir, c.ID())
+ return fmt.Errorf("error detecting workdir %q on container %s: %w", workdir, c.ID(), err)
}
return nil
}
@@ -277,16 +277,16 @@ func (c *Container) resolveWorkDir() error {
if os.IsExist(err) {
return nil
}
- return errors.Wrapf(err, "error creating container %s workdir", c.ID())
+ return fmt.Errorf("error creating container %s workdir: %w", c.ID(), err)
}
// Ensure container entrypoint is created (if required).
uid, gid, _, err := chrootuser.GetUser(c.state.Mountpoint, c.User())
if err != nil {
- return errors.Wrapf(err, "error looking up %s inside of the container %s", c.User(), c.ID())
+ return fmt.Errorf("error looking up %s inside of the container %s: %w", c.User(), c.ID(), err)
}
if err := os.Chown(resolvedWorkdir, int(uid), int(gid)); err != nil {
- return errors.Wrapf(err, "error chowning container %s workdir to container root", c.ID())
+ return fmt.Errorf("error chowning container %s workdir to container root: %w", c.ID(), err)
}
return nil
@@ -311,7 +311,7 @@ func (c *Container) cleanupNetwork() error {
// 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)
+ logrus.Errorf("Unable to clean up network for container %s: %q", c.ID(), err)
}
c.state.NetNS = nil
@@ -367,7 +367,7 @@ func (c *Container) getUserOverrides() *lookup.Overrides {
func lookupHostUser(name string) (*runcuser.ExecUser, error) {
var execUser runcuser.ExecUser
- // Lookup User on host
+ // Look up User on host
u, err := util.LookupUser(name)
if err != nil {
return &execUser, err
@@ -387,13 +387,44 @@ func lookupHostUser(name string) (*runcuser.ExecUser, error) {
return &execUser, nil
}
+// Internal only function which returns upper and work dir from
+// overlay options.
+func getOverlayUpperAndWorkDir(options []string) (string, string, error) {
+ upperDir := ""
+ workDir := ""
+ for _, o := range options {
+ if strings.HasPrefix(o, "upperdir") {
+ splitOpt := strings.SplitN(o, "=", 2)
+ if len(splitOpt) > 1 {
+ upperDir = splitOpt[1]
+ if upperDir == "" {
+ return "", "", errors.New("cannot accept empty value for upperdir")
+ }
+ }
+ }
+ if strings.HasPrefix(o, "workdir") {
+ splitOpt := strings.SplitN(o, "=", 2)
+ if len(splitOpt) > 1 {
+ workDir = splitOpt[1]
+ if workDir == "" {
+ return "", "", errors.New("cannot accept empty value for workdir")
+ }
+ }
+ }
+ }
+ if (upperDir != "" && workDir == "") || (upperDir == "" && workDir != "") {
+ return "", "", errors.New("must specify both upperdir and workdir")
+ }
+ return upperDir, workDir, nil
+}
+
// Generate spec for a container
// Accepts a map of the container's dependencies
func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
overrides := c.getUserOverrides()
execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, c.config.User, overrides)
if err != nil {
- if util.StringInSlice(c.config.User, c.config.HostUsers) {
+ if cutil.StringInSlice(c.config.User, c.config.HostUsers) {
execUser, err = lookupHostUser(c.config.User)
}
if err != nil {
@@ -406,6 +437,14 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
//nolint:staticcheck
g := generate.NewFromSpec(c.config.Spec)
+ // If the flag to mount all devices is set for a privileged container, add
+ // all the devices from the host's machine into the container
+ if c.config.MountAllDevices {
+ if err := util.AddPrivilegedDevices(&g); err != nil {
+ return nil, err
+ }
+ }
+
// If network namespace was requested, add it now
if c.config.CreateNetNS {
if c.config.PostConfigureNetNS {
@@ -446,7 +485,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
for _, namedVol := range c.config.NamedVolumes {
volume, err := c.runtime.GetVolume(namedVol.Name)
if err != nil {
- return nil, errors.Wrapf(err, "error retrieving volume %s to add to container %s", namedVol.Name, c.ID())
+ return nil, fmt.Errorf("error retrieving volume %s to add to container %s: %w", namedVol.Name, c.ID(), err)
}
mountPoint, err := volume.MountPoint()
if err != nil {
@@ -459,23 +498,9 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
for _, o := range namedVol.Options {
if o == "O" {
overlayFlag = true
- }
- if overlayFlag && strings.Contains(o, "upperdir") {
- splitOpt := strings.SplitN(o, "=", 2)
- if len(splitOpt) > 1 {
- upperDir = splitOpt[1]
- if upperDir == "" {
- return nil, errors.New("cannot accept empty value for upperdir")
- }
- }
- }
- if overlayFlag && strings.Contains(o, "workdir") {
- splitOpt := strings.SplitN(o, "=", 2)
- if len(splitOpt) > 1 {
- workDir = splitOpt[1]
- if workDir == "" {
- return nil, errors.New("cannot accept empty value for workdir")
- }
+ upperDir, workDir, err = getOverlayUpperAndWorkDir(namedVol.Options)
+ if err != nil {
+ return nil, err
}
}
}
@@ -488,10 +513,6 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
return nil, err
}
- if (upperDir != "" && workDir == "") || (upperDir == "" && workDir != "") {
- return nil, errors.Wrapf(err, "must specify both upperdir and workdir")
- }
-
overlayOpts = &overlay.Options{RootUID: c.RootUID(),
RootGID: c.RootGID(),
UpperDirOptionFragment: upperDir,
@@ -501,7 +522,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
overlayMount, err = overlay.MountWithOptions(contentDir, mountPoint, namedVol.Dest, overlayOpts)
if err != nil {
- return nil, errors.Wrapf(err, "mounting overlay failed %q", mountPoint)
+ return nil, fmt.Errorf("mounting overlay failed %q: %w", mountPoint, err)
}
for _, o := range namedVol.Options {
@@ -584,13 +605,24 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// Add overlay volumes
for _, overlayVol := range c.config.OverlayVolumes {
+ upperDir, workDir, err := getOverlayUpperAndWorkDir(overlayVol.Options)
+ if err != nil {
+ return nil, err
+ }
contentDir, err := overlay.TempDir(c.config.StaticDir, c.RootUID(), c.RootGID())
if err != nil {
return nil, err
}
- overlayMount, err := overlay.Mount(contentDir, overlayVol.Source, overlayVol.Dest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions())
+ overlayOpts := &overlay.Options{RootUID: c.RootUID(),
+ RootGID: c.RootGID(),
+ UpperDirOptionFragment: upperDir,
+ WorkDirOptionFragment: workDir,
+ GraphOpts: c.runtime.store.GraphOptions(),
+ }
+
+ overlayMount, err := overlay.MountWithOptions(contentDir, overlayVol.Source, overlayVol.Dest, overlayOpts)
if err != nil {
- return nil, errors.Wrapf(err, "mounting overlay failed %q", overlayVol.Source)
+ return nil, fmt.Errorf("mounting overlay failed %q: %w", overlayVol.Source, err)
}
// Check overlay volume options
@@ -614,16 +646,16 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// Mount the specified image.
img, _, err := c.runtime.LibimageRuntime().LookupImage(volume.Source, nil)
if err != nil {
- return nil, errors.Wrapf(err, "error creating image volume %q:%q", volume.Source, volume.Dest)
+ return nil, fmt.Errorf("error creating image volume %q:%q: %w", volume.Source, volume.Dest, err)
}
mountPoint, err := img.Mount(ctx, nil, "")
if err != nil {
- return nil, errors.Wrapf(err, "error mounting image volume %q:%q", volume.Source, volume.Dest)
+ return nil, fmt.Errorf("error mounting image volume %q:%q: %w", volume.Source, volume.Dest, err)
}
contentDir, err := overlay.TempDir(c.config.StaticDir, c.RootUID(), c.RootGID())
if err != nil {
- return nil, errors.Wrapf(err, "failed to create TempDir in the %s directory", c.config.StaticDir)
+ return nil, fmt.Errorf("failed to create TempDir in the %s directory: %w", c.config.StaticDir, err)
}
var overlayMount spec.Mount
@@ -633,7 +665,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
overlayMount, err = overlay.MountReadOnly(contentDir, mountPoint, volume.Dest, c.RootUID(), c.RootGID(), c.runtime.store.GraphOptions())
}
if err != nil {
- return nil, errors.Wrapf(err, "creating overlay mount for image %q failed", volume.Source)
+ return nil, fmt.Errorf("creating overlay mount for image %q failed: %w", volume.Source, err)
}
g.AddMount(overlayMount)
}
@@ -658,7 +690,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if c.config.Umask != "" {
decVal, err := strconv.ParseUint(c.config.Umask, 8, 32)
if err != nil {
- return nil, errors.Wrapf(err, "Invalid Umask Value")
+ return nil, fmt.Errorf("invalid Umask Value: %w", err)
}
umask := uint32(decVal)
g.Config.Process.User.Umask = &umask
@@ -668,7 +700,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if len(c.config.Groups) > 0 {
gids, err := lookup.GetContainerGroups(c.config.Groups, c.state.Mountpoint, overrides)
if err != nil {
- return nil, errors.Wrapf(err, "error looking up supplemental groups for container %s", c.ID())
+ return nil, fmt.Errorf("error looking up supplemental groups for container %s: %w", c.ID(), err)
}
for _, gid := range gids {
g.AddProcessAdditionalGid(gid)
@@ -677,7 +709,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if c.Systemd() {
if err := c.setupSystemd(g.Mounts(), g); err != nil {
- return nil, errors.Wrapf(err, "error adding systemd-specific mounts")
+ return nil, fmt.Errorf("error adding systemd-specific mounts: %w", err)
}
}
@@ -693,7 +725,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// Check whether the current user namespace has enough gids available.
availableGids, err := rootless.GetAvailableGids()
if err != nil {
- return nil, errors.Wrapf(err, "cannot read number of available GIDs")
+ return nil, fmt.Errorf("cannot read number of available GIDs: %w", err)
}
gidMappings = []idtools.IDMap{{
ContainerID: 0,
@@ -838,6 +870,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if err != nil {
return nil, err
}
+
g.SetLinuxCgroupsPath(cgroupPath)
// Warning: CDI may alter g.Config in place.
@@ -848,7 +881,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
}
_, err := registry.InjectDevices(g.Config, c.config.CDIDevices...)
if err != nil {
- return nil, errors.Wrapf(err, "error setting up CDI devices")
+ return nil, fmt.Errorf("error setting up CDI devices: %w", err)
}
}
@@ -872,7 +905,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
if m.Type == "tmpfs" {
finalPath, err := securejoin.SecureJoin(c.state.Mountpoint, m.Destination)
if err != nil {
- return nil, errors.Wrapf(err, "error resolving symlinks for mount destination %s", m.Destination)
+ return nil, fmt.Errorf("error resolving symlinks for mount destination %s: %w", m.Destination, err)
}
trimmedPath := strings.TrimPrefix(finalPath, strings.TrimSuffix(c.state.Mountpoint, "/"))
m.Destination = trimmedPath
@@ -901,7 +934,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
// Warning: precreate hooks may alter g.Config in place.
if c.state.ExtensionStageHooks, err = c.setupOCIHooks(ctx, g.Config); err != nil {
- return nil, errors.Wrapf(err, "error setting up OCI Hooks")
+ return nil, fmt.Errorf("error setting up OCI Hooks: %w", err)
}
if len(c.config.EnvSecrets) > 0 {
manager, err := c.runtime.SecretsManager()
@@ -953,11 +986,11 @@ func (c *Container) mountNotifySocket(g generate.Generator) error {
logrus.Debugf("Checking notify %q dir", notifyDir)
if err := os.MkdirAll(notifyDir, 0755); err != nil {
if !os.IsExist(err) {
- return errors.Wrapf(err, "unable to create notify %q dir", notifyDir)
+ return fmt.Errorf("unable to create notify %q dir: %w", notifyDir, err)
}
}
if err := label.Relabel(notifyDir, c.MountLabel(), true); err != nil {
- return errors.Wrapf(err, "relabel failed %q", notifyDir)
+ return fmt.Errorf("relabel failed %q: %w", notifyDir, err)
}
logrus.Debugf("Add bindmount notify %q dir", notifyDir)
if _, ok := c.state.BindMounts["/run/notify"]; !ok {
@@ -1080,7 +1113,7 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro
func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr string, specNS spec.LinuxNamespaceType) 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())
+ return fmt.Errorf("error retrieving dependency %s of container %s from state: %w", ctr, c.ID(), err)
}
if specNS == spec.UTSNamespace {
@@ -1090,7 +1123,6 @@ func (c *Container) addNamespaceContainer(g *generate.Generator, ns LinuxNS, ctr
g.AddProcessEnv("HOSTNAME", hostname)
}
- // TODO need unlocked version of this for use in pods
nsPath, err := nsCtr.NamespacePath(ns)
if err != nil {
return err
@@ -1110,7 +1142,7 @@ func (c *Container) addCheckpointImageMetadata(importBuilder *buildah.Builder) e
return fmt.Errorf("getting host info: %v", err)
}
- criuVersion, err := criu.GetCriuVestion()
+ criuVersion, err := criu.GetCriuVersion()
if err != nil {
return fmt.Errorf("getting criu version: %v", err)
}
@@ -1168,7 +1200,7 @@ func (c *Container) createCheckpointImage(ctx context.Context, options Container
// Create storage reference
imageRef, err := is.Transport.ParseStoreReference(c.runtime.store, options.CreateImage)
if err != nil {
- return errors.Errorf("Failed to parse image name")
+ return errors.New("failed to parse image name")
}
// Build an image scratch
@@ -1179,7 +1211,7 @@ func (c *Container) createCheckpointImage(ctx context.Context, options Container
if err != nil {
return err
}
- // Clean-up buildah working container
+ // Clean up buildah working container
defer func() {
if err := importBuilder.Delete(); err != nil {
logrus.Errorf("Image builder delete failed: %v", err)
@@ -1232,23 +1264,23 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
// Check if the dependency is an infra container. If it is we can checkpoint
// the container out of the Pod.
if c.config.Pod == "" {
- return errors.Errorf("cannot export checkpoints of containers with dependencies")
+ return errors.New("cannot export checkpoints of containers with dependencies")
}
pod, err := c.runtime.state.Pod(c.config.Pod)
if err != nil {
- return errors.Wrapf(err, "container %s is in pod %s, but pod cannot be retrieved", c.ID(), c.config.Pod)
+ return fmt.Errorf("container %s is in pod %s, but pod cannot be retrieved: %w", c.ID(), c.config.Pod, err)
}
infraID, err := pod.InfraContainerID()
if err != nil {
- return errors.Wrapf(err, "cannot retrieve infra container ID for pod %s", c.config.Pod)
+ return fmt.Errorf("cannot retrieve infra container ID for pod %s: %w", c.config.Pod, err)
}
if c.Dependencies()[0] != infraID {
- return errors.Errorf("cannot export checkpoints of containers with dependencies")
+ return errors.New("cannot export checkpoints of containers with dependencies")
}
}
if len(c.Dependencies()) > 1 {
- return errors.Errorf("cannot export checkpoints of containers with dependencies")
+ return errors.New("cannot export checkpoints of containers with dependencies")
}
logrus.Debugf("Exporting checkpoint image of container %q to %q", c.ID(), options.TargetFile)
@@ -1276,7 +1308,7 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
// To correctly track deleted files, let's go through the output of 'podman diff'
rootFsChanges, err := c.runtime.GetDiff("", c.ID(), define.DiffContainer)
if err != nil {
- return errors.Wrapf(err, "error exporting root file-system diff for %q", c.ID())
+ return fmt.Errorf("error exporting root file-system diff for %q: %w", c.ID(), err)
}
addToTarFiles, err := crutils.CRCreateRootFsDiffTar(&rootFsChanges, c.state.Mountpoint, c.bundlePath())
@@ -1293,7 +1325,7 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
// Create an archive for each volume associated with the container
if !options.IgnoreVolumes {
if err := os.MkdirAll(expVolDir, 0700); err != nil {
- return errors.Wrapf(err, "error creating volumes export directory %q", expVolDir)
+ return fmt.Errorf("error creating volumes export directory %q: %w", expVolDir, err)
}
for _, v := range c.config.NamedVolumes {
@@ -1302,7 +1334,7 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
volumeTarFile, err := os.Create(volumeTarFileFullPath)
if err != nil {
- return errors.Wrapf(err, "error creating %q", volumeTarFileFullPath)
+ return fmt.Errorf("error creating %q: %w", volumeTarFileFullPath, err)
}
volume, err := c.runtime.GetVolume(v.Name)
@@ -1315,7 +1347,7 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
return err
}
if mp == "" {
- return errors.Wrapf(define.ErrInternal, "volume %s is not mounted, cannot export", volume.Name())
+ return fmt.Errorf("volume %s is not mounted, cannot export: %w", volume.Name(), define.ErrInternal)
}
input, err := archive.TarWithOptions(mp, &archive.TarOptions{
@@ -1323,7 +1355,7 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
IncludeSourceDir: true,
})
if err != nil {
- return errors.Wrapf(err, "error reading volume directory %q", v.Dest)
+ return fmt.Errorf("error reading volume directory %q: %w", v.Dest, err)
}
_, err = io.Copy(volumeTarFile, input)
@@ -1343,12 +1375,12 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
})
if err != nil {
- return errors.Wrapf(err, "error reading checkpoint directory %q", c.ID())
+ return fmt.Errorf("error reading checkpoint directory %q: %w", c.ID(), err)
}
outFile, err := os.Create(options.TargetFile)
if err != nil {
- return errors.Wrapf(err, "error creating checkpoint export file %q", options.TargetFile)
+ return fmt.Errorf("error creating checkpoint export file %q: %w", options.TargetFile, err)
}
defer outFile.Close()
@@ -1374,10 +1406,10 @@ func (c *Container) exportCheckpoint(options ContainerCheckpointOptions) error {
func (c *Container) checkpointRestoreSupported(version int) error {
if !criu.CheckForCriu(version) {
- return errors.Errorf("checkpoint/restore requires at least CRIU %d", version)
+ return fmt.Errorf("checkpoint/restore requires at least CRIU %d", version)
}
if !c.ociRuntime.SupportsCheckpoint() {
- return errors.Errorf("configured runtime does not support checkpoint/restore")
+ return errors.New("configured runtime does not support checkpoint/restore")
}
return nil
}
@@ -1388,11 +1420,11 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
}
if c.state.State != define.ContainerStateRunning {
- return nil, 0, errors.Wrapf(define.ErrCtrStateInvalid, "%q is not running, cannot checkpoint", c.state.State)
+ return nil, 0, fmt.Errorf("%q is not running, cannot checkpoint: %w", c.state.State, define.ErrCtrStateInvalid)
}
if c.AutoRemove() && options.TargetFile == "" {
- return nil, 0, errors.Errorf("cannot checkpoint containers that have been started with '--rm' unless '--export' is used")
+ return nil, 0, errors.New("cannot checkpoint containers that have been started with '--rm' unless '--export' is used")
}
if err := c.resolveCheckpointImageName(&options); err != nil {
@@ -1473,7 +1505,7 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
c.state.Restored = false
c.state.RestoredTime = time.Time{}
- // Cleanup Storage and Network
+ // Clean up Storage and Network
if err := c.cleanup(ctx); err != nil {
return nil, 0, err
}
@@ -1485,12 +1517,12 @@ func (c *Container) checkpoint(ctx context.Context, options ContainerCheckpointO
}
statsDirectory, err := os.Open(c.bundlePath())
if err != nil {
- return nil, errors.Wrapf(err, "Not able to open %q", c.bundlePath())
+ return nil, fmt.Errorf("not able to open %q: %w", c.bundlePath(), err)
}
dumpStatistics, err := stats.CriuGetDumpStats(statsDirectory)
if err != nil {
- return nil, errors.Wrap(err, "Displaying checkpointing statistics not possible")
+ return nil, fmt.Errorf("displaying checkpointing statistics not possible: %w", err)
}
return &define.CRIUCheckpointRestoreStatistics{
@@ -1536,7 +1568,7 @@ func (c *Container) generateContainerSpec() error {
g := generate.NewFromSpec(c.config.Spec)
if err := c.saveSpec(g.Config); err != nil {
- return errors.Wrap(err, "saving imported container specification for restore failed")
+ return fmt.Errorf("saving imported container specification for restore failed: %w", err)
}
return nil
@@ -1594,14 +1626,14 @@ func (c *Container) importCheckpointTar(input string) error {
func (c *Container) importPreCheckpoint(input string) error {
archiveFile, err := os.Open(input)
if err != nil {
- return errors.Wrap(err, "failed to open pre-checkpoint archive for import")
+ return fmt.Errorf("failed to open pre-checkpoint archive for import: %w", err)
}
defer archiveFile.Close()
err = archive.Untar(archiveFile, c.bundlePath(), nil)
if err != nil {
- return errors.Wrapf(err, "Unpacking of pre-checkpoint archive %s failed", input)
+ return fmt.Errorf("unpacking of pre-checkpoint archive %s failed: %w", input, err)
}
return nil
}
@@ -1618,11 +1650,11 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
if options.Pod != "" && !crutils.CRRuntimeSupportsPodCheckpointRestore(c.ociRuntime.Path()) {
- return nil, 0, errors.Errorf("runtime %s does not support pod restore", c.ociRuntime.Path())
+ return nil, 0, fmt.Errorf("runtime %s does not support pod restore", c.ociRuntime.Path())
}
if !c.ensureState(define.ContainerStateConfigured, define.ContainerStateExited) {
- return nil, 0, errors.Wrapf(define.ErrCtrStateInvalid, "container %s is running or paused, cannot restore", c.ID())
+ return nil, 0, fmt.Errorf("container %s is running or paused, cannot restore: %w", c.ID(), define.ErrCtrStateInvalid)
}
if options.ImportPrevious != "" {
@@ -1644,7 +1676,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
// Let's try to stat() CRIU's inventory file. If it does not exist, it makes
// no sense to try a restore. This is a minimal check if a checkpoint exist.
if _, err := os.Stat(filepath.Join(c.CheckpointPath(), "inventory.img")); os.IsNotExist(err) {
- return nil, 0, errors.Wrapf(err, "a complete checkpoint for this container cannot be found, cannot restore")
+ return nil, 0, fmt.Errorf("a complete checkpoint for this container cannot be found, cannot restore: %w", err)
}
if err := crutils.CRCreateFileWithLabel(c.bundlePath(), "restore.log", c.MountLabel()); err != nil {
@@ -1742,23 +1774,23 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
// the ones from the infrastructure container.
pod, err := c.runtime.LookupPod(options.Pod)
if err != nil {
- return nil, 0, errors.Wrapf(err, "pod %q cannot be retrieved", options.Pod)
+ return nil, 0, fmt.Errorf("pod %q cannot be retrieved: %w", options.Pod, err)
}
infraContainer, err := pod.InfraContainer()
if err != nil {
- return nil, 0, errors.Wrapf(err, "cannot retrieved infra container from pod %q", options.Pod)
+ return nil, 0, fmt.Errorf("cannot retrieved infra container from pod %q: %w", options.Pod, err)
}
infraContainer.lock.Lock()
if err := infraContainer.syncContainer(); err != nil {
infraContainer.lock.Unlock()
- return nil, 0, errors.Wrapf(err, "Error syncing infrastructure container %s status", infraContainer.ID())
+ return nil, 0, fmt.Errorf("error syncing infrastructure container %s status: %w", infraContainer.ID(), err)
}
if infraContainer.state.State != define.ContainerStateRunning {
if err := infraContainer.initAndStart(ctx); err != nil {
infraContainer.lock.Unlock()
- return nil, 0, errors.Wrapf(err, "Error starting infrastructure container %s status", infraContainer.ID())
+ return nil, 0, fmt.Errorf("error starting infrastructure container %s status: %w", infraContainer.ID(), err)
}
}
infraContainer.lock.Unlock()
@@ -1766,7 +1798,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if c.config.IPCNsCtr != "" {
nsPath, err := infraContainer.namespacePath(IPCNS)
if err != nil {
- return nil, 0, errors.Wrapf(err, "cannot retrieve IPC namespace path for Pod %q", options.Pod)
+ return nil, 0, fmt.Errorf("cannot retrieve IPC namespace path for Pod %q: %w", options.Pod, err)
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.IPCNamespace), nsPath); err != nil {
return nil, 0, err
@@ -1776,7 +1808,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if c.config.NetNsCtr != "" {
nsPath, err := infraContainer.namespacePath(NetNS)
if err != nil {
- return nil, 0, errors.Wrapf(err, "cannot retrieve network namespace path for Pod %q", options.Pod)
+ return nil, 0, fmt.Errorf("cannot retrieve network namespace path for Pod %q: %w", options.Pod, err)
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.NetworkNamespace), nsPath); err != nil {
return nil, 0, err
@@ -1786,7 +1818,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if c.config.PIDNsCtr != "" {
nsPath, err := infraContainer.namespacePath(PIDNS)
if err != nil {
- return nil, 0, errors.Wrapf(err, "cannot retrieve PID namespace path for Pod %q", options.Pod)
+ return nil, 0, fmt.Errorf("cannot retrieve PID namespace path for Pod %q: %w", options.Pod, err)
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.PIDNamespace), nsPath); err != nil {
return nil, 0, err
@@ -1796,7 +1828,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if c.config.UTSNsCtr != "" {
nsPath, err := infraContainer.namespacePath(UTSNS)
if err != nil {
- return nil, 0, errors.Wrapf(err, "cannot retrieve UTS namespace path for Pod %q", options.Pod)
+ return nil, 0, fmt.Errorf("cannot retrieve UTS namespace path for Pod %q: %w", options.Pod, err)
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.UTSNamespace), nsPath); err != nil {
return nil, 0, err
@@ -1806,7 +1838,7 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
if c.config.CgroupNsCtr != "" {
nsPath, err := infraContainer.namespacePath(CgroupNS)
if err != nil {
- return nil, 0, errors.Wrapf(err, "cannot retrieve Cgroup namespace path for Pod %q", options.Pod)
+ return nil, 0, fmt.Errorf("cannot retrieve Cgroup namespace path for Pod %q: %w", options.Pod, err)
}
if err := g.AddOrReplaceLinuxNamespace(string(spec.CgroupNamespace), nsPath); err != nil {
return nil, 0, err
@@ -1874,13 +1906,13 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
volumeFile, err := os.Open(volumeFilePath)
if err != nil {
- return nil, 0, errors.Wrapf(err, "failed to open volume file %s", volumeFilePath)
+ return nil, 0, fmt.Errorf("failed to open volume file %s: %w", volumeFilePath, err)
}
defer volumeFile.Close()
volume, err := c.runtime.GetVolume(v.Name)
if err != nil {
- return nil, 0, errors.Wrapf(err, "failed to retrieve volume %s", v.Name)
+ return nil, 0, fmt.Errorf("failed to retrieve volume %s: %w", v.Name, err)
}
mountPoint, err := volume.MountPoint()
@@ -1888,10 +1920,10 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
return nil, 0, err
}
if mountPoint == "" {
- return nil, 0, errors.Wrapf(err, "unable to import volume %s as it is not mounted", volume.Name())
+ return nil, 0, fmt.Errorf("unable to import volume %s as it is not mounted: %w", volume.Name(), err)
}
if err := archive.UntarUncompressed(volumeFile, mountPoint, nil); err != nil {
- return nil, 0, errors.Wrapf(err, "Failed to extract volume %s to %s", volumeFilePath, mountPoint)
+ return nil, 0, fmt.Errorf("failed to extract volume %s to %s: %w", volumeFilePath, mountPoint, err)
}
}
}
@@ -1918,12 +1950,12 @@ func (c *Container) restore(ctx context.Context, options ContainerCheckpointOpti
}
statsDirectory, err := os.Open(c.bundlePath())
if err != nil {
- return nil, errors.Wrapf(err, "Not able to open %q", c.bundlePath())
+ return nil, fmt.Errorf("not able to open %q: %w", c.bundlePath(), err)
}
restoreStatistics, err := stats.CriuGetRestoreStats(statsDirectory)
if err != nil {
- return nil, errors.Wrap(err, "Displaying restore statistics not possible")
+ return nil, fmt.Errorf("displaying restore statistics not possible: %w", err)
}
return &define.CRIUCheckpointRestoreStatistics{
@@ -2001,7 +2033,7 @@ func (c *Container) getRootNetNsDepCtr() (depCtr *Container, err error) {
depCtr, err = c.runtime.state.Container(nextCtr)
if err != nil {
- return nil, errors.Wrapf(err, "error fetching dependency %s of container %s", c.config.NetNsCtr, c.ID())
+ return nil, fmt.Errorf("error fetching dependency %s of container %s: %w", c.config.NetNsCtr, c.ID(), err)
}
// This should never happen without an error
if depCtr == nil {
@@ -2030,7 +2062,7 @@ func (c *Container) mountIntoRootDirs(mountName string, mountPath string) error
// Make standard bind mounts to include in the container
func (c *Container) makeBindMounts() error {
if err := os.Chown(c.state.RunDir, c.RootUID(), c.RootGID()); err != nil {
- return errors.Wrap(err, "cannot chown run directory")
+ return fmt.Errorf("cannot chown run directory: %w", err)
}
if c.state.BindMounts == nil {
@@ -2048,13 +2080,13 @@ func (c *Container) makeBindMounts() error {
if c.config.NetNsCtr == "" {
if resolvePath, ok := c.state.BindMounts["/etc/resolv.conf"]; ok {
if err := os.Remove(resolvePath); err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "container %s", c.ID())
+ return fmt.Errorf("container %s: %w", c.ID(), err)
}
delete(c.state.BindMounts, "/etc/resolv.conf")
}
if hostsPath, ok := c.state.BindMounts["/etc/hosts"]; ok {
if err := os.Remove(hostsPath); err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "container %s", c.ID())
+ return fmt.Errorf("container %s: %w", c.ID(), err)
}
delete(c.state.BindMounts, "/etc/hosts")
}
@@ -2067,13 +2099,13 @@ func (c *Container) makeBindMounts() error {
// them.
depCtr, err := c.getRootNetNsDepCtr()
if err != nil {
- return errors.Wrapf(err, "error fetching network namespace dependency container for container %s", c.ID())
+ return fmt.Errorf("error fetching network namespace dependency container for container %s: %w", c.ID(), err)
}
// We need that container's bind mounts
bindMounts, err := depCtr.BindMounts()
if err != nil {
- return errors.Wrapf(err, "error fetching bind mounts from dependency %s of container %s", depCtr.ID(), c.ID())
+ return fmt.Errorf("error fetching bind mounts from dependency %s of container %s: %w", depCtr.ID(), c.ID(), err)
}
// The other container may not have a resolv.conf or /etc/hosts
@@ -2083,7 +2115,7 @@ func (c *Container) makeBindMounts() error {
err := c.mountIntoRootDirs("/etc/resolv.conf", resolvPath)
if err != nil {
- return errors.Wrapf(err, "error assigning mounts to container %s", c.ID())
+ return fmt.Errorf("error assigning mounts to container %s: %w", c.ID(), err)
}
}
@@ -2103,13 +2135,13 @@ func (c *Container) makeBindMounts() error {
err = etchosts.Add(hostsPath, getLocalhostHostEntry(c))
lock.Unlock()
if err != nil {
- return errors.Wrapf(err, "error creating hosts file for container %s which depends on container %s", c.ID(), depCtr.ID())
+ return fmt.Errorf("error creating hosts file for container %s which depends on container %s: %w", c.ID(), depCtr.ID(), err)
}
// finally, save it in the new container
err = c.mountIntoRootDirs(config.DefaultHostsFile, hostsPath)
if err != nil {
- return errors.Wrapf(err, "error assigning mounts to container %s", c.ID())
+ return fmt.Errorf("error assigning mounts to container %s: %w", c.ID(), err)
}
}
@@ -2124,13 +2156,13 @@ func (c *Container) makeBindMounts() error {
} else {
if !c.config.UseImageResolvConf {
if err := c.generateResolvConf(); err != nil {
- return errors.Wrapf(err, "error creating resolv.conf for container %s", c.ID())
+ return fmt.Errorf("error creating resolv.conf for container %s: %w", c.ID(), err)
}
}
if !c.config.UseImageHosts {
if err := c.createHosts(); err != nil {
- return errors.Wrapf(err, "error creating hosts file for container %s", c.ID())
+ return fmt.Errorf("error creating hosts file for container %s: %w", c.ID(), err)
}
}
}
@@ -2148,7 +2180,7 @@ func (c *Container) makeBindMounts() error {
}
} else if !c.config.UseImageHosts && c.state.BindMounts["/etc/hosts"] == "" {
if err := c.createHosts(); err != nil {
- return errors.Wrapf(err, "error creating hosts file for container %s", c.ID())
+ return fmt.Errorf("error creating hosts file for container %s: %w", c.ID(), err)
}
}
@@ -2160,7 +2192,7 @@ func (c *Container) makeBindMounts() error {
if c.config.Passwd == nil || *c.config.Passwd {
newPasswd, newGroup, err := c.generatePasswdAndGroup()
if err != nil {
- return errors.Wrapf(err, "error creating temporary passwd file for container %s", c.ID())
+ return fmt.Errorf("error creating temporary passwd file for container %s: %w", c.ID(), err)
}
if newPasswd != "" {
// Make /etc/passwd
@@ -2181,7 +2213,7 @@ func (c *Container) makeBindMounts() error {
if _, ok := c.state.BindMounts["/etc/hostname"]; !ok {
hostnamePath, err := c.writeStringToRundir("hostname", c.Hostname())
if err != nil {
- return errors.Wrapf(err, "error creating hostname file for container %s", c.ID())
+ return fmt.Errorf("error creating hostname file for container %s: %w", c.ID(), err)
}
c.state.BindMounts["/etc/hostname"] = hostnamePath
}
@@ -2193,7 +2225,7 @@ func (c *Container) makeBindMounts() error {
if ctrTimezone != "local" {
_, err = time.LoadLocation(ctrTimezone)
if err != nil {
- return errors.Wrapf(err, "error finding timezone for container %s", c.ID())
+ return fmt.Errorf("error finding timezone for container %s: %w", c.ID(), err)
}
}
if _, ok := c.state.BindMounts["/etc/localtime"]; !ok {
@@ -2201,25 +2233,36 @@ func (c *Container) makeBindMounts() error {
if ctrTimezone == "local" {
zonePath, err = filepath.EvalSymlinks("/etc/localtime")
if err != nil {
- return errors.Wrapf(err, "error finding local timezone for container %s", c.ID())
+ return fmt.Errorf("error finding local timezone for container %s: %w", c.ID(), err)
}
} else {
zone := filepath.Join("/usr/share/zoneinfo", ctrTimezone)
zonePath, err = filepath.EvalSymlinks(zone)
if err != nil {
- return errors.Wrapf(err, "error setting timezone for container %s", c.ID())
+ return fmt.Errorf("error setting timezone for container %s: %w", c.ID(), err)
}
}
localtimePath, err := c.copyTimezoneFile(zonePath)
if err != nil {
- return errors.Wrapf(err, "error setting timezone for container %s", c.ID())
+ return fmt.Errorf("error setting timezone for container %s: %w", c.ID(), err)
}
c.state.BindMounts["/etc/localtime"] = localtimePath
}
}
+ _, hasRunContainerenv := c.state.BindMounts["/run/.containerenv"]
+ if !hasRunContainerenv {
+ // check in the spec mounts
+ for _, m := range c.config.Spec.Mounts {
+ if m.Destination == "/run/.containerenv" || m.Destination == "/run" {
+ hasRunContainerenv = true
+ break
+ }
+ }
+ }
+
// Make .containerenv if it does not exist
- if _, ok := c.state.BindMounts["/run/.containerenv"]; !ok {
+ if !hasRunContainerenv {
containerenv := c.runtime.graphRootMountedFlag(c.config.Spec.Mounts)
isRootless := 0
if rootless.IsRootless() {
@@ -2239,7 +2282,7 @@ rootless=%d
}
containerenvPath, err := c.writeStringToRundir(".containerenv", containerenv)
if err != nil {
- return errors.Wrapf(err, "error creating containerenv file for container %s", c.ID())
+ return fmt.Errorf("error creating containerenv file for container %s: %w", c.ID(), err)
}
c.state.BindMounts["/run/.containerenv"] = containerenvPath
}
@@ -2260,7 +2303,7 @@ rootless=%d
if len(c.Secrets()) > 0 {
// create /run/secrets if subscriptions did not create
if err := c.createSecretMountDir(); err != nil {
- return errors.Wrapf(err, "error creating secrets mount")
+ return fmt.Errorf("error creating secrets mount: %w", err)
}
for _, secret := range c.Secrets() {
secretFileName := secret.Name
@@ -2284,49 +2327,10 @@ rootless=%d
// generateResolvConf generates a containers resolv.conf
func (c *Container) generateResolvConf() error {
var (
- nameservers []string
networkNameServers []string
networkSearchDomains []string
)
- hostns := true
- resolvConf := "/etc/resolv.conf"
- for _, namespace := range c.config.Spec.Linux.Namespaces {
- if namespace.Type == spec.NetworkNamespace {
- hostns = false
- if namespace.Path != "" && !strings.HasPrefix(namespace.Path, "/proc/") {
- definedPath := filepath.Join("/etc/netns", filepath.Base(namespace.Path), "resolv.conf")
- _, err := os.Stat(definedPath)
- if err == nil {
- resolvConf = definedPath
- } else if !os.IsNotExist(err) {
- return err
- }
- }
- break
- }
- }
-
- contents, err := ioutil.ReadFile(resolvConf)
- // resolv.conf doesn't have to exists
- if err != nil && !os.IsNotExist(err) {
- return err
- }
-
- ns := resolvconf.GetNameservers(contents)
- // check if systemd-resolved is used, assume it is used when 127.0.0.53 is the only nameserver
- if !hostns && len(ns) == 1 && ns[0] == "127.0.0.53" {
- // read the actual resolv.conf file for systemd-resolved
- resolvedContents, err := ioutil.ReadFile("/run/systemd/resolve/resolv.conf")
- if err != nil {
- if !os.IsNotExist(err) {
- return errors.Wrapf(err, "detected that systemd-resolved is in use, but could not locate real resolv.conf")
- }
- } else {
- contents = resolvedContents
- }
- }
-
netStatus := c.getNetworkStatus()
for _, status := range netStatus {
if status.DNSServerIPs != nil {
@@ -2346,34 +2350,18 @@ func (c *Container) generateResolvConf() error {
return err
}
- // Ensure that the container's /etc/resolv.conf is compatible with its
- // network configuration.
- resolv, err := resolvconf.FilterResolvDNS(contents, ipv6, !hostns)
- if err != nil {
- return errors.Wrapf(err, "error parsing host resolv.conf")
- }
-
- dns := make([]net.IP, 0, len(c.runtime.config.Containers.DNSServers)+len(c.config.DNSServer))
- for _, i := range c.runtime.config.Containers.DNSServers {
- result := net.ParseIP(i)
- if result == nil {
- return errors.Wrapf(define.ErrInvalidArg, "invalid IP address %s", i)
- }
- dns = append(dns, result)
+ nameservers := make([]string, 0, len(c.runtime.config.Containers.DNSServers)+len(c.config.DNSServer))
+ nameservers = append(nameservers, c.runtime.config.Containers.DNSServers...)
+ for _, ip := range c.config.DNSServer {
+ nameservers = append(nameservers, ip.String())
}
- dns = append(dns, c.config.DNSServer...)
// If the user provided dns, it trumps all; then dns masq; then resolv.conf
var search []string
- switch {
- case len(dns) > 0:
- // We store DNS servers as net.IP, so need to convert to string
- for _, server := range dns {
- nameservers = append(nameservers, server.String())
- }
- default:
- // Make a new resolv.conf
+ keepHostServers := false
+ if len(nameservers) == 0 {
+ keepHostServers = true
// first add the nameservers from the networks status
- nameservers = append(nameservers, networkNameServers...)
+ nameservers = networkNameServers
// when we add network dns server we also have to add the search domains
search = networkSearchDomains
// slirp4netns has a built in DNS forwarder.
@@ -2385,38 +2373,34 @@ func (c *Container) generateResolvConf() error {
nameservers = append(nameservers, slirp4netnsDNS.String())
}
}
- nameservers = append(nameservers, resolvconf.GetNameservers(resolv.Content)...)
}
if len(c.config.DNSSearch) > 0 || len(c.runtime.config.Containers.DNSSearches) > 0 {
- if !util.StringInSlice(".", c.config.DNSSearch) {
- search = append(search, c.runtime.config.Containers.DNSSearches...)
- search = append(search, c.config.DNSSearch...)
- }
- } else {
- search = append(search, resolvconf.GetSearchDomains(resolv.Content)...)
+ customSearch := make([]string, 0, len(c.config.DNSSearch)+len(c.runtime.config.Containers.DNSSearches))
+ customSearch = append(customSearch, c.runtime.config.Containers.DNSSearches...)
+ customSearch = append(customSearch, c.config.DNSSearch...)
+ search = customSearch
}
- var options []string
- if len(c.config.DNSOption) > 0 || len(c.runtime.config.Containers.DNSOptions) > 0 {
- options = c.runtime.config.Containers.DNSOptions
- options = append(options, c.config.DNSOption...)
- } else {
- options = resolvconf.GetOptions(resolv.Content)
- }
+ options := make([]string, 0, len(c.config.DNSOption)+len(c.runtime.config.Containers.DNSOptions))
+ options = append(options, c.runtime.config.Containers.DNSOptions...)
+ options = append(options, c.config.DNSOption...)
destPath := filepath.Join(c.state.RunDir, "resolv.conf")
- if err := os.Remove(destPath); err != nil && !os.IsNotExist(err) {
- return errors.Wrapf(err, "container %s", c.ID())
- }
-
- // Build resolv.conf
- if _, err = resolvconf.Build(destPath, nameservers, search, options); err != nil {
- return errors.Wrapf(err, "error building resolv.conf for container %s", c.ID())
+ if err := resolvconf.New(&resolvconf.Params{
+ IPv6Enabled: ipv6,
+ KeepHostServers: keepHostServers,
+ Nameservers: nameservers,
+ Namespaces: c.config.Spec.Linux.Namespaces,
+ Options: options,
+ Path: destPath,
+ Searches: search,
+ }); err != nil {
+ return fmt.Errorf("error building resolv.conf for container %s: %w", c.ID(), err)
}
- return c.bindMountRootFile(destPath, "/etc/resolv.conf")
+ return c.bindMountRootFile(destPath, resolvconf.DefaultResolvConf)
}
// Check if a container uses IPv6.
@@ -2457,31 +2441,13 @@ func (c *Container) addNameserver(ips []string) error {
}
// Do we have a resolv.conf at all?
- path, ok := c.state.BindMounts["/etc/resolv.conf"]
+ path, ok := c.state.BindMounts[resolvconf.DefaultResolvConf]
if !ok {
return nil
}
- // Read in full contents, parse out existing nameservers
- contents, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- ns := resolvconf.GetNameservers(contents)
- options := resolvconf.GetOptions(contents)
- search := resolvconf.GetSearchDomains(contents)
-
- // We could verify that it doesn't already exist
- // but extra nameservers shouldn't harm anything.
- // Ensure we are the first entry in resolv.conf though, otherwise we
- // might be after user-added servers.
- ns = append(ips, ns...)
-
- // We're rewriting the container's resolv.conf as part of this, but we
- // hold the container lock, so there should be no risk of parallel
- // modification.
- if _, err := resolvconf.Build(path, ns, search, options); err != nil {
- return errors.Wrapf(err, "error adding new nameserver to container %s resolv.conf", c.ID())
+ if err := resolvconf.Add(path, ips); err != nil {
+ return fmt.Errorf("adding new nameserver to container %s resolv.conf: %w", c.ID(), err)
}
return nil
@@ -2496,34 +2462,13 @@ func (c *Container) removeNameserver(ips []string) error {
}
// Do we have a resolv.conf at all?
- path, ok := c.state.BindMounts["/etc/resolv.conf"]
+ path, ok := c.state.BindMounts[resolvconf.DefaultResolvConf]
if !ok {
return nil
}
- // Read in full contents, parse out existing nameservers
- contents, err := ioutil.ReadFile(path)
- if err != nil {
- return err
- }
- ns := resolvconf.GetNameservers(contents)
- options := resolvconf.GetOptions(contents)
- search := resolvconf.GetSearchDomains(contents)
-
- toRemove := make(map[string]bool)
- for _, ip := range ips {
- toRemove[ip] = true
- }
-
- newNS := make([]string, 0, len(ns))
- for _, server := range ns {
- if !toRemove[server] {
- newNS = append(newNS, server)
- }
- }
-
- if _, err := resolvconf.Build(path, newNS, search, options); err != nil {
- return errors.Wrapf(err, "error removing nameservers from container %s resolv.conf", c.ID())
+ if err := resolvconf.Remove(path, ips); err != nil {
+ return fmt.Errorf("removing nameservers from container %s resolv.conf: %w", c.ID(), err)
}
return nil
@@ -2653,16 +2598,16 @@ func (c *Container) generateCurrentUserGroupEntry() (string, int, error) {
g, err := user.LookupGroupId(strconv.Itoa(gid))
if err != nil {
- return "", 0, errors.Wrapf(err, "failed to get current group")
+ return "", 0, fmt.Errorf("failed to get current group: %w", err)
}
- // Lookup group name to see if it exists in the image.
+ // Look up group name to see if it exists in the image.
_, err = lookup.GetGroup(c.state.Mountpoint, g.Name)
if err != runcuser.ErrNoGroupEntries {
return "", 0, err
}
- // Lookup GID to see if it exists in the image.
+ // Look up GID to see if it exists in the image.
_, err = lookup.GetGroup(c.state.Mountpoint, g.Gid)
if err != runcuser.ErrNoGroupEntries {
return "", 0, err
@@ -2675,7 +2620,7 @@ func (c *Container) generateCurrentUserGroupEntry() (string, int, error) {
if uid != 0 {
u, err := user.LookupId(strconv.Itoa(uid))
if err != nil {
- return "", 0, errors.Wrapf(err, "failed to get current user to make group entry")
+ return "", 0, fmt.Errorf("failed to get current user to make group entry: %w", err)
}
username = u.Username
}
@@ -2699,7 +2644,7 @@ func (c *Container) generateUserGroupEntry(addedGID int) (string, error) {
gid, err := strconv.ParseUint(group, 10, 32)
if err != nil {
- return "", nil // nolint: nilerr
+ return "", nil //nolint: nilerr
}
if addedGID != 0 && addedGID == int(gid) {
@@ -2732,7 +2677,7 @@ func (c *Container) generatePasswdEntry() (string, error) {
addedUID := 0
for _, userid := range c.config.HostUsers {
- // Lookup User on host
+ // Look up User on host
u, err := util.LookupUser(userid)
if err != nil {
return "", err
@@ -2773,7 +2718,7 @@ func (c *Container) generateCurrentUserPasswdEntry() (string, int, int, error) {
u, err := user.LookupId(strconv.Itoa(uid))
if err != nil {
- return "", 0, 0, errors.Wrapf(err, "failed to get current user")
+ return "", 0, 0, fmt.Errorf("failed to get current user: %w", err)
}
pwd, err := c.userPasswdEntry(u)
if err != nil {
@@ -2784,13 +2729,13 @@ func (c *Container) generateCurrentUserPasswdEntry() (string, int, int, error) {
}
func (c *Container) userPasswdEntry(u *user.User) (string, error) {
- // Lookup the user to see if it exists in the container image.
+ // Look up the user to see if it exists in the container image.
_, err := lookup.GetUser(c.state.Mountpoint, u.Username)
if err != runcuser.ErrNoPasswdEntries {
return "", err
}
- // Lookup the UID to see if it exists in the container image.
+ // Look up the UID to see if it exists in the container image.
_, err = lookup.GetUser(c.state.Mountpoint, u.Uid)
if err != runcuser.ErrNoPasswdEntries {
return "", err
@@ -2855,14 +2800,14 @@ func (c *Container) generateUserPasswdEntry(addedUID int) (string, error) {
// If a non numeric User, then don't generate passwd
uid, err := strconv.ParseUint(userspec, 10, 32)
if err != nil {
- return "", nil // nolint: nilerr
+ return "", nil //nolint: nilerr
}
if addedUID != 0 && int(uid) == addedUID {
return "", nil
}
- // Lookup the user to see if it exists in the container image
+ // Look up the user to see if it exists in the container image
_, err = lookup.GetUser(c.state.Mountpoint, userspec)
if err != runcuser.ErrNoPasswdEntries {
return "", err
@@ -2875,7 +2820,7 @@ func (c *Container) generateUserPasswdEntry(addedUID int) (string, error) {
} else {
group, err := lookup.GetGroup(c.state.Mountpoint, groupspec)
if err != nil {
- return "", errors.Wrapf(err, "unable to get gid %s from group file", groupspec)
+ return "", fmt.Errorf("unable to get gid %s from group file: %w", groupspec, err)
}
gid = group.Gid
}
@@ -2984,7 +2929,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {
logrus.Debugf("Making /etc/passwd for container %s", c.ID())
originPasswdFile, err := securejoin.SecureJoin(c.state.Mountpoint, "/etc/passwd")
if err != nil {
- return "", "", errors.Wrapf(err, "error creating path to container %s /etc/passwd", c.ID())
+ return "", "", fmt.Errorf("error creating path to container %s /etc/passwd: %w", c.ID(), err)
}
orig, err := ioutil.ReadFile(originPasswdFile)
if err != nil && !os.IsNotExist(err) {
@@ -2992,7 +2937,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {
}
passwdFile, err := c.writeStringToStaticDir("passwd", string(orig)+passwdEntry)
if err != nil {
- return "", "", errors.Wrapf(err, "failed to create temporary passwd file")
+ return "", "", fmt.Errorf("failed to create temporary passwd file: %w", err)
}
if err := os.Chmod(passwdFile, 0644); err != nil {
return "", "", err
@@ -3002,17 +2947,17 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {
logrus.Debugf("Modifying container %s /etc/passwd", c.ID())
containerPasswd, err := securejoin.SecureJoin(c.state.Mountpoint, "/etc/passwd")
if err != nil {
- return "", "", errors.Wrapf(err, "error looking up location of container %s /etc/passwd", c.ID())
+ return "", "", fmt.Errorf("error looking up location of container %s /etc/passwd: %w", c.ID(), err)
}
f, err := os.OpenFile(containerPasswd, os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
- return "", "", errors.Wrapf(err, "container %s", c.ID())
+ return "", "", fmt.Errorf("container %s: %w", c.ID(), err)
}
defer f.Close()
if _, err := f.WriteString(passwdEntry); err != nil {
- return "", "", errors.Wrapf(err, "unable to append to container %s /etc/passwd", c.ID())
+ return "", "", fmt.Errorf("unable to append to container %s /etc/passwd: %w", c.ID(), err)
}
default:
logrus.Debugf("Not modifying container %s /etc/passwd", c.ID())
@@ -3030,7 +2975,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {
logrus.Debugf("Making /etc/group for container %s", c.ID())
originGroupFile, err := securejoin.SecureJoin(c.state.Mountpoint, "/etc/group")
if err != nil {
- return "", "", errors.Wrapf(err, "error creating path to container %s /etc/group", c.ID())
+ return "", "", fmt.Errorf("error creating path to container %s /etc/group: %w", c.ID(), err)
}
orig, err := ioutil.ReadFile(originGroupFile)
if err != nil && !os.IsNotExist(err) {
@@ -3038,7 +2983,7 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {
}
groupFile, err := c.writeStringToStaticDir("group", string(orig)+groupEntry)
if err != nil {
- return "", "", errors.Wrapf(err, "failed to create temporary group file")
+ return "", "", fmt.Errorf("failed to create temporary group file: %w", err)
}
if err := os.Chmod(groupFile, 0644); err != nil {
return "", "", err
@@ -3048,17 +2993,17 @@ func (c *Container) generatePasswdAndGroup() (string, string, error) {
logrus.Debugf("Modifying container %s /etc/group", c.ID())
containerGroup, err := securejoin.SecureJoin(c.state.Mountpoint, "/etc/group")
if err != nil {
- return "", "", errors.Wrapf(err, "error looking up location of container %s /etc/group", c.ID())
+ return "", "", fmt.Errorf("error looking up location of container %s /etc/group: %w", c.ID(), err)
}
f, err := os.OpenFile(containerGroup, os.O_APPEND|os.O_WRONLY, 0600)
if err != nil {
- return "", "", errors.Wrapf(err, "container %s", c.ID())
+ return "", "", fmt.Errorf("container %s: %w", c.ID(), err)
}
defer f.Close()
if _, err := f.WriteString(groupEntry); err != nil {
- return "", "", errors.Wrapf(err, "unable to append to container %s /etc/group", c.ID())
+ return "", "", fmt.Errorf("unable to append to container %s /etc/group: %w", c.ID(), err)
}
default:
logrus.Debugf("Not modifying container %s /etc/group", c.ID())
@@ -3093,7 +3038,7 @@ func (c *Container) expectPodCgroup() (bool, error) {
case cgroupManager == config.CgroupfsCgroupsManager:
return !rootless.IsRootless(), nil
default:
- return false, errors.Wrapf(define.ErrInvalidArg, "invalid cgroup mode %s requested for pods", cgroupManager)
+ return false, fmt.Errorf("invalid cgroup mode %s requested for pods: %w", cgroupManager, define.ErrInvalidArg)
}
}
@@ -3108,7 +3053,7 @@ func (c *Container) getOCICgroupPath() (string, error) {
case c.config.NoCgroups:
return "", nil
case c.config.CgroupsMode == cgroupSplit:
- selfCgroup, err := utils.GetOwnCgroup()
+ selfCgroup, err := utils.GetOwnCgroupDisallowRoot()
if err != nil {
return "", err
}
@@ -3130,7 +3075,7 @@ func (c *Container) getOCICgroupPath() (string, error) {
logrus.Debugf("Setting Cgroup path for container %s to %s", c.ID(), cgroupPath)
return cgroupPath, nil
default:
- return "", errors.Wrapf(define.ErrInvalidArg, "invalid cgroup manager %s requested", cgroupManager)
+ return "", fmt.Errorf("invalid cgroup manager %s requested: %w", cgroupManager, define.ErrInvalidArg)
}
}
@@ -3141,7 +3086,7 @@ func (c *Container) copyTimezoneFile(zonePath string) (string, error) {
return "", err
}
if file.IsDir() {
- return "", errors.New("Invalid timezone: is a directory")
+ return "", errors.New("invalid timezone: is a directory")
}
src, err := os.Open(zonePath)
if err != nil {
@@ -3175,14 +3120,14 @@ func (c *Container) cleanupOverlayMounts() error {
func (c *Container) checkFileExistsInRootfs(file string) (bool, error) {
checkPath, err := securejoin.SecureJoin(c.state.Mountpoint, file)
if err != nil {
- return false, errors.Wrapf(err, "cannot create path to container %s file %q", c.ID(), file)
+ return false, fmt.Errorf("cannot create path to container %s file %q: %w", c.ID(), file, err)
}
stat, err := os.Stat(checkPath)
if err != nil {
if os.IsNotExist(err) {
return false, nil
}
- return false, errors.Wrapf(err, "container %s", c.ID())
+ return false, fmt.Errorf("container %s: %w", c.ID(), err)
}
if stat.IsDir() {
return false, nil
@@ -3218,7 +3163,7 @@ func (c *Container) createSecretMountDir() error {
func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error {
vol, err := c.runtime.state.Volume(v.Name)
if err != nil {
- return errors.Wrapf(err, "error retrieving named volume %s for container %s", v.Name, c.ID())
+ return fmt.Errorf("error retrieving named volume %s for container %s: %w", v.Name, c.ID(), err)
}
vol.lock.Lock()
@@ -3229,10 +3174,8 @@ func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error {
return err
}
- // TODO: For now, I've disabled chowning volumes owned by non-Podman
- // drivers. This may be safe, but it's really going to be a case-by-case
- // thing, I think - safest to leave disabled now and re-enable later if
- // there is a demand.
+ // Volumes owned by a volume driver are not chowned - we don't want to
+ // mess with a mount not managed by us.
if vol.state.NeedsChown && !vol.UsesVolumeDriver() {
vol.state.NeedsChown = false
@@ -3247,7 +3190,7 @@ func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error {
mappings := idtools.NewIDMappingsFromMaps(c.config.IDMappings.UIDMap, c.config.IDMappings.GIDMap)
newPair, err := mappings.ToHost(p)
if err != nil {
- return errors.Wrapf(err, "error mapping user %d:%d", uid, gid)
+ return fmt.Errorf("error mapping user %d:%d: %w", uid, gid, err)
}
uid = newPair.UID
gid = newPair.GID
@@ -3282,7 +3225,7 @@ func (c *Container) fixVolumePermissions(v *ContainerNamedVolume) error {
return err
}
stat := st.Sys().(*syscall.Stat_t)
- atime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)) // nolint: unconvert
+ atime := time.Unix(int64(stat.Atim.Sec), int64(stat.Atim.Nsec)) //nolint: unconvert
if err := os.Chtimes(mountPoint, atime, st.ModTime()); err != nil {
return err
}