summaryrefslogtreecommitdiff
path: root/pkg/domain/infra/abi
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/domain/infra/abi')
-rw-r--r--pkg/domain/infra/abi/containers.go30
-rw-r--r--pkg/domain/infra/abi/cp.go433
-rw-r--r--pkg/domain/infra/abi/events.go2
-rw-r--r--pkg/domain/infra/abi/healthcheck.go2
-rw-r--r--pkg/domain/infra/abi/images.go217
-rw-r--r--pkg/domain/infra/abi/images_list.go2
-rw-r--r--pkg/domain/infra/abi/pods.go2
-rw-r--r--pkg/domain/infra/abi/runtime.go2
-rw-r--r--pkg/domain/infra/abi/system.go41
-rw-r--r--pkg/domain/infra/abi/terminal/sigproxy_linux.go2
-rw-r--r--pkg/domain/infra/abi/terminal/terminal.go2
-rw-r--r--pkg/domain/infra/abi/terminal/terminal_linux.go2
12 files changed, 606 insertions, 131 deletions
diff --git a/pkg/domain/infra/abi/containers.go b/pkg/domain/infra/abi/containers.go
index 50003dbe2..73a0d8ec3 100644
--- a/pkg/domain/infra/abi/containers.go
+++ b/pkg/domain/infra/abi/containers.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package abi
import (
@@ -931,3 +929,31 @@ func (ic *ContainerEngine) ContainerUnmount(ctx context.Context, nameOrIds []str
func (ic *ContainerEngine) Config(_ context.Context) (*config.Config, error) {
return ic.Libpod.GetConfig()
}
+
+func (ic *ContainerEngine) ContainerPort(ctx context.Context, nameOrId string, options entities.ContainerPortOptions) ([]*entities.ContainerPortReport, error) {
+ var reports []*entities.ContainerPortReport
+ ctrs, err := getContainersByContext(options.All, false, []string{nameOrId}, ic.Libpod)
+ if err != nil {
+ return nil, err
+ }
+ for _, con := range ctrs {
+ state, err := con.State()
+ if err != nil {
+ return nil, err
+ }
+ if state != define.ContainerStateRunning {
+ continue
+ }
+ portmappings, err := con.PortMappings()
+ if err != nil {
+ return nil, err
+ }
+ if len(portmappings) > 0 {
+ reports = append(reports, &entities.ContainerPortReport{
+ Id: con.ID(),
+ Ports: portmappings,
+ })
+ }
+ }
+ return reports, nil
+}
diff --git a/pkg/domain/infra/abi/cp.go b/pkg/domain/infra/abi/cp.go
new file mode 100644
index 000000000..9fc1e3bee
--- /dev/null
+++ b/pkg/domain/infra/abi/cp.go
@@ -0,0 +1,433 @@
+package abi
+
+import (
+ "archive/tar"
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/containers/buildah/pkg/chrootuser"
+ "github.com/containers/buildah/util"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/define"
+ "github.com/containers/libpod/pkg/domain/entities"
+ "github.com/containers/storage"
+ "github.com/containers/storage/pkg/chrootarchive"
+ "github.com/containers/storage/pkg/idtools"
+ securejoin "github.com/cyphar/filepath-securejoin"
+ "github.com/docker/docker/pkg/archive"
+ "github.com/opencontainers/go-digest"
+ "github.com/opencontainers/runtime-spec/specs-go"
+ "github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
+)
+
+func (ic *ContainerEngine) ContainerCp(ctx context.Context, source, dest string, options entities.ContainerCpOptions) (*entities.ContainerCpReport, error) {
+ var extract bool
+
+ srcCtr, srcPath := parsePath(ic.Libpod, source)
+ destCtr, destPath := parsePath(ic.Libpod, dest)
+
+ if (srcCtr == nil && destCtr == nil) || (srcCtr != nil && destCtr != nil) {
+ return nil, errors.Errorf("invalid arguments %s, %s you must use just one container", source, dest)
+ }
+
+ if len(srcPath) == 0 || len(destPath) == 0 {
+ return nil, errors.Errorf("invalid arguments %s, %s you must specify paths", source, dest)
+ }
+ ctr := srcCtr
+ isFromHostToCtr := ctr == nil
+ if isFromHostToCtr {
+ ctr = destCtr
+ }
+
+ mountPoint, err := ctr.Mount()
+ if err != nil {
+ return nil, err
+ }
+ defer func() {
+ if err := ctr.Unmount(false); err != nil {
+ logrus.Errorf("unable to umount container '%s': %q", ctr.ID(), err)
+ }
+ }()
+
+ if options.Pause {
+ if err := ctr.Pause(); err != nil {
+ // An invalid state error is fine.
+ // The container isn't running or is already paused.
+ // TODO: We can potentially start the container while
+ // the copy is running, which still allows a race where
+ // malicious code could mess with the symlink.
+ if errors.Cause(err) != define.ErrCtrStateInvalid {
+ return nil, err
+ }
+ } else {
+ // Only add the defer if we actually paused
+ defer func() {
+ if err := ctr.Unpause(); err != nil {
+ logrus.Errorf("Error unpausing container after copying: %v", err)
+ }
+ }()
+ }
+ }
+
+ user, err := getUser(mountPoint, ctr.User())
+ if err != nil {
+ return nil, err
+ }
+ idMappingOpts, err := ctr.IDMappings()
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting IDMappingOptions")
+ }
+ destOwner := idtools.IDPair{UID: int(user.UID), GID: int(user.GID)}
+ hostUID, hostGID, err := util.GetHostIDs(convertIDMap(idMappingOpts.UIDMap), convertIDMap(idMappingOpts.GIDMap), user.UID, user.GID)
+ if err != nil {
+ return nil, err
+ }
+
+ hostOwner := idtools.IDPair{UID: int(hostUID), GID: int(hostGID)}
+
+ if isFromHostToCtr {
+ if isVol, volDestName, volName := isVolumeDestName(destPath, ctr); isVol { //nolint(gocritic)
+ path, err := pathWithVolumeMount(ctr, ic.Libpod, volDestName, volName, destPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting destination path from volume %s", volDestName)
+ }
+ destPath = path
+ } else if isBindMount, mount := isBindMountDestName(destPath, ctr); isBindMount { //nolint(gocritic)
+ path, err := pathWithBindMountSource(mount, destPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting destination path from bind mount %s", mount.Destination)
+ }
+ destPath = path
+ } else if filepath.IsAbs(destPath) { //nolint(gocritic)
+ cleanedPath, err := securejoin.SecureJoin(mountPoint, destPath)
+ if err != nil {
+ return nil, err
+ }
+ destPath = cleanedPath
+ } else { //nolint(gocritic)
+ ctrWorkDir, err := securejoin.SecureJoin(mountPoint, ctr.WorkingDir())
+ if err != nil {
+ return nil, err
+ }
+ if err = idtools.MkdirAllAndChownNew(ctrWorkDir, 0755, hostOwner); err != nil {
+ return nil, errors.Wrapf(err, "error creating directory %q", destPath)
+ }
+ cleanedPath, err := securejoin.SecureJoin(mountPoint, filepath.Join(ctr.WorkingDir(), destPath))
+ if err != nil {
+ return nil, err
+ }
+ destPath = cleanedPath
+ }
+ } else {
+ destOwner = idtools.IDPair{UID: os.Getuid(), GID: os.Getgid()}
+ if isVol, volDestName, volName := isVolumeDestName(srcPath, ctr); isVol { //nolint(gocritic)
+ path, err := pathWithVolumeMount(ctr, ic.Libpod, volDestName, volName, srcPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting source path from volume %s", volDestName)
+ }
+ srcPath = path
+ } else if isBindMount, mount := isBindMountDestName(srcPath, ctr); isBindMount { //nolint(gocritic)
+ path, err := pathWithBindMountSource(mount, srcPath)
+ if err != nil {
+ return nil, errors.Wrapf(err, "error getting source path from bind mount %s", mount.Destination)
+ }
+ srcPath = path
+ } else if filepath.IsAbs(srcPath) { //nolint(gocritic)
+ cleanedPath, err := securejoin.SecureJoin(mountPoint, srcPath)
+ if err != nil {
+ return nil, err
+ }
+ srcPath = cleanedPath
+ } else { //nolint(gocritic)
+ cleanedPath, err := securejoin.SecureJoin(mountPoint, filepath.Join(ctr.WorkingDir(), srcPath))
+ if err != nil {
+ return nil, err
+ }
+ srcPath = cleanedPath
+ }
+ }
+
+ if !filepath.IsAbs(destPath) {
+ dir, err := os.Getwd()
+ if err != nil {
+ return nil, errors.Wrapf(err, "err getting current working directory")
+ }
+ destPath = filepath.Join(dir, destPath)
+ }
+
+ if source == "-" {
+ srcPath = os.Stdin.Name()
+ extract = true
+ }
+ err = containerCopy(srcPath, destPath, source, dest, idMappingOpts, &destOwner, extract, isFromHostToCtr)
+ return &entities.ContainerCpReport{}, err
+}
+
+func getUser(mountPoint string, userspec string) (specs.User, error) {
+ uid, gid, _, err := chrootuser.GetUser(mountPoint, userspec)
+ u := specs.User{
+ UID: uid,
+ GID: gid,
+ Username: userspec,
+ }
+ if !strings.Contains(userspec, ":") {
+ groups, err2 := chrootuser.GetAdditionalGroupsForUser(mountPoint, uint64(u.UID))
+ if err2 != nil {
+ if errors.Cause(err2) != chrootuser.ErrNoSuchUser && err == nil {
+ err = err2
+ }
+ } else {
+ u.AdditionalGids = groups
+ }
+
+ }
+ return u, err
+}
+
+func parsePath(runtime *libpod.Runtime, path string) (*libpod.Container, string) {
+ pathArr := strings.SplitN(path, ":", 2)
+ if len(pathArr) == 2 {
+ ctr, err := runtime.LookupContainer(pathArr[0])
+ if err == nil {
+ return ctr, pathArr[1]
+ }
+ }
+ return nil, path
+}
+
+func evalSymlinks(path string) (string, error) {
+ if path == os.Stdin.Name() {
+ return path, nil
+ }
+ return filepath.EvalSymlinks(path)
+}
+
+func getPathInfo(path string) (string, os.FileInfo, error) {
+ path, err := evalSymlinks(path)
+ if err != nil {
+ return "", nil, errors.Wrapf(err, "error evaluating symlinks %q", path)
+ }
+ srcfi, err := os.Stat(path)
+ if err != nil {
+ return "", nil, errors.Wrapf(err, "error reading path %q", path)
+ }
+ return path, srcfi, nil
+}
+
+func containerCopy(srcPath, destPath, src, dest string, idMappingOpts storage.IDMappingOptions, chownOpts *idtools.IDPair, extract, isFromHostToCtr bool) error {
+ srcPath, err := evalSymlinks(srcPath)
+ if err != nil {
+ return errors.Wrapf(err, "error evaluating symlinks %q", srcPath)
+ }
+
+ srcPath, srcfi, err := getPathInfo(srcPath)
+ if err != nil {
+ return err
+ }
+
+ filename := filepath.Base(destPath)
+ if filename == "-" && !isFromHostToCtr {
+ err := streamFileToStdout(srcPath, srcfi)
+ if err != nil {
+ return errors.Wrapf(err, "error streaming source file %s to Stdout", srcPath)
+ }
+ return nil
+ }
+
+ destdir := destPath
+ if !srcfi.IsDir() {
+ destdir = filepath.Dir(destPath)
+ }
+ _, err = os.Stat(destdir)
+ if err != nil && !os.IsNotExist(err) {
+ return errors.Wrapf(err, "error checking directory %q", destdir)
+ }
+ destDirIsExist := err == nil
+ if err = os.MkdirAll(destdir, 0755); err != nil {
+ return errors.Wrapf(err, "error creating directory %q", destdir)
+ }
+
+ // return functions for copying items
+ copyFileWithTar := chrootarchive.CopyFileWithTarAndChown(chownOpts, digest.Canonical.Digester().Hash(), idMappingOpts.UIDMap, idMappingOpts.GIDMap)
+ copyWithTar := chrootarchive.CopyWithTarAndChown(chownOpts, digest.Canonical.Digester().Hash(), idMappingOpts.UIDMap, idMappingOpts.GIDMap)
+ untarPath := chrootarchive.UntarPathAndChown(chownOpts, digest.Canonical.Digester().Hash(), idMappingOpts.UIDMap, idMappingOpts.GIDMap)
+
+ if srcfi.IsDir() {
+ logrus.Debugf("copying %q to %q", srcPath+string(os.PathSeparator)+"*", dest+string(os.PathSeparator)+"*")
+ if destDirIsExist && !strings.HasSuffix(src, fmt.Sprintf("%s.", string(os.PathSeparator))) {
+ destPath = filepath.Join(destPath, filepath.Base(srcPath))
+ }
+ if err = copyWithTar(srcPath, destPath); err != nil {
+ return errors.Wrapf(err, "error copying %q to %q", srcPath, dest)
+ }
+ return nil
+ }
+
+ if extract {
+ // We're extracting an archive into the destination directory.
+ logrus.Debugf("extracting contents of %q into %q", srcPath, destPath)
+ if err = untarPath(srcPath, destPath); err != nil {
+ return errors.Wrapf(err, "error extracting %q into %q", srcPath, destPath)
+ }
+ return nil
+ }
+
+ destfi, err := os.Stat(destPath)
+ if err != nil {
+ if !os.IsNotExist(err) || strings.HasSuffix(dest, string(os.PathSeparator)) {
+ return errors.Wrapf(err, "failed to get stat of dest path %s", destPath)
+ }
+ }
+ if destfi != nil && destfi.IsDir() {
+ destPath = filepath.Join(destPath, filepath.Base(srcPath))
+ }
+
+ // Copy the file, preserving attributes.
+ logrus.Debugf("copying %q to %q", srcPath, destPath)
+ if err = copyFileWithTar(srcPath, destPath); err != nil {
+ return errors.Wrapf(err, "error copying %q to %q", srcPath, destPath)
+ }
+ return nil
+}
+
+func convertIDMap(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping) {
+ for _, idmap := range idMaps {
+ tempIDMap := specs.LinuxIDMapping{
+ ContainerID: uint32(idmap.ContainerID),
+ HostID: uint32(idmap.HostID),
+ Size: uint32(idmap.Size),
+ }
+ convertedIDMap = append(convertedIDMap, tempIDMap)
+ }
+ return convertedIDMap
+}
+
+func streamFileToStdout(srcPath string, srcfi os.FileInfo) error {
+ if srcfi.IsDir() {
+ tw := tar.NewWriter(os.Stdout)
+ err := filepath.Walk(srcPath, func(path string, info os.FileInfo, err error) error {
+ if err != nil || !info.Mode().IsRegular() || path == srcPath {
+ return err
+ }
+ hdr, err := tar.FileInfoHeader(info, "")
+ if err != nil {
+ return err
+ }
+
+ if err = tw.WriteHeader(hdr); err != nil {
+ return err
+ }
+ fh, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+
+ _, err = io.Copy(tw, fh)
+ return err
+ })
+ if err != nil {
+ return errors.Wrapf(err, "error streaming directory %s to Stdout", srcPath)
+ }
+ return nil
+ }
+
+ file, err := os.Open(srcPath)
+ if err != nil {
+ return errors.Wrapf(err, "error opening file %s", srcPath)
+ }
+ defer file.Close()
+ if !archive.IsArchivePath(srcPath) {
+ tw := tar.NewWriter(os.Stdout)
+ hdr, err := tar.FileInfoHeader(srcfi, "")
+ if err != nil {
+ return err
+ }
+ err = tw.WriteHeader(hdr)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(tw, file)
+ if err != nil {
+ return errors.Wrapf(err, "error streaming archive %s to Stdout", srcPath)
+ }
+ return nil
+ }
+
+ _, err = io.Copy(os.Stdout, file)
+ if err != nil {
+ return errors.Wrapf(err, "error streaming file to Stdout")
+ }
+ return nil
+}
+
+func isVolumeDestName(path string, ctr *libpod.Container) (bool, string, string) {
+ separator := string(os.PathSeparator)
+ if filepath.IsAbs(path) {
+ path = strings.TrimPrefix(path, separator)
+ }
+ if path == "" {
+ return false, "", ""
+ }
+ for _, vol := range ctr.Config().NamedVolumes {
+ volNamePath := strings.TrimPrefix(vol.Dest, separator)
+ if matchVolumePath(path, volNamePath) {
+ return true, vol.Dest, vol.Name
+ }
+ }
+ return false, "", ""
+}
+
+// if SRCPATH or DESTPATH is from volume mount's destination -v or --mount type=volume, generates the path with volume mount point
+func pathWithVolumeMount(ctr *libpod.Container, runtime *libpod.Runtime, volDestName, volName, path string) (string, error) {
+ destVolume, err := runtime.GetVolume(volName)
+ if err != nil {
+ return "", errors.Wrapf(err, "error getting volume destination %s", volName)
+ }
+ if !filepath.IsAbs(path) {
+ path = filepath.Join(string(os.PathSeparator), path)
+ }
+ path, err = securejoin.SecureJoin(destVolume.MountPoint(), strings.TrimPrefix(path, volDestName))
+ return path, err
+}
+
+func isBindMountDestName(path string, ctr *libpod.Container) (bool, specs.Mount) {
+ separator := string(os.PathSeparator)
+ if filepath.IsAbs(path) {
+ path = strings.TrimPrefix(path, string(os.PathSeparator))
+ }
+ if path == "" {
+ return false, specs.Mount{}
+ }
+ for _, m := range ctr.Config().Spec.Mounts {
+ if m.Type != "bind" {
+ continue
+ }
+ mDest := strings.TrimPrefix(m.Destination, separator)
+ if matchVolumePath(path, mDest) {
+ return true, m
+ }
+ }
+ return false, specs.Mount{}
+}
+
+func matchVolumePath(path, target string) bool {
+ pathStr := filepath.Clean(path)
+ target = filepath.Clean(target)
+ for len(pathStr) > len(target) && strings.Contains(pathStr, string(os.PathSeparator)) {
+ pathStr = pathStr[:strings.LastIndex(pathStr, string(os.PathSeparator))]
+ }
+ return pathStr == target
+}
+
+func pathWithBindMountSource(m specs.Mount, path string) (string, error) {
+ if !filepath.IsAbs(path) {
+ path = filepath.Join(string(os.PathSeparator), path)
+ }
+ return securejoin.SecureJoin(m.Source, strings.TrimPrefix(path, m.Destination))
+}
diff --git a/pkg/domain/infra/abi/events.go b/pkg/domain/infra/abi/events.go
index 9540a5b96..20773cdce 100644
--- a/pkg/domain/infra/abi/events.go
+++ b/pkg/domain/infra/abi/events.go
@@ -1,5 +1,3 @@
-//+build ABISupport
-
package abi
import (
diff --git a/pkg/domain/infra/abi/healthcheck.go b/pkg/domain/infra/abi/healthcheck.go
index 699483243..351bf4f7e 100644
--- a/pkg/domain/infra/abi/healthcheck.go
+++ b/pkg/domain/infra/abi/healthcheck.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package abi
import (
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 0f710ad28..32f7d75e5 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package abi
import (
@@ -23,6 +21,7 @@ import (
domainUtils "github.com/containers/libpod/pkg/domain/utils"
"github.com/containers/libpod/pkg/util"
"github.com/containers/storage"
+ "github.com/hashicorp/go-multierror"
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -36,76 +35,6 @@ func (ir *ImageEngine) Exists(_ context.Context, nameOrId string) (*entities.Boo
return &entities.BoolReport{Value: err == nil}, nil
}
-func (ir *ImageEngine) Delete(ctx context.Context, nameOrId []string, opts entities.ImageDeleteOptions) (*entities.ImageDeleteReport, error) {
- report := entities.ImageDeleteReport{}
-
- if opts.All {
- var previousTargets []*libpodImage.Image
- repeatRun:
- targets, err := ir.Libpod.ImageRuntime().GetRWImages()
- if err != nil {
- return &report, errors.Wrapf(err, "unable to query local images")
- }
- if len(targets) == 0 {
- return &report, nil
- }
- if len(targets) > 0 && len(targets) == len(previousTargets) {
- return &report, errors.New("unable to delete all images; re-run the rmi command again.")
- }
- previousTargets = targets
-
- for _, img := range targets {
- isParent, err := img.IsParent(ctx)
- if err != nil {
- return &report, err
- }
- if isParent {
- continue
- }
- err = ir.deleteImage(ctx, img, opts, report)
- report.Errors = append(report.Errors, err)
- }
- if len(previousTargets) != 1 {
- goto repeatRun
- }
- return &report, nil
- }
-
- for _, id := range nameOrId {
- image, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
- if err != nil {
- return nil, err
- }
-
- err = ir.deleteImage(ctx, image, opts, report)
- if err != nil {
- return &report, err
- }
- }
- return &report, nil
-}
-
-func (ir *ImageEngine) deleteImage(ctx context.Context, img *libpodImage.Image, opts entities.ImageDeleteOptions, report entities.ImageDeleteReport) error {
- results, err := ir.Libpod.RemoveImage(ctx, img, opts.Force)
- switch errors.Cause(err) {
- case nil:
- break
- case storage.ErrImageUsedByContainer:
- report.ImageInUse = errors.New(
- fmt.Sprintf("A container associated with containers/storage, i.e. via Buildah, CRI-O, etc., may be associated with this image: %-12.12s\n", img.ID()))
- return nil
- case libpodImage.ErrNoSuchImage:
- report.ImageNotFound = err
- return nil
- default:
- return err
- }
-
- report.Deleted = append(report.Deleted, results.Deleted)
- report.Untagged = append(report.Untagged, results.Untagged...)
- return nil
-}
-
func (ir *ImageEngine) Prune(ctx context.Context, opts entities.ImagePruneOptions) (*entities.ImagePruneReport, error) {
results, err := ir.Libpod.ImageRuntime().PruneImages(ctx, opts.All, opts.Filter)
if err != nil {
@@ -476,3 +405,147 @@ func (ir *ImageEngine) Build(ctx context.Context, containerFiles []string, opts
}
return &entities.BuildReport{ID: id}, nil
}
+
+func (ir *ImageEngine) Tree(ctx context.Context, nameOrId string, opts entities.ImageTreeOptions) (*entities.ImageTreeReport, error) {
+ img, err := ir.Libpod.ImageRuntime().NewFromLocal(nameOrId)
+ if err != nil {
+ return nil, err
+ }
+ results, err := img.GenerateTree(opts.WhatRequires)
+ if err != nil {
+ return nil, err
+ }
+ return &entities.ImageTreeReport{Tree: results}, nil
+}
+
+// Remove removes one or more images from local storage.
+func (ir *ImageEngine) Remove(ctx context.Context, images []string, opts entities.ImageRemoveOptions) (report *entities.ImageRemoveReport, finalError error) {
+ var (
+ // noSuchImageErrors indicates that at least one image was not found.
+ noSuchImageErrors bool
+ // inUseErrors indicates that at least one image is being used by a
+ // container.
+ inUseErrors bool
+ // otherErrors indicates that at least one error other than the two
+ // above occured.
+ otherErrors bool
+ // deleteError is a multierror to conveniently collect errors during
+ // removal. We really want to delete as many images as possible and not
+ // error out immediately.
+ deleteError *multierror.Error
+ )
+
+ report = &entities.ImageRemoveReport{}
+
+ // Set the removalCode and the error after all work is done.
+ defer func() {
+ switch {
+ // 2
+ case inUseErrors:
+ // One of the specified images has child images or is
+ // being used by a container.
+ report.ExitCode = 2
+ // 1
+ case noSuchImageErrors && !(otherErrors || inUseErrors):
+ // One of the specified images did not exist, and no other
+ // failures.
+ report.ExitCode = 1
+ // 0
+ default:
+ // Nothing to do.
+ }
+ if deleteError != nil {
+ // go-multierror has a trailing new line which we need to remove to normalize the string.
+ finalError = deleteError.ErrorOrNil()
+ finalError = errors.New(strings.TrimSpace(finalError.Error()))
+ }
+ }()
+
+ // deleteImage is an anonymous function to conveniently delete an image
+ // withouth having to pass all local data around.
+ deleteImage := func(img *image.Image) error {
+ results, err := ir.Libpod.RemoveImage(ctx, img, opts.Force)
+ switch errors.Cause(err) {
+ case nil:
+ break
+ case storage.ErrImageUsedByContainer:
+ inUseErrors = true // Important for exit codes in Podman.
+ return errors.New(
+ fmt.Sprintf("A container associated with containers/storage, i.e. via Buildah, CRI-O, etc., may be associated with this image: %-12.12s\n", img.ID()))
+ default:
+ otherErrors = true // Important for exit codes in Podman.
+ return err
+ }
+
+ report.Deleted = append(report.Deleted, results.Deleted)
+ report.Untagged = append(report.Untagged, results.Untagged...)
+ return nil
+ }
+
+ // Delete all images from the local storage.
+ if opts.All {
+ previousImages := 0
+ // Remove all images one-by-one.
+ for {
+ storageImages, err := ir.Libpod.ImageRuntime().GetRWImages()
+ if err != nil {
+ deleteError = multierror.Append(deleteError,
+ errors.Wrapf(err, "unable to query local images"))
+ otherErrors = true // Important for exit codes in Podman.
+ return
+ }
+ // No images (left) to remove, so we're done.
+ if len(storageImages) == 0 {
+ return
+ }
+ // Prevent infinity loops by making a delete-progress check.
+ if previousImages == len(storageImages) {
+ otherErrors = true // Important for exit codes in Podman.
+ deleteError = multierror.Append(deleteError,
+ errors.New("unable to delete all images, check errors and re-run image removal if needed"))
+ break
+ }
+ previousImages = len(storageImages)
+ // Delete all "leaves" (i.e., images without child images).
+ for _, img := range storageImages {
+ isParent, err := img.IsParent(ctx)
+ if err != nil {
+ otherErrors = true // Important for exit codes in Podman.
+ deleteError = multierror.Append(deleteError, err)
+ }
+ // Skip parent images.
+ if isParent {
+ continue
+ }
+ if err := deleteImage(img); err != nil {
+ deleteError = multierror.Append(deleteError, err)
+ }
+ }
+ }
+
+ return
+ }
+
+ // Delete only the specified images.
+ for _, id := range images {
+ img, err := ir.Libpod.ImageRuntime().NewFromLocal(id)
+ switch errors.Cause(err) {
+ case nil:
+ break
+ case image.ErrNoSuchImage:
+ noSuchImageErrors = true // Important for exit codes in Podman.
+ fallthrough
+ default:
+ deleteError = multierror.Append(deleteError, err)
+ continue
+ }
+
+ err = deleteImage(img)
+ if err != nil {
+ otherErrors = true // Important for exit codes in Podman.
+ deleteError = multierror.Append(deleteError, err)
+ }
+ }
+
+ return
+}
diff --git a/pkg/domain/infra/abi/images_list.go b/pkg/domain/infra/abi/images_list.go
index 68b961cb6..9add915ea 100644
--- a/pkg/domain/infra/abi/images_list.go
+++ b/pkg/domain/infra/abi/images_list.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package abi
import (
diff --git a/pkg/domain/infra/abi/pods.go b/pkg/domain/infra/abi/pods.go
index 6b6e13e24..c4ae9efbf 100644
--- a/pkg/domain/infra/abi/pods.go
+++ b/pkg/domain/infra/abi/pods.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package abi
import (
diff --git a/pkg/domain/infra/abi/runtime.go b/pkg/domain/infra/abi/runtime.go
index b53fb6d3a..7394cadfc 100644
--- a/pkg/domain/infra/abi/runtime.go
+++ b/pkg/domain/infra/abi/runtime.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package abi
import (
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 078f5404d..e5c109ee6 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -1,20 +1,15 @@
-// +build ABISupport
-
package abi
import (
"context"
"fmt"
"io/ioutil"
- "net"
"os"
"strconv"
- "strings"
"syscall"
"github.com/containers/common/pkg/config"
"github.com/containers/libpod/libpod/define"
- api "github.com/containers/libpod/pkg/api/server"
"github.com/containers/libpod/pkg/cgroups"
"github.com/containers/libpod/pkg/domain/entities"
"github.com/containers/libpod/pkg/rootless"
@@ -33,42 +28,6 @@ func (ic *ContainerEngine) Info(ctx context.Context) (*define.Info, error) {
return ic.Libpod.Info()
}
-func (ic *ContainerEngine) RestService(_ context.Context, opts entities.ServiceOptions) error {
- var (
- listener *net.Listener
- err error
- )
-
- if opts.URI != "" {
- fields := strings.Split(opts.URI, ":")
- if len(fields) == 1 {
- return errors.Errorf("%s is an invalid socket destination", opts.URI)
- }
- address := strings.Join(fields[1:], ":")
- l, err := net.Listen(fields[0], address)
- if err != nil {
- return errors.Wrapf(err, "unable to create socket %s", opts.URI)
- }
- listener = &l
- }
-
- server, err := api.NewServerWithSettings(ic.Libpod, opts.Timeout, listener)
- if err != nil {
- return err
- }
- defer func() {
- if err := server.Shutdown(); err != nil {
- logrus.Warnf("Error when stopping API service: %s", err)
- }
- }()
-
- err = server.Serve()
- if listener != nil {
- _ = (*listener).Close()
- }
- return err
-}
-
func (ic *ContainerEngine) VarlinkService(_ context.Context, opts entities.ServiceOptions) error {
var varlinkInterfaces = []*iopodman.VarlinkInterface{
iopodmanAPI.New(opts.Command, ic.Libpod),
diff --git a/pkg/domain/infra/abi/terminal/sigproxy_linux.go b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
index d7f5853d8..b422e549e 100644
--- a/pkg/domain/infra/abi/terminal/sigproxy_linux.go
+++ b/pkg/domain/infra/abi/terminal/sigproxy_linux.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package terminal
import (
diff --git a/pkg/domain/infra/abi/terminal/terminal.go b/pkg/domain/infra/abi/terminal/terminal.go
index f187bdd6b..0fc3af511 100644
--- a/pkg/domain/infra/abi/terminal/terminal.go
+++ b/pkg/domain/infra/abi/terminal/terminal.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package terminal
import (
diff --git a/pkg/domain/infra/abi/terminal/terminal_linux.go b/pkg/domain/infra/abi/terminal/terminal_linux.go
index 664205df1..15701342f 100644
--- a/pkg/domain/infra/abi/terminal/terminal_linux.go
+++ b/pkg/domain/infra/abi/terminal/terminal_linux.go
@@ -1,5 +1,3 @@
-// +build ABISupport
-
package terminal
import (