summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cmd/kpod/login.go2
-rw-r--r--cmd/kpod/logout.go2
-rw-r--r--cmd/kpod/push.go43
-rw-r--r--completions/bash/kpod4
-rw-r--r--docs/kpod-push.1.md32
-rw-r--r--libpod/common/common.go20
-rw-r--r--libpod/common/docker_registry_options.go3
-rw-r--r--libpod/runtime_img.go16
-rw-r--r--test/kpod_push.bats16
9 files changed, 110 insertions, 28 deletions
diff --git a/cmd/kpod/login.go b/cmd/kpod/login.go
index df74a2fdf..8984d069c 100644
--- a/cmd/kpod/login.go
+++ b/cmd/kpod/login.go
@@ -56,7 +56,7 @@ func loginCmd(c *cli.Context) error {
server = args[0]
}
- sc := common.GetSystemContext("", c.String("authfile"))
+ sc := common.GetSystemContext("", c.String("authfile"), false)
// username of user logged in to server (if one exists)
userFromAuthFile := config.GetUserLoggedIn(sc, server)
diff --git a/cmd/kpod/logout.go b/cmd/kpod/logout.go
index 9d1d52e32..cae8ddfb2 100644
--- a/cmd/kpod/logout.go
+++ b/cmd/kpod/logout.go
@@ -46,7 +46,7 @@ func logoutCmd(c *cli.Context) error {
server = args[0]
}
- sc := common.GetSystemContext("", c.String("authfile"))
+ sc := common.GetSystemContext("", c.String("authfile"), false)
if c.Bool("all") {
if err := config.RemoveAllAuthentication(sc); err != nil {
diff --git a/cmd/kpod/push.go b/cmd/kpod/push.go
index 4f1218a08..d3d42e0ee 100644
--- a/cmd/kpod/push.go
+++ b/cmd/kpod/push.go
@@ -4,9 +4,12 @@ import (
"fmt"
"io"
"os"
+ "strings"
+ "github.com/containers/image/manifest"
"github.com/containers/image/types"
"github.com/containers/storage/pkg/archive"
+ imgspecv1 "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors"
"github.com/projectatomic/libpod/libpod"
"github.com/projectatomic/libpod/libpod/common"
@@ -29,6 +32,14 @@ var (
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)",
@@ -75,8 +86,16 @@ func pushCmd(c *cli.Context) error {
if err := validateFlags(c, pushFlags); err != nil {
return err
}
- srcName := c.Args().Get(0)
- destName := c.Args().Get(1)
+ srcName := args[0]
+ destName := args[1]
+
+ // --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")
+ }
+ }
registryCredsString := c.String("creds")
certPath := c.String("cert-dir")
@@ -112,6 +131,20 @@ func pushCmd(c *cli.Context) error {
writer = os.Stdout
}
+ 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"))
+ }
+ }
+
options := libpod.CopyOptions{
Compression: archive.Uncompressed,
SignaturePolicyPath: c.String("signature-policy"),
@@ -124,8 +157,10 @@ func pushCmd(c *cli.Context) error {
RemoveSignatures: removeSignatures,
SignBy: signBy,
},
- AuthFile: c.String("authfile"),
- Writer: writer,
+ AuthFile: c.String("authfile"),
+ Writer: writer,
+ ManifestMIMEType: manifestType,
+ ForceCompress: c.Bool("compress"),
}
return runtime.PushImage(srcName, destName, options)
diff --git a/completions/bash/kpod b/completions/bash/kpod
index d403fed3e..417e9468d 100644
--- a/completions/bash/kpod
+++ b/completions/bash/kpod
@@ -921,8 +921,7 @@ _kpod_mount() {
_kpod_push() {
local boolean_options="
- --disable-compression
- -D
+ --compress
--quiet
-q
--remove-signatures
@@ -931,6 +930,7 @@ _kpod_push() {
local options_with_args="
--authfile
+ --format
--cert-dir
--creds
--sign-by
diff --git a/docs/kpod-push.1.md b/docs/kpod-push.1.md
index a9d314cbe..211a5f517 100644
--- a/docs/kpod-push.1.md
+++ b/docs/kpod-push.1.md
@@ -9,8 +9,10 @@ kpod push - Push an image from local storage to elsewhere
**kpod** **push** [*options* [...]] **imageID** [**destination**]
## DESCRIPTION
-Pushes an image from local storage to a specified destination, decompressing
-and recompressing layers as needed.
+Pushes an image from local storage to a specified destination.
+Push is mainly used to push images to registries, however **kpod push**
+can be used to save images to tarballs and directories using the following
+transports: **dir:**, **docker-archive:**, **docker-daemon:**, **oci-archive:**, and **ostree:**.
## imageID
Image stored in local container/storage
@@ -19,6 +21,8 @@ Image stored in local container/storage
The DESTINATION is a location to store container images
The Image "DESTINATION" uses a "transport":"details" format.
+ If a transport is not given, kpod push will attempt to push
+ to a registry.
Multiple transports are supported:
@@ -55,9 +59,15 @@ Credentials (USERNAME:PASSWORD) to use for authenticating to a registry
Pathname of a directory containing TLS certificates and keys
-**--disable-compression, -D**
+**--compress**
-Don't compress copies of filesystem layers which will be pushed
+Compress tarball image layers when pushing to a directory using the 'dir' transport. (default is same compression type, compressed or uncompressed, as source)
+Note: This flag can only be set when using the **dir** transport
+
+**--format, -f**
+
+Manifest Type (oci, v2s1, or v2s2) to use when pushing an image to a directory using the 'dir:' transport (default is manifest type of source)
+Note: This flag can only be set when using the **dir** transport
**--quiet, -q**
@@ -113,5 +123,19 @@ Writing manifest to image destination
Storing signatures
```
+This example pushes the rhel7 image to rhel7-dir with the "oci" manifest type
+```
+# kpod push --format oci registry.access.redhat.com/rhel7 dir:rhel7-dir
+Getting image source signatures
+Copying blob sha256:9cadd93b16ff2a0c51ac967ea2abfadfac50cfa3af8b5bf983d89b8f8647f3e4
+ 71.41 MB / 71.41 MB [======================================================] 9s
+Copying blob sha256:4aa565ad8b7a87248163ce7dba1dd3894821aac97e846b932ff6b8ef9a8a508a
+ 1.21 KB / 1.21 KB [========================================================] 0s
+Copying config sha256:f1b09a81455c351eaa484b61aacd048ab613c08e4c5d1da80c4c46301b03cf3b
+ 3.01 KB / 3.01 KB [========================================================] 0s
+Writing manifest to image destination
+Storing signatures
+```
+
## SEE ALSO
kpod(1), kpod-pull(1), crio(8), crio.conf(5), docker-login(1)
diff --git a/libpod/common/common.go b/libpod/common/common.go
index 8a7fbcd5e..6af3cd232 100644
--- a/libpod/common/common.go
+++ b/libpod/common/common.go
@@ -16,31 +16,33 @@ var (
)
// GetCopyOptions constructs a new containers/image/copy.Options{} struct from the given parameters
-func GetCopyOptions(reportWriter io.Writer, signaturePolicyPath string, srcDockerRegistry, destDockerRegistry *DockerRegistryOptions, signing SigningOptions, authFile string) *cp.Options {
+func GetCopyOptions(reportWriter io.Writer, signaturePolicyPath string, srcDockerRegistry, destDockerRegistry *DockerRegistryOptions, signing SigningOptions, authFile, manifestType string, forceCompress bool) *cp.Options {
if srcDockerRegistry == nil {
srcDockerRegistry = &DockerRegistryOptions{}
}
if destDockerRegistry == nil {
destDockerRegistry = &DockerRegistryOptions{}
}
- srcContext := srcDockerRegistry.GetSystemContext(signaturePolicyPath, authFile)
- destContext := destDockerRegistry.GetSystemContext(signaturePolicyPath, authFile)
+ srcContext := srcDockerRegistry.GetSystemContext(signaturePolicyPath, authFile, forceCompress)
+ destContext := destDockerRegistry.GetSystemContext(signaturePolicyPath, authFile, forceCompress)
return &cp.Options{
- RemoveSignatures: signing.RemoveSignatures,
- SignBy: signing.SignBy,
- ReportWriter: reportWriter,
- SourceCtx: srcContext,
- DestinationCtx: destContext,
+ RemoveSignatures: signing.RemoveSignatures,
+ SignBy: signing.SignBy,
+ ReportWriter: reportWriter,
+ SourceCtx: srcContext,
+ DestinationCtx: destContext,
+ ForceManifestMIMEType: manifestType,
}
}
// GetSystemContext Constructs a new containers/image/types.SystemContext{} struct from the given signaturePolicy path
-func GetSystemContext(signaturePolicyPath, authFilePath string) *types.SystemContext {
+func GetSystemContext(signaturePolicyPath, authFilePath string, forceCompress bool) *types.SystemContext {
sc := &types.SystemContext{}
if signaturePolicyPath != "" {
sc.SignaturePolicyPath = signaturePolicyPath
}
sc.AuthFilePath = authFilePath
+ sc.DirForceCompress = forceCompress
return sc
}
diff --git a/libpod/common/docker_registry_options.go b/libpod/common/docker_registry_options.go
index 24fa5c03e..f79ae0c54 100644
--- a/libpod/common/docker_registry_options.go
+++ b/libpod/common/docker_registry_options.go
@@ -22,13 +22,14 @@ type DockerRegistryOptions struct {
// GetSystemContext constructs a new system context from the given signaturePolicy path and the
// values in the DockerRegistryOptions
-func (o DockerRegistryOptions) GetSystemContext(signaturePolicyPath, authFile string) *types.SystemContext {
+func (o DockerRegistryOptions) GetSystemContext(signaturePolicyPath, authFile string, forceCompress bool) *types.SystemContext {
sc := &types.SystemContext{
SignaturePolicyPath: signaturePolicyPath,
DockerAuthConfig: o.DockerRegistryCreds,
DockerCertPath: o.DockerCertPath,
DockerInsecureSkipTLSVerify: o.DockerInsecureSkipTLSVerify,
AuthFilePath: authFile,
+ DirForceCompress: forceCompress,
}
return sc
}
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index d5da35c42..6107c2fdb 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -78,6 +78,10 @@ type CopyOptions struct {
Reference string
// ImageConfig is the Image spec for the image created when a tar archive is imported
ImageConfig ociv1.Image
+ // ManifestMIMEType is the manifest type of the image when saving to a directory
+ ManifestMIMEType string
+ // ForceCompress compresses the image layers when saving to a directory using the dir transport if true
+ ForceCompress bool
}
// Image API
@@ -643,7 +647,7 @@ func (r *Runtime) PullImage(imgName string, options CopyOptions) (string, error)
signaturePolicyPath = options.SignaturePolicyPath
}
- sc := common.GetSystemContext(signaturePolicyPath, options.AuthFile)
+ sc := common.GetSystemContext(signaturePolicyPath, options.AuthFile, false)
srcRef, err := alltransports.ParseImageName(imgName)
if err != nil {
@@ -664,7 +668,7 @@ func (r *Runtime) PullImage(imgName string, options CopyOptions) (string, error)
}
defer policyContext.Destroy()
- copyOptions := common.GetCopyOptions(options.Writer, signaturePolicyPath, &options.DockerRegistryOptions, nil, options.SigningOptions, options.AuthFile)
+ copyOptions := common.GetCopyOptions(options.Writer, signaturePolicyPath, &options.DockerRegistryOptions, nil, options.SigningOptions, options.AuthFile, "", false)
for _, imageInfo := range pullStructs {
// Print the following statement only when pulling from a docker or atomic registry
@@ -721,7 +725,7 @@ func (r *Runtime) PushImage(source string, destination string, options CopyOptio
signaturePolicyPath = options.SignaturePolicyPath
}
- sc := common.GetSystemContext(signaturePolicyPath, options.AuthFile)
+ sc := common.GetSystemContext(signaturePolicyPath, options.AuthFile, options.ForceCompress)
policyContext, err := getPolicyContext(sc)
if err != nil {
@@ -735,7 +739,7 @@ func (r *Runtime) PushImage(source string, destination string, options CopyOptio
return errors.Wrapf(err, "error getting source imageReference for %q", source)
}
- copyOptions := common.GetCopyOptions(options.Writer, signaturePolicyPath, nil, &options.DockerRegistryOptions, options.SigningOptions, options.AuthFile)
+ copyOptions := common.GetCopyOptions(options.Writer, signaturePolicyPath, nil, &options.DockerRegistryOptions, options.SigningOptions, options.AuthFile, options.ManifestMIMEType, options.ForceCompress)
// Copy the image to the remote destination
err = cp.Image(policyContext, dest, src, copyOptions)
@@ -1004,7 +1008,7 @@ func (r *Runtime) ImportImage(path string, options CopyOptions) error {
}
var reference = options.Reference
- sc := common.GetSystemContext("", "")
+ sc := common.GetSystemContext("", "", false)
// if reference not given, get the image digest
if reference == "" {
@@ -1020,7 +1024,7 @@ func (r *Runtime) ImportImage(path string, options CopyOptions) error {
}
defer policyContext.Destroy()
- copyOptions := common.GetCopyOptions(os.Stdout, "", nil, nil, common.SigningOptions{}, "")
+ copyOptions := common.GetCopyOptions(os.Stdout, "", nil, nil, common.SigningOptions{}, "", "", false)
dest, err := is.Transport.ParseStoreReference(r.store, reference)
if err != nil {
diff --git a/test/kpod_push.bats b/test/kpod_push.bats
index d9b1811cc..dee29a64c 100644
--- a/test/kpod_push.bats
+++ b/test/kpod_push.bats
@@ -84,3 +84,19 @@ function setup() {
run ${KPOD_BINARY} $KPOD_OPTIONS rmi "$ALPINE"
echo "$output"
}
+
+@test "push with manifest type conversion" {
+ run bash -c "${KPOD_BINARY} $KPOD_OPTIONS push --format oci "${BB}" dir:my-dir"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run bash -c "grep "application/vnd.oci.image.config.v1+json" my-dir/manifest.json"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run bash -c "${KPOD_BINARY} $KPOD_OPTIONS push --compress --format v2s2 "${BB}" dir:my-dir"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ run bash -c "grep "application/vnd.docker.distribution.manifest.v2+json" my-dir/manifest.json"
+ echo "$output"
+ [ "$status" -eq 0 ]
+ rm -rf my-dir
+}