summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Dockerfile.fedora20
-rw-r--r--cmd/podman/cliconfig/config.go1
-rw-r--r--cmd/podman/commands.go2
-rw-r--r--cmd/podman/container.go1
-rw-r--r--cmd/podman/cp.go1
-rw-r--r--cmd/podman/push.go3
-rw-r--r--cmd/podman/shared/intermediate.go10
-rw-r--r--completions/bash/podman1
-rw-r--r--docs/podman-push.1.md18
-rw-r--r--libpod/image/image.go23
-rw-r--r--pkg/adapter/runtime.go4
-rw-r--r--pkg/adapter/runtime_remote.go2
-rw-r--r--pkg/varlinkapi/images.go4
-rw-r--r--test/e2e/push_test.go8
14 files changed, 59 insertions, 39 deletions
diff --git a/Dockerfile.fedora b/Dockerfile.fedora
index 0f82fdc5c..429597f4f 100644
--- a/Dockerfile.fedora
+++ b/Dockerfile.fedora
@@ -27,36 +27,24 @@ RUN dnf -y install btrfs-progs-devel \
xz \
slirp4netns \
container-selinux \
+ containernetworking-plugins \
iptables && dnf clean all
-# Install CNI plugins
-ENV CNI_COMMIT 485be65581341430f9106a194a98f0f2412245fb
-ENV
-RUN set -x \
- && export GOPATH="$(mktemp -d)" GOCACHE="$(mktemp -d)" \
- && git clone https://github.com/containernetworking/plugins.git "$GOPATH/src/github.com/containernetworking/plugins" \
- && cd "$GOPATH/src/github.com/containernetworking/plugins" \
- && git checkout -q "$CNI_COMMIT" \
- && ./build_linux.sh \
- && mkdir -p /usr/libexec/cni \
- && cp bin/* /usr/libexec/cni \
- && rm -rf "$GOPATH"
-
# Install ginkgo
RUN set -x \
- && export GOPATH=/go \
+ && export GOPATH=/go GOCACHE="$(mktemp -d)" \
&& go get -u github.com/onsi/ginkgo/ginkgo \
&& install -D -m 755 "$GOPATH"/bin/ginkgo /usr/bin/
# Install gomega
RUN set -x \
- && export GOPATH=/go \
+ && export GOPATH=/go GOCACHE="$(mktemp -d)" \
&& go get github.com/onsi/gomega/...
# Install conmon
ENV CONMON_COMMIT 6f3572558b97bc60dd8f8c7f0807748e6ce2c440
RUN set -x \
- && export GOPATH="$(mktemp -d)" \
+ && export GOPATH="$(mktemp -d)" GOCACHE="$(mktemp -d)" \
&& git clone https://github.com/containers/conmon.git "$GOPATH/src/github.com/containers/conmon.git" \
&& cd "$GOPATH/src/github.com/containers/conmon.git" \
&& git fetch origin --tags \
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index e7ad921da..8075baf34 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -423,6 +423,7 @@ type PushValues struct {
CertDir string
Compress bool
Creds string
+ Digestfile string
Format string
Quiet bool
RemoveSignatures bool
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index e23918a5b..77c76d1b7 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -11,6 +11,7 @@ const remoteclient = false
// Commands that the local client implements
func getMainCommands() []*cobra.Command {
rootCommands := []*cobra.Command{
+ _cpCommand,
_playCommand,
_loginCommand,
_logoutCommand,
@@ -39,6 +40,7 @@ func getImageSubCommands() []*cobra.Command {
func getContainerSubCommands() []*cobra.Command {
return []*cobra.Command{
+ _cpCommand,
_cleanupCommand,
_mountCommand,
_refreshCommand,
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index 557f5fafa..66b58f06e 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -55,7 +55,6 @@ var (
_commitCommand,
_containerExistsCommand,
_contInspectSubCommand,
- _cpCommand,
_diffCommand,
_execCommand,
_exportCommand,
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index ad7253ac0..5e1ca8312 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -55,7 +55,6 @@ func init() {
flags.BoolVar(&cpCommand.Pause, "pause", false, "Pause the container while copying")
cpCommand.SetHelpTemplate(HelpTemplate())
cpCommand.SetUsageTemplate(UsageTemplate())
- rootCmd.AddCommand(cpCommand.Command)
}
func cpCmd(c *cliconfig.CpValues) error {
diff --git a/cmd/podman/push.go b/cmd/podman/push.go
index 43df8c2de..13ebe8a1f 100644
--- a/cmd/podman/push.go
+++ b/cmd/podman/push.go
@@ -51,6 +51,7 @@ func init() {
pushCommand.SetUsageTemplate(UsageTemplate())
flags := pushCommand.Flags()
flags.StringVar(&pushCommand.Creds, "creds", "", "`Credentials` (USERNAME:PASSWORD) to use for authenticating to a registry")
+ flags.StringVar(&pushCommand.Digestfile, "digestfile", "", "After copying the image, write the digest of the resulting image to the file")
flags.StringVarP(&pushCommand.Format, "format", "f", "", "Manifest type (oci, v2s1, or v2s2) to use when pushing an image using the 'dir:' transport (default is manifest type of source)")
flags.BoolVarP(&pushCommand.Quiet, "quiet", "q", false, "Don't output progress information when pushing images")
flags.BoolVar(&pushCommand.RemoveSignatures, "remove-signatures", false, "Discard any pre-existing signatures in the image")
@@ -143,5 +144,5 @@ func pushCmd(c *cliconfig.PushValues) error {
SignBy: signBy,
}
- return runtime.Push(getContext(), srcName, destName, manifestType, c.Authfile, c.SignaturePolicy, writer, c.Compress, so, &dockerRegistryOptions, nil)
+ return runtime.Push(getContext(), srcName, destName, manifestType, c.Authfile, c.String("digestfile"), c.SignaturePolicy, writer, c.Compress, so, &dockerRegistryOptions, nil)
}
diff --git a/cmd/podman/shared/intermediate.go b/cmd/podman/shared/intermediate.go
index c6c32f8a9..5aaac8687 100644
--- a/cmd/podman/shared/intermediate.go
+++ b/cmd/podman/shared/intermediate.go
@@ -114,7 +114,7 @@ func (f GenericCLIResults) findResult(flag string) GenericCLIResult {
if ok {
return val
}
- logrus.Errorf("unable to find flag %s", flag)
+ logrus.Debugf("unable to find flag %s", flag)
return nil
}
@@ -366,12 +366,10 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["add-host"] = newCRStringSlice(c, "add-host")
m["annotation"] = newCRStringSlice(c, "annotation")
m["attach"] = newCRStringSlice(c, "attach")
- m["authfile"] = newCRString(c, "authfile")
m["blkio-weight"] = newCRString(c, "blkio-weight")
m["blkio-weight-device"] = newCRStringSlice(c, "blkio-weight-device")
m["cap-add"] = newCRStringSlice(c, "cap-add")
m["cap-drop"] = newCRStringSlice(c, "cap-drop")
- m["cgroupns"] = newCRString(c, "cgroupns")
m["cgroup-parent"] = newCRString(c, "cgroup-parent")
m["cidfile"] = newCRString(c, "cidfile")
m["conmon-pidfile"] = newCRString(c, "conmon-pidfile")
@@ -395,7 +393,6 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["dns-search"] = newCRStringSlice(c, "dns-search")
m["entrypoint"] = newCRString(c, "entrypoint")
m["env"] = newCRStringArray(c, "env")
- m["env-host"] = newCRBool(c, "env-host")
m["env-file"] = newCRStringSlice(c, "env-file")
m["expose"] = newCRStringSlice(c, "expose")
m["gidmap"] = newCRStringSlice(c, "gidmap")
@@ -407,7 +404,6 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["healthcheck-start-period"] = newCRString(c, "health-start-period")
m["healthcheck-timeout"] = newCRString(c, "health-timeout")
m["hostname"] = newCRString(c, "hostname")
- m["http-proxy"] = newCRBool(c, "http-proxy")
m["image-volume"] = newCRString(c, "image-volume")
m["init"] = newCRBool(c, "init")
m["init-path"] = newCRString(c, "init-path")
@@ -465,6 +461,10 @@ func NewIntermediateLayer(c *cliconfig.PodmanCommand, remote bool) GenericCLIRes
m["workdir"] = newCRString(c, "workdir")
// global flag
if !remote {
+ m["authfile"] = newCRString(c, "authfile")
+ m["cgroupns"] = newCRString(c, "cgroupns")
+ m["env-host"] = newCRBool(c, "env-host")
+ m["http-proxy"] = newCRBool(c, "http-proxy")
m["trace"] = newCRBool(c, "trace")
m["syslog"] = newCRBool(c, "syslog")
}
diff --git a/completions/bash/podman b/completions/bash/podman
index 962c15a95..7280f4040 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1758,6 +1758,7 @@ _podman_mount() {
_podman_push() {
local boolean_options="
--compress
+ --digestflag
--help
-h
--quiet
diff --git a/docs/podman-push.1.md b/docs/podman-push.1.md
index 2058a432c..29e4044a3 100644
--- a/docs/podman-push.1.md
+++ b/docs/podman-push.1.md
@@ -61,13 +61,17 @@ value can be entered. The password is entered without echo.
**--cert-dir**=*path*
Use certificates at *path* (\*.crt, \*.cert, \*.key) to connect to the registry.
-Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands) (Not available for remote commands)
+Default certificates directory is _/etc/containers/certs.d_. (Not available for remote commands)
**--compress**
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
+**--digestfile** *Digestfile*
+
+After copying the image, write the digest of the resulting image to the file. (Not available for remote commands)
+
**--format**, **-f**=*format*
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)
@@ -93,19 +97,23 @@ TLS verification will be used unless the target registry is listed as an insecur
## EXAMPLE
-This example extracts the imageID image to a local directory in docker format.
+This example pushes the image specified by the imageID to a local directory in docker format.
`# podman push imageID dir:/path/to/image`
-This example extracts the imageID image to a local directory in oci format.
+This example pushes the image specified by the imageID to a local directory in oci format.
`# podman push imageID oci-archive:/path/to/layout:image:tag`
-This example extracts the imageID image to a container registry named registry.example.com
+This example pushes the image specified by the imageID to a container registry named registry.example.com
`# podman push imageID docker://registry.example.com/repository:tag`
-This example extracts the imageID image and puts into the local docker container store
+This example pushes the image specified by the imageID to a container registry named registry.example.com and saves the digest in the specified digestfile.
+
+ `# podman push --digestfile=/tmp/mydigest imageID docker://registry.example.com/repository:tag`
+
+This example pushes the image specified by the imageID and puts it into the local docker container store
`# podman push imageID docker-daemon:image:tag`
diff --git a/libpod/image/image.go b/libpod/image/image.go
index cb7c390c6..1ff271a4d 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
+ "io/ioutil"
"os"
"path/filepath"
"strings"
@@ -555,7 +556,7 @@ func (i *Image) UntagImage(tag string) error {
// PushImageToHeuristicDestination pushes the given image to "destination", which is heuristically parsed.
// Use PushImageToReference if the destination is known precisely.
-func (i *Image) PushImageToHeuristicDestination(ctx context.Context, destination, manifestMIMEType, authFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+func (i *Image) PushImageToHeuristicDestination(ctx context.Context, destination, manifestMIMEType, authFile, digestFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
if destination == "" {
return errors.Wrapf(syscall.EINVAL, "destination image name must be specified")
}
@@ -573,11 +574,11 @@ func (i *Image) PushImageToHeuristicDestination(ctx context.Context, destination
return err
}
}
- return i.PushImageToReference(ctx, dest, manifestMIMEType, authFile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, additionalDockerArchiveTags)
+ return i.PushImageToReference(ctx, dest, manifestMIMEType, authFile, digestFile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, additionalDockerArchiveTags)
}
// PushImageToReference pushes the given image to a location described by the given path
-func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageReference, manifestMIMEType, authFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageReference, manifestMIMEType, authFile, digestFile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions SigningOptions, dockerRegistryOptions *DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
sc := GetSystemContext(signaturePolicyPath, authFile, forceCompress)
sc.BlobInfoCacheDir = filepath.Join(i.imageruntime.store.GraphRoot(), "cache")
@@ -599,10 +600,22 @@ func (i *Image) PushImageToReference(ctx context.Context, dest types.ImageRefere
copyOptions := getCopyOptions(sc, writer, nil, dockerRegistryOptions, signingOptions, manifestMIMEType, additionalDockerArchiveTags)
copyOptions.DestinationCtx.SystemRegistriesConfPath = registries.SystemRegistriesConfPath() // FIXME: Set this more globally. Probably no reason not to have it in every types.SystemContext, and to compute the value just once in one place.
// Copy the image to the remote destination
- _, err = cp.Image(ctx, policyContext, dest, src, copyOptions)
+ manifestBytes, err := cp.Image(ctx, policyContext, dest, src, copyOptions)
if err != nil {
return errors.Wrapf(err, "Error copying image to the remote destination")
}
+ digest, err := manifest.Digest(manifestBytes)
+ if err != nil {
+ return errors.Wrapf(err, "error computing digest of manifest of new image %q", transports.ImageName(dest))
+ }
+
+ logrus.Debugf("Successfully pushed %s with digest %s", transports.ImageName(dest), digest.String())
+
+ if digestFile != "" {
+ if err = ioutil.WriteFile(digestFile, []byte(digest.String()), 0644); err != nil {
+ return errors.Wrapf(err, "failed to write digest to file %q", digestFile)
+ }
+ }
i.newImageEvent(events.Push)
return nil
}
@@ -1358,7 +1371,7 @@ func (i *Image) Save(ctx context.Context, source, format, output string, moreTag
return err
}
}
- if err := i.PushImageToReference(ctx, destRef, manifestType, "", "", writer, compress, SigningOptions{}, &DockerRegistryOptions{}, additionaltags); err != nil {
+ if err := i.PushImageToReference(ctx, destRef, manifestType, "", "", "", writer, compress, SigningOptions{}, &DockerRegistryOptions{}, additionaltags); err != nil {
return errors.Wrapf(err, "unable to save %q", source)
}
i.newImageEvent(events.Save)
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 7d4f97b28..0537308f8 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -201,12 +201,12 @@ func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmV
}
// Push is a wrapper to push an image to a registry
-func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, digestfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
newImage, err := r.ImageRuntime().NewFromLocal(srcName)
if err != nil {
return err
}
- return newImage.PushImageToHeuristicDestination(ctx, destination, manifestMIMEType, authfile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, nil)
+ return newImage.PushImageToHeuristicDestination(ctx, destination, manifestMIMEType, authfile, digestfile, signaturePolicyPath, writer, forceCompress, signingOptions, dockerRegistryOptions, nil)
}
// InspectVolumes returns a slice of volumes based on an arg list or --all
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 683bf1d35..8588966b6 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -619,7 +619,7 @@ func (r *LocalRuntime) RemoveVolumes(ctx context.Context, c *cliconfig.VolumeRmV
return iopodman.VolumeRemove().Call(r.Conn, rmOpts)
}
-func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
+func (r *LocalRuntime) Push(ctx context.Context, srcName, destination, manifestMIMEType, authfile, digestfile, signaturePolicyPath string, writer io.Writer, forceCompress bool, signingOptions image.SigningOptions, dockerRegistryOptions *image.DockerRegistryOptions, additionalDockerArchiveTags []reference.NamedTagged) error {
reply, err := iopodman.PushImage().Send(r.Conn, varlink.More, srcName, destination, forceCompress, manifestMIMEType, signingOptions.RemoveSignatures, signingOptions.SignBy)
if err != nil {
diff --git a/pkg/varlinkapi/images.go b/pkg/varlinkapi/images.go
index fe7f11b4d..a1fdf5955 100644
--- a/pkg/varlinkapi/images.go
+++ b/pkg/varlinkapi/images.go
@@ -353,7 +353,7 @@ func (i *LibpodAPI) PushImage(call iopodman.VarlinkCall, name, tag string, compr
output := bytes.NewBuffer([]byte{})
c := make(chan error)
go func() {
- err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", "", output, compress, so, &dockerRegistryOptions, nil)
+ err := newImage.PushImageToHeuristicDestination(getContext(), destname, manifestType, "", "", "", output, compress, so, &dockerRegistryOptions, nil)
c <- err
close(c)
}()
@@ -615,7 +615,7 @@ func (i *LibpodAPI) ExportImage(call iopodman.VarlinkCall, name, destination str
return err
}
- if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, additionalTags); err != nil {
+ if err := newImage.PushImageToHeuristicDestination(getContext(), destination, "", "", "", "", nil, compress, image.SigningOptions{}, &image.DockerRegistryOptions{}, additionalTags); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyExportImage(newImage.ID())
diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go
index cf6279f2f..4360eeece 100644
--- a/test/e2e/push_test.go
+++ b/test/e2e/push_test.go
@@ -76,6 +76,14 @@ var _ = Describe("Podman push", func() {
push := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
push.WaitWithDefaultTimeout()
Expect(push.ExitCode()).To(Equal(0))
+
+ // Test --digestfile option
+ push2 := podmanTest.PodmanNoCache([]string{"push", "--tls-verify=false", "--digestfile=/tmp/digestfile.txt", "--remove-signatures", ALPINE, "localhost:5000/my-alpine"})
+ push2.WaitWithDefaultTimeout()
+ fi, err := os.Lstat("/tmp/digestfile.txt")
+ Expect(err).To(BeNil())
+ Expect(fi.Name()).To(Equal("digestfile.txt"))
+ Expect(push2.ExitCode()).To(Equal(0))
})
It("podman push to local registry with authorization", func() {