diff options
Diffstat (limited to 'pkg')
-rw-r--r-- | pkg/domain/entities/engine_image.go | 2 | ||||
-rw-r--r-- | pkg/domain/entities/images.go | 30 | ||||
-rw-r--r-- | pkg/domain/infra/abi/images.go | 126 | ||||
-rw-r--r-- | pkg/domain/infra/tunnel/images.go | 8 | ||||
-rw-r--r-- | pkg/rootless/rootless_linux.c | 3 |
5 files changed, 163 insertions, 6 deletions
diff --git a/pkg/domain/entities/engine_image.go b/pkg/domain/entities/engine_image.go index 7ece24c60..594f9617f 100644 --- a/pkg/domain/entities/engine_image.go +++ b/pkg/domain/entities/engine_image.go @@ -16,6 +16,7 @@ type ImageEngine interface { Inspect(ctx context.Context, namesOrIDs []string, opts InspectOptions) ([]*ImageInspectReport, []error, error) List(ctx context.Context, opts ImageListOptions) ([]*ImageSummary, error) Load(ctx context.Context, opts ImageLoadOptions) (*ImageLoadReport, error) + Mount(ctx context.Context, images []string, options ImageMountOptions) ([]*ImageMountReport, error) Prune(ctx context.Context, opts ImagePruneOptions) (*ImagePruneReport, error) Pull(ctx context.Context, rawImage string, opts ImagePullOptions) (*ImagePullReport, error) Push(ctx context.Context, source string, destination string, opts ImagePushOptions) error @@ -27,6 +28,7 @@ type ImageEngine interface { Shutdown(ctx context.Context) Tag(ctx context.Context, nameOrID string, tags []string, options ImageTagOptions) 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 ManifestCreate(ctx context.Context, names, images []string, opts ManifestCreateOptions) (string, error) ManifestInspect(ctx context.Context, name string) ([]byte, error) diff --git a/pkg/domain/entities/images.go b/pkg/domain/entities/images.go index b38facfb5..cb970b09a 100644 --- a/pkg/domain/entities/images.go +++ b/pkg/domain/entities/images.go @@ -91,7 +91,7 @@ type ImageRemoveOptions struct { } // ImageRemoveResponse is the response for removing one or more image(s) from storage -// and containers what was untagged vs actually removed. +// and images what was untagged vs actually removed. type ImageRemoveReport struct { // Deleted images. Deleted []string `json:",omitempty"` @@ -318,3 +318,31 @@ type SignOptions struct { // SignReport describes the result of signing type SignReport struct{} + +// ImageMountOptions describes the input values for mounting images +// in the CLI +type ImageMountOptions struct { + All bool + Format string +} + +// ImageUnmountOptions are the options from the cli for unmounting +type ImageUnmountOptions struct { + All bool + Force bool +} + +// ImageMountReport describes the response from image mount +type ImageMountReport struct { + Err error + Id string //nolint + Name string + Repositories []string + Path string +} + +// ImageUnmountReport describes the response from umounting an image +type ImageUnmountReport struct { + Err error + Id string //nolint +} diff --git a/pkg/domain/infra/abi/images.go b/pkg/domain/infra/abi/images.go index e2fe8a5e6..10ec7f8f3 100644 --- a/pkg/domain/infra/abi/images.go +++ b/pkg/domain/infra/abi/images.go @@ -11,8 +11,6 @@ import ( "strconv" "strings" - "github.com/containers/podman/v2/pkg/rootless" - "github.com/containers/common/pkg/config" "github.com/containers/image/v5/docker" dockerarchive "github.com/containers/image/v5/docker/archive" @@ -27,6 +25,7 @@ import ( libpodImage "github.com/containers/podman/v2/libpod/image" "github.com/containers/podman/v2/pkg/domain/entities" domainUtils "github.com/containers/podman/v2/pkg/domain/utils" + "github.com/containers/podman/v2/pkg/rootless" "github.com/containers/podman/v2/pkg/trust" "github.com/containers/podman/v2/pkg/util" "github.com/containers/storage" @@ -85,6 +84,125 @@ func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entiti return &history, nil } +func (ir *ImageEngine) Mount(ctx context.Context, nameOrIDs []string, opts entities.ImageMountOptions) ([]*entities.ImageMountReport, error) { + var ( + images []*image.Image + err error + ) + if os.Geteuid() != 0 { + if driver := ir.Libpod.StorageConfig().GraphDriverName; driver != "vfs" { + // Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part + // of the mount command. + return nil, errors.Errorf("cannot mount using driver %s in rootless mode", driver) + } + + became, ret, err := rootless.BecomeRootInUserNS("") + if err != nil { + return nil, err + } + if became { + os.Exit(ret) + } + } + if opts.All { + allImages, err := ir.Libpod.ImageRuntime().GetImages() + if err != nil { + return nil, err + } + for _, img := range allImages { + if !img.IsReadOnly() { + images = append(images, img) + } + } + } else { + for _, i := range nameOrIDs { + img, err := ir.Libpod.ImageRuntime().NewFromLocal(i) + if err != nil { + return nil, err + } + images = append(images, img) + } + } + reports := make([]*entities.ImageMountReport, 0, len(images)) + for _, img := range images { + report := entities.ImageMountReport{Id: img.ID()} + if img.IsReadOnly() { + report.Err = errors.Errorf("mounting readonly %s image not supported", img.ID()) + } else { + report.Path, report.Err = img.Mount([]string{}, "") + } + reports = append(reports, &report) + } + if len(reports) > 0 { + return reports, nil + } + + images, err = ir.Libpod.ImageRuntime().GetImages() + if err != nil { + return nil, err + } + for _, i := range images { + mounted, path, err := i.Mounted() + if err != nil { + if errors.Cause(err) == storage.ErrLayerUnknown { + continue + } + return nil, err + } + if mounted { + tags, err := i.RepoTags() + if err != nil { + return nil, err + } + reports = append(reports, &entities.ImageMountReport{ + Id: i.ID(), + Name: string(i.Digest()), + Repositories: tags, + Path: path, + }) + } + } + return reports, nil +} + +func (ir *ImageEngine) Unmount(ctx context.Context, nameOrIDs []string, options entities.ImageUnmountOptions) ([]*entities.ImageUnmountReport, error) { + var images []*image.Image + + if options.All { + allImages, err := ir.Libpod.ImageRuntime().GetImages() + if err != nil { + return nil, err + } + for _, img := range allImages { + if !img.IsReadOnly() { + images = append(images, img) + } + } + } else { + for _, i := range nameOrIDs { + img, err := ir.Libpod.ImageRuntime().NewFromLocal(i) + if err != nil { + return nil, err + } + images = append(images, img) + } + } + + reports := []*entities.ImageUnmountReport{} + for _, img := range images { + report := entities.ImageUnmountReport{Id: img.ID()} + if err := img.Unmount(options.Force); err != nil { + if options.All && errors.Cause(err) == storage.ErrLayerNotMounted { + logrus.Debugf("Error umounting image %s, storage.ErrLayerNotMounted", img.ID()) + continue + } + report.Err = errors.Wrapf(err, "error unmounting image %s", img.ID()) + } + reports = append(reports, &report) + } + return reports, nil +} + func ToDomainHistoryLayer(layer *libpodImage.History) entities.ImageHistoryLayer { l := entities.ImageHistoryLayer{} l.ID = layer.ID @@ -225,7 +343,7 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri case "v2s2", "docker": manifestType = manifest.DockerV2Schema2MediaType default: - return fmt.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", options.Format) + return errors.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", options.Format) } var registryCreds *types.DockerAuthConfig @@ -292,7 +410,7 @@ func (ir *ImageEngine) Push(ctx context.Context, source string, destination stri // // // TODO: Determine Size // report := entities.ImagePruneReport{} -// copy(report.Report.Id, id) +// copy(report.Report.ID, id) // return &report, nil // } diff --git a/pkg/domain/infra/tunnel/images.go b/pkg/domain/infra/tunnel/images.go index 6407724b5..6845d01c0 100644 --- a/pkg/domain/infra/tunnel/images.go +++ b/pkg/domain/infra/tunnel/images.go @@ -54,6 +54,14 @@ func (ir *ImageEngine) List(ctx context.Context, opts entities.ImageListOptions) return is, nil } +func (ir *ImageEngine) Mount(ctx context.Context, images []string, options entities.ImageMountOptions) ([]*entities.ImageMountReport, error) { + return nil, errors.New("mounting images is not supported for remote clients") +} + +func (ir *ImageEngine) Unmount(ctx context.Context, images []string, options entities.ImageUnmountOptions) ([]*entities.ImageUnmountReport, error) { + return nil, errors.New("unmounting images is not supported for remote clients") +} + func (ir *ImageEngine) History(ctx context.Context, nameOrID string, opts entities.ImageHistoryOptions) (*entities.ImageHistoryReport, error) { results, err := images.History(ir.ClientCxt, nameOrID) if err != nil { diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c index 8e0151496..d3e43e44d 100644 --- a/pkg/rootless/rootless_linux.c +++ b/pkg/rootless/rootless_linux.c @@ -211,7 +211,8 @@ can_use_shortcut () break; } - if (argv[argc+1] != NULL && strcmp (argv[argc], "container") == 0 && + if (argv[argc+1] != NULL && (strcmp (argv[argc], "container") == 0 || + strcmp (argv[argc], "image") == 0) && strcmp (argv[argc+1], "mount") == 0) { ret = false; |