mirror of
https://github.com/podman-container-tools/podman.git
synced 2026-09-03 22:27:52 +00:00
the destination image for podman push should be optional (if the destination has already been tagged in). the man page for podman push describes that it should work this way. Resolves: #645 Signed-off-by: baude <bbaude@redhat.com> Closes: #646 Approved by: mheon
163 lines
4.5 KiB
Go
163 lines
4.5 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/containers/image/manifest"
|
|
"github.com/containers/image/types"
|
|
imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/pkg/errors"
|
|
"github.com/projectatomic/libpod/libpod"
|
|
"github.com/projectatomic/libpod/libpod/image"
|
|
"github.com/projectatomic/libpod/pkg/util"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
var (
|
|
pushFlags = []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "signature-policy",
|
|
Usage: "`pathname` of signature policy file (not usually used)",
|
|
Hidden: true,
|
|
},
|
|
cli.StringFlag{
|
|
Name: "creds",
|
|
Usage: "`credentials` (USERNAME:PASSWORD) to use for authenticating to a registry",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "cert-dir",
|
|
Usage: "`pathname` of a directory containing TLS certificates and keys",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "compress",
|
|
Usage: "compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type as source)",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "format, f",
|
|
Usage: "manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)",
|
|
},
|
|
cli.BoolTFlag{
|
|
Name: "tls-verify",
|
|
Usage: "require HTTPS and verify certificates when contacting registries (default: true)",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "remove-signatures",
|
|
Usage: "discard any pre-existing signatures in the image",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "sign-by",
|
|
Usage: "add a signature at the destination using the specified key",
|
|
},
|
|
cli.BoolFlag{
|
|
Name: "quiet, q",
|
|
Usage: "don't output progress information when pushing images",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "authfile",
|
|
Usage: "Path of the authentication file. Default is ${XDG_RUNTIME_DIR}/containers/auth.json",
|
|
},
|
|
}
|
|
pushDescription = fmt.Sprintf(`
|
|
Pushes an image to a specified location.
|
|
The Image "DESTINATION" uses a "transport":"details" format.
|
|
See podman-push(1) section "DESTINATION" for the expected format`)
|
|
|
|
pushCommand = cli.Command{
|
|
Name: "push",
|
|
Usage: "push an image to a specified destination",
|
|
Description: pushDescription,
|
|
Flags: pushFlags,
|
|
Action: pushCmd,
|
|
ArgsUsage: "IMAGE DESTINATION",
|
|
}
|
|
)
|
|
|
|
func pushCmd(c *cli.Context) error {
|
|
var (
|
|
registryCreds *types.DockerAuthConfig
|
|
destName string
|
|
)
|
|
|
|
args := c.Args()
|
|
srcName := args[0]
|
|
if len(args) == 0 || len(args) > 2 {
|
|
return errors.New("podman push requires at least one image name, and optionally a second to specify a different destination name")
|
|
}
|
|
switch len(args) {
|
|
case 1:
|
|
destName = args[0]
|
|
case 2:
|
|
destName = args[1]
|
|
}
|
|
if err := validateFlags(c, pushFlags); err != nil {
|
|
return err
|
|
}
|
|
|
|
// --compress and --format can only be used for the "dir" transport
|
|
splitArg := strings.SplitN(destName, ":", 2)
|
|
if c.IsSet("compress") || c.IsSet("format") {
|
|
if splitArg[0] != libpod.DirTransport {
|
|
return errors.Errorf("--compress and --format can be set only when pushing to a directory using the 'dir' transport")
|
|
}
|
|
}
|
|
|
|
certPath := c.String("cert-dir")
|
|
skipVerify := !c.BoolT("tls-verify")
|
|
removeSignatures := c.Bool("remove-signatures")
|
|
signBy := c.String("sign-by")
|
|
|
|
if c.IsSet("creds") {
|
|
creds, err := util.ParseRegistryCreds(c.String("creds"))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
registryCreds = creds
|
|
}
|
|
|
|
runtime, err := getRuntime(c)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "could not create runtime")
|
|
}
|
|
defer runtime.Shutdown(false)
|
|
|
|
var writer io.Writer
|
|
if !c.Bool("quiet") {
|
|
writer = os.Stderr
|
|
}
|
|
|
|
var manifestType string
|
|
if c.IsSet("format") {
|
|
switch c.String("format") {
|
|
case "oci":
|
|
manifestType = imgspecv1.MediaTypeImageManifest
|
|
case "v2s1":
|
|
manifestType = manifest.DockerV2Schema1SignedMediaType
|
|
case "v2s2", "docker":
|
|
manifestType = manifest.DockerV2Schema2MediaType
|
|
default:
|
|
return fmt.Errorf("unknown format %q. Choose on of the supported formats: 'oci', 'v2s1', or 'v2s2'", c.String("format"))
|
|
}
|
|
}
|
|
|
|
dockerRegistryOptions := image.DockerRegistryOptions{
|
|
DockerRegistryCreds: registryCreds,
|
|
DockerCertPath: certPath,
|
|
DockerInsecureSkipTLSVerify: skipVerify,
|
|
}
|
|
|
|
so := image.SigningOptions{
|
|
RemoveSignatures: removeSignatures,
|
|
SignBy: signBy,
|
|
}
|
|
|
|
newImage, err := runtime.ImageRuntime().NewFromLocal(srcName)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
//return runtime.PushImage(srcName, destName, options)
|
|
return newImage.PushImage(getContext(), destName, manifestType, c.String("authfile"), c.String("signature-policy"), writer, c.Bool("compress"), so, &dockerRegistryOptions)
|
|
}
|