summaryrefslogtreecommitdiff
path: root/pkg
diff options
context:
space:
mode:
Diffstat (limited to 'pkg')
-rw-r--r--pkg/domain/entities/engine_image.go1
-rw-r--r--pkg/domain/entities/images.go4
-rw-r--r--pkg/domain/infra/abi/images.go65
-rw-r--r--pkg/domain/infra/tunnel/images.go5
4 files changed, 75 insertions, 0 deletions
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go
index b0f9ae408..d72f64b5e 100644
--- a/pkg/domain/entities/engine_image.go
+++ b/pkg/domain/entities/engine_image.go
@@ -27,6 +27,7 @@ type ImageEngine interface {
ShowTrust(ctx context.Context, args []string, options ShowTrustOptions) (*ShowTrustReport, error)
Shutdown(ctx context.Context)
Tag(ctx context.Context, nameOrID string, tags []string, options ImageTagOptions) error
+ Transfer(ctx context.Context, scpOpts ImageScpOptions) error
Tree(ctx context.Context, nameOrID string, options ImageTreeOptions) (*ImageTreeReport, error)
Unmount(ctx context.Context, images []string, options ImageUnmountOptions) ([]*ImageUnmountReport, error)
Untag(ctx context.Context, nameOrID string, tags []string, options ImageUntagOptions) error
diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go
index ac5e6f410..7ac07a8b3 100644
--- a/pkg/domain/entities/images.go
+++ b/pkg/domain/entities/images.go
@@ -328,6 +328,10 @@ type ImageScpOptions struct {
Save ImageSaveOptions
// Load options used for the second half of the scp operation
Load ImageLoadOptions
+ // Rootless determines whether we are loading locally from root storage to rootless storage
+ Rootless bool
+ // User is used in conjunction with Rootless to determine which user to use to obtain the uid
+ User string
}
// ImageTreeOptions provides options for ImageEngine.Tree()
diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go
index 8878bf128..e9528acf1 100644
--- a/pkg/domain/infra/abi/images.go
+++ b/pkg/domain/infra/abi/images.go
@@ -6,9 +6,12 @@ import (
"io/ioutil"
"net/url"
"os"
+ "os/exec"
+ "os/user"
"path"
"path/filepath"
"strconv"
+ "strings"
"github.com/containers/common/libimage"
"github.com/containers/common/pkg/config"
@@ -18,6 +21,7 @@ import (
"github.com/containers/image/v5/signature"
"github.com/containers/image/v5/transports"
"github.com/containers/image/v5/transports/alltransports"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
domainUtils "github.com/containers/podman/v3/pkg/domain/utils"
@@ -330,6 +334,67 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri
return pushError
}
+// Transfer moves images from root to rootless storage so the user specified in the scp call can access and use the image modified by root
+func (ir *ImageEngine) Transfer(ctx context.Context, scpOpts entities.ImageScpOptions) error {
+ if scpOpts.User == "" {
+ return errors.Wrapf(define.ErrInvalidArg, "you must define a user when transferring from root to rootless storage")
+ }
+ var u *user.User
+ scpOpts.User = strings.Split(scpOpts.User, ":")[0] // split in case provided with uid:gid
+ _, err := strconv.Atoi(scpOpts.User)
+ if err != nil {
+ u, err = user.Lookup(scpOpts.User)
+ if err != nil {
+ return err
+ }
+ } else {
+ u, err = user.LookupId(scpOpts.User)
+ if err != nil {
+ return err
+ }
+ }
+ uid, err := strconv.Atoi(u.Uid)
+ if err != nil {
+ return err
+ }
+ gid, err := strconv.Atoi(u.Gid)
+ if err != nil {
+ return err
+ }
+ err = os.Chown(scpOpts.Save.Output, uid, gid) // chown the output because was created by root so we need to give th euser read access
+ if err != nil {
+ return err
+ }
+
+ podman, err := os.Executable()
+ if err != nil {
+ return err
+ }
+ machinectl, err := exec.LookPath("machinectl")
+ if err != nil {
+ logrus.Warn("defaulting to su since machinectl is not available, su will fail if no user session is available")
+ cmd := exec.Command("su", "-l", u.Username, "--command", podman+" --log-level="+logrus.GetLevel().String()+" --cgroup-manager=cgroupfs load --input="+scpOpts.Save.Output) // load the new image to the rootless storage
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = os.Stdout
+ logrus.Debug("Executing load command su")
+ err = cmd.Run()
+ if err != nil {
+ return err
+ }
+ } else {
+ cmd := exec.Command(machinectl, "shell", "-q", u.Username+"@.host", podman, "--log-level="+logrus.GetLevel().String(), "--cgroup-manager=cgroupfs", "load", "--input", scpOpts.Save.Output) // load the new image to the rootless storage
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = os.Stdout
+ logrus.Debug("Executing load command machinectl")
+ err = cmd.Run()
+ if err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, options entities.ImageTagOptions) error {
// Allow tagging manifest list instead of resolving instances from manifest
lookupOptions := &libimage.LookupImageOptions{ManifestList: true}
diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go
index b8af2de68..ed0c35de4 100644
--- a/pkg/domain/infra/tunnel/images.go
+++ b/pkg/domain/infra/tunnel/images.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/common/pkg/config"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
+ "github.com/containers/podman/v3/libpod/define"
"github.com/containers/podman/v3/pkg/bindings/images"
"github.com/containers/podman/v3/pkg/domain/entities"
"github.com/containers/podman/v3/pkg/domain/entities/reports"
@@ -122,6 +123,10 @@ func (ir *ImageEngine) Pull(ctx context.Context, rawImage string, opts entities.
return &entities.ImagePullReport{Images: pulledImages}, nil
}
+func (ir *ImageEngine) Transfer(ctx context.Context, scpOpts entities.ImageScpOptions) error {
+ return errors.Wrapf(define.ErrNotImplemented, "cannot use the remote client to transfer images between root and rootless storage")
+}
+
func (ir *ImageEngine) Tag(ctx context.Context, nameOrID string, tags []string, opt entities.ImageTagOptions) error {
options := new(images.TagOptions)
for _, newTag := range tags {