Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scp: add option types #24240

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion cmd/podman/images/scp.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"github.com/containers/common/pkg/ssh"
"github.com/containers/podman/v5/cmd/podman/common"
"github.com/containers/podman/v5/cmd/podman/registry"
"github.com/containers/podman/v5/pkg/domain/entities"
"github.com/spf13/cobra"
)

Expand Down Expand Up @@ -73,7 +74,11 @@ func scp(cmd *cobra.Command, args []string) (finalErr error) {
}

sshEngine := ssh.DefineMode(sshType)
err = registry.ImageEngine().Scp(registry.Context(), src, dst, parentFlags, quiet, sshEngine)
scpOpts := entities.ImageScpOptions{}
scpOpts.ParentFlags = parentFlags
scpOpts.Quiet = quiet
scpOpts.SSHMode = sshEngine
_, err = registry.ImageEngine().Scp(registry.Context(), src, dst, scpOpts)
if err != nil {
return err
}
Expand Down
10 changes: 7 additions & 3 deletions pkg/api/handlers/libpod/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -713,18 +713,22 @@ func ImageScp(w http.ResponseWriter, r *http.Request) {

sourceArg := utils.GetName(r)

rep, source, dest, _, err := domainUtils.ExecuteTransfer(sourceArg, query.Destination, []string{}, query.Quiet, ssh.GolangMode)
opts := entities.ScpExecuteTransferOptions{}
opts.ParentFlags = []string{}
opts.Quiet = query.Quiet
opts.SSHMode = ssh.GolangMode
report, err := domainUtils.ExecuteTransfer(sourceArg, query.Destination, opts)
if err != nil {
utils.Error(w, http.StatusInternalServerError, err)
return
}

if source != nil || dest != nil {
if report.Source != nil || report.Dest != nil {
utils.Error(w, http.StatusBadRequest, fmt.Errorf("cannot use the user transfer function on the remote client: %w", define.ErrInvalidArg))
return
}

utils.WriteResponse(w, http.StatusOK, &reports.ScpReport{Id: rep.Names[0]})
utils.WriteResponse(w, http.StatusOK, &reports.ScpReport{Id: report.LoadReport.Names[0]})
}

// Resolve the passed (short) name to one more candidates it may resolve to.
Expand Down
3 changes: 1 addition & 2 deletions pkg/domain/entities/engine_image.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (

"github.com/containers/common/libimage/define"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/ssh"
"github.com/containers/podman/v5/pkg/domain/entities/reports"
)

Expand All @@ -24,7 +23,7 @@ type ImageEngine interface { //nolint:interfacebloat
Push(ctx context.Context, source string, destination string, opts ImagePushOptions) (*ImagePushReport, error)
Remove(ctx context.Context, images []string, opts ImageRemoveOptions) (*ImageRemoveReport, []error)
Save(ctx context.Context, nameOrID string, tags []string, options ImageSaveOptions) error
Scp(ctx context.Context, src, dst string, parentFlags []string, quiet bool, sshMode ssh.EngineMode) error
Scp(ctx context.Context, src, dst string, opts ImageScpOptions) (*ImageScpReport, error)
Search(ctx context.Context, term string, opts ImageSearchOptions) ([]ImageSearchReport, error)
SetTrust(ctx context.Context, args []string, options SetTrustOptions) error
ShowTrust(ctx context.Context, args []string, options ShowTrustOptions) (*ShowTrustReport, error)
Expand Down
18 changes: 5 additions & 13 deletions pkg/domain/entities/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -305,22 +305,14 @@ type ImageSaveOptions struct {
SignaturePolicy string
}

// ImageScpOptions provide options for securely copying images to and from a remote host
// ImageScpOptions provides options for ImageEngine.Scp()
type ImageScpOptions struct {
// Remote determines if this entity is operating on a remote machine
Remote bool `json:"remote,omitempty"`
// File is the input/output file for the save and load Operation
File string `json:"file,omitempty"`
// Quiet Determines if the save and load operation will be done quietly
Quiet bool `json:"quiet,omitempty"`
// Image is the image the user is providing to save and load
Image string `json:"image,omitempty"`
// User is used in conjunction with Transfer to determine if a valid user was given to save from/load into
User string `json:"user,omitempty"`
// Tag is the name to be used for the image on the destination
Tag string `json:"tag,omitempty"`
ScpExecuteTransferOptions
}

// ImageScpReport provides results from ImageEngine.Scp()
type ImageScpReport struct{}

// ImageScpConnections provides the ssh related information used in remote image transfer
type ImageScpConnections struct {
// Connections holds the raw string values for connections (ssh or unix)
Expand Down
90 changes: 90 additions & 0 deletions pkg/domain/entities/scp.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
package entities

import (
"net/url"

"github.com/containers/common/pkg/ssh"
)

// ScpTransferImageOptions provide options for securely copying images to and from a remote host
type ScpTransferImageOptions struct {
// Remote determines if this entity is operating on a remote machine
Remote bool `json:"remote,omitempty"`
// File is the input/output file for the save and load Operation
File string `json:"file,omitempty"`
// Quiet Determines if the save and load operation will be done quietly
Quiet bool `json:"quiet,omitempty"`
// Image is the image the user is providing to save and load
Image string `json:"image,omitempty"`
// User is used in conjunction with Transfer to determine if a valid user was given to save from/load into
User string `json:"user,omitempty"`
// Tag is the name to be used for the image on the destination
Tag string `json:"tag,omitempty"`
}

type ScpLoadReport = ImageLoadReport

type ScpExecuteTransferOptions struct {
// ParentFlags are the arguments to apply to the parent podman command when called via ssh
ParentFlags []string
// Quiet Determines if the save and load operation will be done quietly
Quiet bool
// SSHMode is the specified ssh.EngineMode which should be used
SSHMode ssh.EngineMode
}

type ScpExecuteTransferReport struct {
// LoadReport provides results from calling podman load
LoadReport *ScpLoadReport
// Source contains data relating to the source of the image to transfer
Source *ScpTransferImageOptions
// Dest contains data relating to the destination of the image to transfer
Dest *ScpTransferImageOptions
// ParentFlags are the arguments to apply to the parent podman command when called via ssh
ParentFlags []string
}

type ScpLoadToRemoteOptions struct {
// Dest contains data relating to the destination of the image to transfer
Dest ScpTransferImageOptions
// LocalFile is a path to a local file containing saved image data to transfer
LocalFile string
// Tag is the name of the tag to be given to the loaded image (unused)
Tag string
// URL points to the remote location for loading to
URL *url.URL
// Iden is a path to an optional identity file with ssh key
Iden string
// SSHMode is the specified ssh.EngineMode which should be used
SSHMode ssh.EngineMode
}

type ScpLoadToRemoteReport struct {
// Response contains any additional information from the executed load command
Response string
// ID is the identifier of the loaded image
ID string
}

type ScpSaveToRemoteOptions struct {
Image string
// LocalFile is a path to a local file to copy the saved image to
LocalFile string
// Tag is the name of the tag to be given to the saved image (unused)
Tag string
// URL points to the remote location for saving from
URL *url.URL
// Iden is a path to an optional identity file with ssh key
Iden string
// SSHMode is the specified ssh.EngineMode which should be used
SSHMode ssh.EngineMode
}

type ScpSaveToRemoteReport struct{}

type ScpCreateCommandsOptions struct {
// ParentFlags are the arguments to apply to the parent podman command when called via ssh
ParentFlags []string
// Podman is the path to the local podman executable
Podman string
}
21 changes: 10 additions & 11 deletions pkg/domain/infra/abi/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ import (
"github.com/containers/common/libimage"
"github.com/containers/common/libimage/filter"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/ssh"
"github.com/containers/image/v5/docker"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/manifest"
Expand Down Expand Up @@ -772,21 +771,21 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
return nil, nil
}

func (ir *ImageEngine) Scp(ctx context.Context, src, dst string, parentFlags []string, quiet bool, sshMode ssh.EngineMode) error {
rep, source, dest, flags, err := domainUtils.ExecuteTransfer(src, dst, parentFlags, quiet, sshMode)
func (ir *ImageEngine) Scp(ctx context.Context, src, dst string, opts entities.ImageScpOptions) (*entities.ImageScpReport, error) {
report, err := domainUtils.ExecuteTransfer(src, dst, opts.ScpExecuteTransferOptions)
if err != nil {
return err
return nil, err
}
if (rep == nil && err == nil) && (source != nil && dest != nil) { // we need to execute the transfer
err := Transfer(ctx, *source, *dest, flags)
if (report.LoadReport == nil && err == nil) && (report.Source != nil && report.Dest != nil) { // we need to execute the transfer
err := Transfer(ctx, *report.Source, *report.Dest, report.ParentFlags)
if err != nil {
return err
return nil, err
}
}
return nil
return &entities.ImageScpReport{}, nil
}

func Transfer(ctx context.Context, source entities.ImageScpOptions, dest entities.ImageScpOptions, parentFlags []string) error {
func Transfer(ctx context.Context, source entities.ScpTransferImageOptions, dest entities.ScpTransferImageOptions, parentFlags []string) error {
if source.User == "" {
return fmt.Errorf("you must define a user when transferring from root to rootless storage: %w", define.ErrInvalidArg)
}
Expand All @@ -801,7 +800,7 @@ func Transfer(ctx context.Context, source entities.ImageScpOptions, dest entitie
}

// TransferRootless creates new podman processes using exec.Command and sudo, transferring images between the given source and destination users
func transferRootless(source entities.ImageScpOptions, dest entities.ImageScpOptions, podman string, parentFlags []string) error {
func transferRootless(source entities.ScpTransferImageOptions, dest entities.ScpTransferImageOptions, podman string, parentFlags []string) error {
var cmdSave *exec.Cmd
saveCommand, loadCommand := parentFlags, parentFlags
saveCommand = append(saveCommand, []string{"save"}...)
Expand Down Expand Up @@ -842,7 +841,7 @@ func transferRootless(source entities.ImageScpOptions, dest entities.ImageScpOpt
}

// transferRootful creates new podman processes using exec.Command and a new uid/gid alongside a cleared environment
func transferRootful(source entities.ImageScpOptions, dest entities.ImageScpOptions, podman string, parentFlags []string) error {
func transferRootful(source entities.ScpTransferImageOptions, dest entities.ScpTransferImageOptions, podman string, parentFlags []string) error {
basicCommand := make([]string, 0, len(parentFlags)+1)
basicCommand = append(basicCommand, podman)
basicCommand = append(basicCommand, parentFlags...)
Expand Down
9 changes: 4 additions & 5 deletions pkg/domain/infra/tunnel/images.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
bdefine "github.com/containers/buildah/define"
"github.com/containers/common/libimage/filter"
"github.com/containers/common/pkg/config"
"github.com/containers/common/pkg/ssh"
"github.com/containers/image/v5/docker/reference"
"github.com/containers/image/v5/types"
"github.com/containers/podman/v5/libpod/define"
Expand Down Expand Up @@ -415,22 +414,22 @@ func (ir *ImageEngine) Sign(ctx context.Context, names []string, options entitie
return nil, errors.New("not implemented yet")
}

func (ir *ImageEngine) Scp(ctx context.Context, src, dst string, parentFlags []string, quiet bool, sshMode ssh.EngineMode) error {
func (ir *ImageEngine) Scp(ctx context.Context, src, dst string, opts entities.ImageScpOptions) (*entities.ImageScpReport, error) {
options := new(images.ScpOptions)

var destination *string
if len(dst) > 1 {
destination = &dst
}
options.Quiet = &quiet
options.Quiet = &opts.Quiet
options.Destination = destination

rep, err := images.Scp(ir.ClientCtx, &src, destination, *options)
if err != nil {
return err
return nil, err
}

fmt.Println("Loaded Image(s):", rep.Id)

return nil
return &entities.ImageScpReport{}, nil
}
Loading