Add manifest type conversion to kpod push

User can select from 3 manifest types: oci, v2s1, or v2s2
e.g kpod push --format v2s2 alpine dir:my-directory
Added "compress" flag to enable compression when true

Signed-off-by: umohnani8 <umohnani@redhat.com>

Closes: #126
Approved by: rhatdan
This commit is contained in:
umohnani8 2017-12-12 13:33:10 -05:00 committed by Atomic Bot
parent bf0d359047
commit 1e7d880b56
9 changed files with 110 additions and 28 deletions

View File

@ -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)

View File

@ -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 {

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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
}

View File

@ -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
}

View File

@ -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 {

View File

@ -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
}