summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml18
-rwxr-xr-xAPI.md16
-rw-r--r--Makefile1
-rw-r--r--README.md3
-rw-r--r--cmd/podman/images.go7
-rw-r--r--cmd/podman/inspect.go2
-rw-r--r--cmd/podman/pause.go2
-rw-r--r--cmd/podman/ps.go41
-rw-r--r--cmd/podman/rmi.go2
-rw-r--r--cmd/podman/trust.go152
-rw-r--r--cmd/podman/umount.go2
-rw-r--r--cmd/podman/varlink/io.podman.varlink14
-rwxr-xr-xcontrib/cirrus/build_vm_images.sh22
-rw-r--r--contrib/cirrus/packer/Makefile12
-rw-r--r--contrib/cirrus/packer/centos_setup.sh1
-rw-r--r--contrib/cirrus/packer/image-builder-image_base-setup.sh3
-rw-r--r--contrib/cirrus/packer/libpod_base_images.yml8
-rw-r--r--contrib/cirrus/packer/libpod_images.yml13
-rw-r--r--contrib/cirrus/packer/rhel_base-setup.sh34
-rw-r--r--contrib/cirrus/packer/rhel_setup.sh3
-rw-r--r--contrib/imgts/Dockerfile20
-rw-r--r--contrib/imgts/README.md11
-rwxr-xr-xcontrib/imgts/entrypoint.sh45
-rw-r--r--contrib/imgts/google-cloud-sdk.repo8
-rw-r--r--docs/podman-image-trust.1.md47
-rw-r--r--docs/podman.1.md20
-rw-r--r--libpod/image/image.go6
-rw-r--r--pkg/trust/trust.go122
-rw-r--r--pkg/varlinkapi/mount.go4
-rw-r--r--test/e2e/info_test.go2
-rw-r--r--test/e2e/ps_test.go7
-rw-r--r--vendor.conf2
-rw-r--r--vendor/github.com/containers/image/copy/copy.go39
-rw-r--r--vendor/github.com/containers/image/docker/docker_client.go33
-rw-r--r--vendor/github.com/containers/image/docker/docker_image.go2
-rw-r--r--vendor/github.com/containers/image/docker/docker_image_dest.go42
-rw-r--r--vendor/github.com/containers/image/docker/docker_image_src.go10
-rw-r--r--vendor/github.com/containers/image/version/version.go2
-rw-r--r--vendor/github.com/urfave/cli/help.go2
39 files changed, 502 insertions, 278 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index d3a9eea40..dbd0e8b3e 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -31,7 +31,7 @@ env:
PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-7f4cd1f7"
UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-7f4cd1f7"
# RHEL_CACHE_IMAGE_NAME: "rhel-8-notready"
- # PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-libpod-7f4cd1f7"
+ PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-libpod-7f4cd1f7"
# CENTOS_CACHE_IMAGE_NAME: "centos-7-notready"
####
@@ -45,9 +45,9 @@ env:
CRIU_COMMIT: "c74b83cd49c00589c0c0468ba5fe685b67fdbd0a"
RUNC_COMMIT: "25f3f893c86d07426df93b7aa172f33fdf093fbd"
# CSV of cache-image names to build (see $PACKER_BASE/libpod_images.json)
- PACKER_BUILDS: "ubuntu-18,fedora-29,fedora-28" # TODO: fah-29,rhel-7,centos-7
+ PACKER_BUILDS: "ubuntu-18,fedora-29,fedora-28,rhel-7" # TODO: rhel-8,centos-7
# Version of packer to use
- PACKER_VER: "1.3.1"
+ PACKER_VER: "1.3.2"
# Special image w/ nested-libvirt + tools for creating new cache and base images
IMAGE_BUILDER_CACHE_IMAGE_NAME: "image-builder-image-1541772081"
# Google-maintained base-image names
@@ -58,7 +58,7 @@ env:
PRIOR_FEDORA_BASE_IMAGE: "fedora-cloud-base-28-1-1-1544474897"
FAH_BASE_IMAGE: "fedora-atomichost-29-20181025-1-1541787861"
# RHEL image must be imported, google bills extra for their native image.
- RHEL_BASE_IMAGE: "rhel-guest-image-7-6-210-x86-64-qcow2-1541783972"
+ RHEL_BASE_IMAGE: "rhel-guest-image-7-6-210-x86-64-qcow2-1548099756"
####
#### Credentials and other secret-sauces, decrypted at runtime when authorized.
@@ -109,7 +109,6 @@ gating_task:
- '/usr/local/bin/entrypoint.sh validate'
- '/usr/local/bin/entrypoint.sh lint'
-
build_each_commit_task:
depends_on:
@@ -134,6 +133,7 @@ build_each_commit_task:
- git fetch --depth $CIRRUS_CLONE_DEPTH origin $CIRRUS_BASE_BRANCH
- env GOPATH=/var/tmp/go/ make build-all-new-commits GIT_BASE_BRANCH=origin/$CIRRUS_BASE_BRANCH
+
# This task does the unit and integration testing for every platform
testing_task:
@@ -154,10 +154,10 @@ testing_task:
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
+ image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}"
# TODO: tests fail
- # image_name: "${RHEL_CACHE_IMAGE_NAME}
- # image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}
+ # image_name: "${RHEL_CACHE_IMAGE_NAME}"
# image_name: "${CENTOS_CACHE_IMAGE_NAME}"
timeout_in: 120m
@@ -191,9 +191,9 @@ optional_testing_task:
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
+ image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}"
# TODO: Make these work (also build_images_task below)
- # image_name: "${RHEL_CACHE_IMAGE_NAME}
- # image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}
+ # image_name: "${RHEL_CACHE_IMAGE_NAME}"
# image_name: "${CENTOS_CACHE_IMAGE_NAME}"
timeout_in: 60m
diff --git a/API.md b/API.md
index fba6c89ee..f32325d37 100755
--- a/API.md
+++ b/API.md
@@ -81,7 +81,7 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func ListContainerChanges(name: string) ContainerChanges](#ListContainerChanges)
-[func ListContainerMounts() []string](#ListContainerMounts)
+[func ListContainerMounts() map[string]](#ListContainerMounts)
[func ListContainerPorts(name: string) NotImplemented](#ListContainerPorts)
@@ -643,19 +643,17 @@ its base image. It returns a struct of changed, deleted, and added path names.
### <a name="ListContainerMounts"></a>func ListContainerMounts
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
-method ListContainerMounts() [[]string](#[]string)</div>
+method ListContainerMounts() [map[string]](#map[string])</div>
ListContainerMounts gathers all the mounted container mount points and returns them as an array
of strings
#### Example
~~~
-$ varlink call -m unix:/run/podman/io.podman/io.podman.ListContainerMounts
+$ varlink call unix:/run/podman/io.podman/io.podman.ListContainerMounts
{
- "mounts": [
- "/var/lib/containers/storage/overlay/b215fb622c65ba3b06c6d2341be80b76a9de7ae415ce419e65228873d4f0dcc8/merged",
- "/var/lib/containers/storage/overlay/5eaf806073f79c0ed9a695180ad598e34f963f7407da1d2ccf3560bdab49b26f/merged",
- "/var/lib/containers/storage/overlay/1ecb6b1dbb251737c7a24a31869096839c3719d8b250bf075f75172ddcc701e1/merged",
- "/var/lib/containers/storage/overlay/7137b28a3c422165fe920cba851f2f8da271c6b5908672c451ebda03ad3919e2/merged"
- ]
+ "mounts": {
+ "04e4c255269ed2545e7f8bd1395a75f7949c50c223415c00c1d54bfa20f3b3d9": "/var/lib/containers/storage/overlay/a078925828f57e20467ca31cfca8a849210d21ec7e5757332b72b6924f441c17/merged",
+ "1d58c319f9e881a644a5122ff84419dccf6d138f744469281446ab243ef38924": "/var/lib/containers/storage/overlay/948fcf93f8cb932f0f03fd52e3180a58627d547192ffe3b88e0013b98ddcd0d2/merged"
+ }
}
~~~
### <a name="ListContainerPorts"></a>func ListContainerPorts
diff --git a/Makefile b/Makefile
index 02f7293f5..334ee980d 100644
--- a/Makefile
+++ b/Makefile
@@ -225,6 +225,7 @@ install: .gopathok install.bin install.man install.cni install.systemd
install.bin:
install ${SELINUXOPT} -d -m 755 $(BINDIR)
install ${SELINUXOPT} -m 755 bin/podman $(BINDIR)/podman
+ test -z "${SELINUXOPT}" || chcon --verbose --reference=$(BINDIR)/podman bin/podman
install.man: docs
install ${SELINUXOPT} -d -m 755 $(MANDIR)/man1
diff --git a/README.md b/README.md
index 93e780524..f2a7bf152 100644
--- a/README.md
+++ b/README.md
@@ -3,8 +3,7 @@
# Library and tool for running OCI-based containers in Pods
Libpod provides a library for applications looking to use the Container Pod concept,
-popularized by Kubernetes. libpod also contains the `podman` tool, for managing
-Pods, Containers, and Container Images.
+popularized by Kubernetes. Libpod also contains the Pod Manager tool `(Podman)`. Podman manages pods, containers, container images, and container volumes.
* [Latest Version: 1.0.0](https://github.com/containers/libpod/releases/latest)
* [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master)
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 031f06618..d4f405975 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -188,13 +188,6 @@ func imagesCmd(c *cli.Context) error {
}
opts.outputformat = opts.setOutputFormat()
- /*
- podman does not implement --all for images
-
- intermediate images are only generated during the build process. they are
- children to the image once built. until buildah supports caching builds,
- it will not generate these intermediate images.
- */
images, err := runtime.GetImages()
if err != nil {
return errors.Wrapf(err, "unable to get images")
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 5595a8331..1346da9fb 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -40,7 +40,7 @@ var (
inspectDescription = "This displays the low-level information on containers and images identified by name or ID. By default, this will render all results in a JSON array. If the container and image have the same name, this will return container JSON for unspecified type."
inspectCommand = cli.Command{
Name: "inspect",
- Usage: "Displays the configuration of a container or image",
+ Usage: "Display the configuration of a container or image",
Description: inspectDescription,
Flags: sortFlags(inspectFlags),
Action: inspectCmd,
diff --git a/cmd/podman/pause.go b/cmd/podman/pause.go
index fcb2f3cb8..9da6abf4b 100644
--- a/cmd/podman/pause.go
+++ b/cmd/podman/pause.go
@@ -25,7 +25,7 @@ var (
`
pauseCommand = cli.Command{
Name: "pause",
- Usage: "Pauses all the processes in one or more containers",
+ Usage: "Pause all the processes in one or more containers",
Description: pauseDescription,
Flags: pauseFlags,
Action: pauseCmd,
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 0ad3f4c73..1708c671c 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -606,19 +606,50 @@ func portsToString(ports []ocicni.PortMapping) string {
}
func printFormat(format string, containers []shared.PsContainerOutput) error {
- out := template.New("output")
- out, err := out.Parse(format + "\n")
+ // return immediately if no containers are present
+ if len(containers) == 0 {
+ return nil
+ }
+
+ // Use a tabwriter to align column format
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
+
+ // Make a map of the field names for the headers
+ headerNames := make(map[string]string)
+ v := reflect.ValueOf(containers[0])
+ t := v.Type()
+ for i := 0; i < t.NumField(); i++ {
+ headerNames[t.Field(i).Name] = t.Field(i).Name
+ }
+
+ // Spit out the header if "table" is present in the format
+ if strings.HasPrefix(format, "table") {
+ hformat := strings.Replace(strings.TrimSpace(format[5:]), " ", "\t", -1)
+ format = hformat
+ headerTmpl, err := template.New("header").Parse(hformat)
+ if err != nil {
+ return err
+ }
+ if err := headerTmpl.Execute(w, headerNames); err != nil {
+ return err
+ }
+ fmt.Fprintln(w, "")
+ }
+ // Spit out the data rows now
+ dataTmpl, err := template.New("data").Parse(format)
if err != nil {
return err
}
+
for _, container := range containers {
- if err := out.Execute(os.Stdout, container); err != nil {
+ if err := dataTmpl.Execute(w, container); err != nil {
return err
}
-
+ fmt.Fprintln(w, "")
}
- return nil
+ // Flush the writer
+ return w.Flush()
}
func dumpJSON(containers []shared.PsContainerOutput) error {
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index fbf860eb2..c904f2f92 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -24,7 +24,7 @@ var (
}
rmiCommand = cli.Command{
Name: "rmi",
- Usage: "Removes one or more images from local storage",
+ Usage: "Remove one or more images from local storage",
Description: rmiDescription,
Action: rmiCmd,
ArgsUsage: "IMAGE-NAME-OR-ID [...]",
diff --git a/cmd/podman/trust.go b/cmd/podman/trust.go
index 863f36d09..a99be6ba2 100644
--- a/cmd/podman/trust.go
+++ b/cmd/podman/trust.go
@@ -6,6 +6,7 @@ import (
"io/ioutil"
"os"
"sort"
+ "strings"
"github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/formats"
@@ -13,6 +14,7 @@ import (
"github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/trust"
"github.com/pkg/errors"
+ "github.com/sirupsen/logrus"
"github.com/urfave/cli"
)
@@ -103,6 +105,7 @@ func showTrustCmd(c *cli.Context) error {
var (
policyPath string
systemRegistriesDirPath string
+ outjson interface{}
)
if c.IsSet("policypath") {
policyPath = c.String("policypath")
@@ -127,30 +130,26 @@ func showTrustCmd(c *cli.Context) error {
return nil
}
- var policyContentStruct trust.PolicyContent
- if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
- return errors.Errorf("could not read trust policies")
- }
- policyJSON, showOutputMap, err := trust.GetPolicy(policyContentStruct, systemRegistriesDirPath)
+ policyContentStruct, err := trust.GetPolicy(policyPath)
if err != nil {
- return errors.Wrapf(err, "error reading registry config file")
+ return errors.Wrapf(err, "could not read trust policies")
}
+
if c.Bool("json") {
- var outjson interface{}
+ policyJSON, err := getPolicyJSON(policyContentStruct, systemRegistriesDirPath)
+ if err != nil {
+ return errors.Wrapf(err, "could not show trust policies in JSON format")
+ }
outjson = policyJSON
out := formats.JSONStruct{Output: outjson}
return formats.Writer(out).Out()
}
- sortedRepos := sortPolicyJSONKey(policyJSON)
- var output []interface{}
- for _, reponame := range sortedRepos {
- showOutput, exists := showOutputMap[reponame]
- if exists {
- output = append(output, interface{}(showOutput))
- }
+ showOutputMap, err := getPolicyShowOutput(policyContentStruct, systemRegistriesDirPath)
+ if err != nil {
+ return errors.Wrapf(err, "could not show trust policies")
}
- out := formats.StdoutTemplateArray{Output: output, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"}
+ out := formats.StdoutTemplateArray{Output: showOutputMap, Template: "{{.Repo}}\t{{.Trusttype}}\t{{.GPGid}}\t{{.Sigstore}}"}
return formats.Writer(out).Out()
}
@@ -159,7 +158,11 @@ func setTrustCmd(c *cli.Context) error {
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
-
+ var (
+ policyPath string
+ policyContentStruct trust.PolicyContent
+ newReposContent []trust.RepoContent
+ )
args := c.Args()
if len(args) != 1 {
return errors.Errorf("default or a registry name must be specified")
@@ -182,17 +185,13 @@ func setTrustCmd(c *cli.Context) error {
return errors.Errorf("At least one public key must be defined for type 'signedBy'")
}
- var policyPath string
if c.IsSet("policypath") {
policyPath = c.String("policypath")
} else {
policyPath = trust.DefaultPolicyPath(runtime.SystemContext())
}
- var policyContentStruct trust.PolicyContent
- policyFileExists := false
_, err = os.Stat(policyPath)
if !os.IsNotExist(err) {
- policyFileExists = true
policyContent, err := ioutil.ReadFile(policyPath)
if err != nil {
return errors.Wrapf(err, "unable to read %s", policyPath)
@@ -200,11 +199,7 @@ func setTrustCmd(c *cli.Context) error {
if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
return errors.Errorf("could not read trust policies")
}
- if args[0] != "default" && len(policyContentStruct.Default) == 0 {
- return errors.Errorf("Default trust policy must be set.")
- }
}
- var newReposContent []trust.RepoContent
if len(pubkeysfile) != 0 {
for _, filepath := range pubkeysfile {
newReposContent = append(newReposContent, trust.RepoContent{Type: trusttype, KeyType: "GPGKeys", KeyPath: filepath})
@@ -215,8 +210,8 @@ func setTrustCmd(c *cli.Context) error {
if args[0] == "default" {
policyContentStruct.Default = newReposContent
} else {
- if policyFileExists == false && len(policyContentStruct.Default) == 0 {
- return errors.Errorf("Default trust policy must be set to create the policy file.")
+ if len(policyContentStruct.Default) == 0 {
+ return errors.Errorf("Default trust policy must be set.")
}
registryExists := false
for transport, transportval := range policyContentStruct.Transports {
@@ -248,7 +243,7 @@ func setTrustCmd(c *cli.Context) error {
return nil
}
-func sortPolicyJSONKey(m map[string]map[string]interface{}) []string {
+func sortShowOutputMapKey(m map[string]trust.ShowOutput) []string {
keys := make([]string, len(m))
i := 0
for k := range m {
@@ -269,3 +264,106 @@ func isValidTrustType(t string) bool {
func getDefaultPolicyPath() string {
return trust.DefaultPolicyPath(&types.SystemContext{})
}
+
+func getPolicyJSON(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, error) {
+ registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
+ if err != nil {
+ return nil, err
+ }
+
+ policyJSON := make(map[string]map[string]interface{})
+ if len(policyContentStruct.Default) > 0 {
+ policyJSON["* (default)"] = make(map[string]interface{})
+ policyJSON["* (default)"]["type"] = policyContentStruct.Default[0].Type
+ }
+ for transname, transval := range policyContentStruct.Transports {
+ for repo, repoval := range transval {
+ policyJSON[repo] = make(map[string]interface{})
+ policyJSON[repo]["type"] = repoval[0].Type
+ policyJSON[repo]["transport"] = transname
+ keyarr := []string{}
+ uids := []string{}
+ for _, repoele := range repoval {
+ if len(repoele.KeyPath) > 0 {
+ keyarr = append(keyarr, repoele.KeyPath)
+ uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...)
+ }
+ if len(repoele.KeyData) > 0 {
+ keyarr = append(keyarr, string(repoele.KeyData))
+ uids = append(uids, trust.GetGPGIdFromKeyData(string(repoele.KeyData))...)
+ }
+ }
+ policyJSON[repo]["keys"] = keyarr
+ policyJSON[repo]["sigstore"] = ""
+ registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs)
+ if registryNamespace != nil {
+ policyJSON[repo]["sigstore"] = registryNamespace.SigStore
+ }
+ }
+ }
+ return policyJSON, nil
+}
+
+var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"}
+
+func trustTypeDescription(trustType string) string {
+ trustDescription, exist := typeDescription[trustType]
+ if !exist {
+ logrus.Warnf("invalid trust type %s", trustType)
+ }
+ return trustDescription
+}
+
+func getPolicyShowOutput(policyContentStruct trust.PolicyContent, systemRegistriesDirPath string) ([]interface{}, error) {
+ var output []interface{}
+
+ registryConfigs, err := trust.LoadAndMergeConfig(systemRegistriesDirPath)
+ if err != nil {
+ return nil, err
+ }
+
+ trustShowOutputMap := make(map[string]trust.ShowOutput)
+ if len(policyContentStruct.Default) > 0 {
+ defaultPolicyStruct := trust.ShowOutput{
+ Repo: "default",
+ Trusttype: trustTypeDescription(policyContentStruct.Default[0].Type),
+ }
+ trustShowOutputMap["* (default)"] = defaultPolicyStruct
+ }
+ for _, transval := range policyContentStruct.Transports {
+ for repo, repoval := range transval {
+ tempTrustShowOutput := trust.ShowOutput{
+ Repo: repo,
+ Trusttype: repoval[0].Type,
+ }
+ keyarr := []string{}
+ uids := []string{}
+ for _, repoele := range repoval {
+ if len(repoele.KeyPath) > 0 {
+ keyarr = append(keyarr, repoele.KeyPath)
+ uids = append(uids, trust.GetGPGIdFromKeyPath(repoele.KeyPath)...)
+ }
+ if len(repoele.KeyData) > 0 {
+ keyarr = append(keyarr, string(repoele.KeyData))
+ uids = append(uids, trust.GetGPGIdFromKeyData(string(repoele.KeyData))...)
+ }
+ }
+ tempTrustShowOutput.GPGid = strings.Join(uids, ", ")
+
+ registryNamespace := trust.HaveMatchRegistry(repo, registryConfigs)
+ if registryNamespace != nil {
+ tempTrustShowOutput.Sigstore = registryNamespace.SigStore
+ }
+ trustShowOutputMap[repo] = tempTrustShowOutput
+ }
+ }
+
+ sortedRepos := sortShowOutputMapKey(trustShowOutputMap)
+ for _, reponame := range sortedRepos {
+ showOutput, exists := trustShowOutputMap[reponame]
+ if exists {
+ output = append(output, interface{}(showOutput))
+ }
+ }
+ return output, nil
+}
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index 7c9b5897b..42f169228 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -34,7 +34,7 @@ An unmount can be forced with the --force flag.
umountCommand = cli.Command{
Name: "umount",
Aliases: []string{"unmount"},
- Usage: "Unmounts working container's root filesystem",
+ Usage: "Unmount working container's root filesystem",
Description: description,
Flags: sortFlags(umountFlags),
Action: umountCmd,
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index 80f0bbdfe..8b02057a1 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -987,17 +987,15 @@ method ContainerRunlabel(runlabel: Runlabel) -> ()
# of strings
# #### Example
# ~~~
-# $ varlink call -m unix:/run/podman/io.podman/io.podman.ListContainerMounts
+# $ varlink call unix:/run/podman/io.podman/io.podman.ListContainerMounts
# {
-# "mounts": [
-# "/var/lib/containers/storage/overlay/b215fb622c65ba3b06c6d2341be80b76a9de7ae415ce419e65228873d4f0dcc8/merged",
-# "/var/lib/containers/storage/overlay/5eaf806073f79c0ed9a695180ad598e34f963f7407da1d2ccf3560bdab49b26f/merged",
-# "/var/lib/containers/storage/overlay/1ecb6b1dbb251737c7a24a31869096839c3719d8b250bf075f75172ddcc701e1/merged",
-# "/var/lib/containers/storage/overlay/7137b28a3c422165fe920cba851f2f8da271c6b5908672c451ebda03ad3919e2/merged"
-# ]
+# "mounts": {
+# "04e4c255269ed2545e7f8bd1395a75f7949c50c223415c00c1d54bfa20f3b3d9": "/var/lib/containers/storage/overlay/a078925828f57e20467ca31cfca8a849210d21ec7e5757332b72b6924f441c17/merged",
+# "1d58c319f9e881a644a5122ff84419dccf6d138f744469281446ab243ef38924": "/var/lib/containers/storage/overlay/948fcf93f8cb932f0f03fd52e3180a58627d547192ffe3b88e0013b98ddcd0d2/merged"
+# }
# }
# ~~~
-method ListContainerMounts() -> (mounts: []string)
+method ListContainerMounts() -> (mounts: [string]string)
# MountContainer mounts a container by name or full/partial ID. Upon a successful mount, the destination
# mount is returned as a string.
diff --git a/contrib/cirrus/build_vm_images.sh b/contrib/cirrus/build_vm_images.sh
index ee45b1ead..6b86aa4d4 100755
--- a/contrib/cirrus/build_vm_images.sh
+++ b/contrib/cirrus/build_vm_images.sh
@@ -42,15 +42,33 @@ then
fi
fi
-set -x
-
cd "$GOSRC/$PACKER_BASE"
+
+# Separate PR-produced images from those produced on master.
+if [[ "${CIRRUS_BRANCH:-}" == "master" ]]
+then
+ POST_MERGE_BUCKET_SUFFIX="-master"
+else
+ POST_MERGE_BUCKET_SUFFIX=""
+fi
+
make libpod_images \
PACKER_BUILDS=$PACKER_BUILDS \
PACKER_VER=$PACKER_VER \
GOSRC=$GOSRC \
SCRIPT_BASE=$SCRIPT_BASE \
PACKER_BASE=$PACKER_BASE \
+ POST_MERGE_BUCKET_SUFFIX=$POST_MERGE_BUCKET_SUFFIX \
BUILT_IMAGE_SUFFIX=$BUILT_IMAGE_SUFFIX
record_timestamp "cache-image build end"
+
+# When successful, upload manifest of produced images using a filename unique
+# to this build.
+URI="gs://packer-import${POST_MERGE_BUCKET_SUFFIX}/manifest${BUILT_IMAGE_SUFFIX}.json"
+gsutil cp packer-manifest.json "$URI"
+
+echo "Finished."
+echo "Any tarball URI's referenced above at at $URI"
+echo "may be used to create VM images suitable for use in"
+echo ".cirrus.yml as values for the 'image_name' keys."
diff --git a/contrib/cirrus/packer/Makefile b/contrib/cirrus/packer/Makefile
index 9bf27373e..0a783e979 100644
--- a/contrib/cirrus/packer/Makefile
+++ b/contrib/cirrus/packer/Makefile
@@ -3,7 +3,7 @@
# builder name(s) from applicable YAML file,
# e.g for names see libpod_images.yml
-PACKER_VER ?= 1.3.1
+PACKER_VER ?= 1.3.2
PACKER_DIST_FILENAME := packer_${PACKER_VER}_linux_amd64.zip
# Only needed for libpod_base_images target
@@ -11,6 +11,7 @@ TIMESTAMP := $(shell date +%s)
GOSRC ?= $(shell realpath "./../../../")
PACKER_BASE ?= contrib/cirrus/packer
SCRIPT_BASE ?= contrib/cirrus
+POST_MERGE_BUCKET_SUFFIX ?=
# For debugging nested-virt, use
#TTYDEV := $(shell tty)
@@ -50,10 +51,6 @@ endif
-var PACKER_BASE=$(PACKER_BASE) \
-var SCRIPT_BASE=$(SCRIPT_BASE) \
libpod_images.json
- @echo ""
- @echo "Finished. The images mentioned above, and in packer-manifest.json"
- @echo "can be used in .cirrus.yml as values for the 'image_name' keys"
- @echo ""
cidata.ssh:
ssh-keygen -f $@ -P "" -q
@@ -100,9 +97,6 @@ endif
-var RHEL_IMAGE_FILE=$(RHEL_IMAGE_FILE) \
-var RHEL_CSUM_FILE=$(RHEL_CSUM_FILE) \
-var 'RHSM_COMMAND=$(RHSM_COMMAND)' \
+ -var POST_MERGE_BUCKET_SUFFIX=$(POST_MERGE_BUCKET_SUFFIX) \
-only $(PACKER_BUILDS) \
libpod_base_images.json
- @echo ""
- @echo "Finished. The images mentioned above, and in packer-manifest.json"
- @echo "can be used in .cirrus.yml as values for the *_BASE_IMAGE keys."
- @echo ""
diff --git a/contrib/cirrus/packer/centos_setup.sh b/contrib/cirrus/packer/centos_setup.sh
index a13050569..923f2563b 100644
--- a/contrib/cirrus/packer/centos_setup.sh
+++ b/contrib/cirrus/packer/centos_setup.sh
@@ -25,6 +25,7 @@ ooe.sh sudo yum -y update
ooe.sh sudo yum -y install centos-release-scl epel-release
ooe.sh sudo yum -y install \
+ PyYAML \
atomic-registries \
btrfs-progs-devel \
bzip2 \
diff --git a/contrib/cirrus/packer/image-builder-image_base-setup.sh b/contrib/cirrus/packer/image-builder-image_base-setup.sh
index b8e2824a7..8cf9fd8ab 100644
--- a/contrib/cirrus/packer/image-builder-image_base-setup.sh
+++ b/contrib/cirrus/packer/image-builder-image_base-setup.sh
@@ -45,10 +45,13 @@ ooe.sh sudo yum -y install \
qemu-kvm-tools \
qemu-user \
rsync \
+ rng-tools \
unzip \
util-linux \
vim
+sudo systemctl enable rngd
+
sudo ln -s /usr/libexec/qemu-kvm /usr/bin/
sudo tee /etc/modprobe.d/kvm-nested.conf <<EOF
diff --git a/contrib/cirrus/packer/libpod_base_images.yml b/contrib/cirrus/packer/libpod_base_images.yml
index 109b9b8d5..bf568b40e 100644
--- a/contrib/cirrus/packer/libpod_base_images.yml
+++ b/contrib/cirrus/packer/libpod_base_images.yml
@@ -105,7 +105,7 @@ builders:
ssh_username: 'root'
- <<: *nested_virt
- name: 'prior_fedora'
+ name: 'prior-fedora'
iso_url: '{{user `PRIOR_FEDORA_IMAGE_URL`}}'
iso_checksum_url: '{{user `PRIOR_FEDORA_CSUM_URL`}}'
@@ -161,7 +161,7 @@ provisioners:
post-processors:
- - type: "compress"
- only: ['fedora', 'prior_fedora', 'fah', 'rhel']
+ only: ['fedora', 'prior-fedora', 'fah', 'rhel']
output: '/tmp/{{build_name}}/disk.raw.tar.gz'
format: '.tar.gz'
compression_level: 9
@@ -171,12 +171,12 @@ post-processors:
project_id: '{{user `GCP_PROJECT_ID`}}'
account_file: '{{user `GOOGLE_APPLICATION_CREDENTIALS`}}'
bucket: '{{user `XFERBUCKET`}}'
- gcs_object_name: '{{build_name}}-{{user `TIMESTAMP`}}-{{uuid}}.tar.gz'
+ gcs_object_name: '{{build_name}}-{{user `TIMESTAMP`}}.tar.gz'
image_name: "{{user `FEDORA_BASE_IMAGE_NAME`}}-{{user `TIMESTAMP`}}"
image_description: 'Based on {{user `FEDORA_IMAGE_URL`}}'
image_family: '{{user `FEDORA_BASE_IMAGE_NAME`}}'
- <<: *gcp_import
- only: ['prior_fedora']
+ only: ['prior-fedora']
image_name: "{{user `PRIOR_FEDORA_BASE_IMAGE_NAME`}}-{{user `TIMESTAMP`}}"
image_description: 'Based on {{user `PRIOR_FEDORA_IMAGE_URL`}}'
image_family: '{{user `PRIOR_FEDORA_BASE_IMAGE_NAME`}}'
diff --git a/contrib/cirrus/packer/libpod_images.yml b/contrib/cirrus/packer/libpod_images.yml
index d31c11a8d..30ad0723a 100644
--- a/contrib/cirrus/packer/libpod_images.yml
+++ b/contrib/cirrus/packer/libpod_images.yml
@@ -29,6 +29,10 @@ variables:
SERVICE_ACCOUNT: '{{env `SERVICE_ACCOUNT`}}'
GOOGLE_APPLICATION_CREDENTIALS: '{{env `GOOGLE_APPLICATION_CREDENTIALS`}}'
+ # Used to separate images produced during PR testing from those
+ # produced from post-merge testing. Must be empty for PR testing.
+ POST_MERGE_BUCKET_SUFFIX: ''
+
# Don't leak sensitive values in error messages / output
sensitive-variables:
- 'GCE_SSH_USERNAME'
@@ -84,13 +88,18 @@ provisioners:
- type: 'shell'
script: '{{user `GOSRC`}}/{{user `PACKER_BASE`}}/{{split build_name "-" 0}}_setup.sh'
environment_vars:
- - 'SCRIPT_BASE={{user `SCRIPT_BASE`}}'
+ - 'GOSRC=/tmp/libpod'
- 'CNI_COMMIT={{user `CNI_COMMIT`}}'
- 'FEDORA_CNI_COMMIT={{user `FEDORA_CNI_COMMIT`}}'
- 'CRIO_COMMIT={{user `CRIO_COMMIT`}}'
- 'CRIU_COMMIT={{user `CRIU_COMMIT`}}'
- 'RUNC_COMMIT={{user `RUNC_COMMIT`}}'
+ - 'SCRIPT_BASE={{user `SCRIPT_BASE`}}'
- 'RHSM_COMMAND={{user `RHSM_COMMAND`}}'
post-processors:
- - - type: 'manifest'
+ # Store VM disk in GCP storage, where it will expire based on a defined
+ # lifecycle. This prevents GCE from filling with disused images.
+ - - type: 'googlecompute-export'
+ paths: ['gs://packer-import{{user `POST_MERGE_BUCKET_SUFFIX`}}/{{build_name}}{{user `BUILT_IMAGE_SUFFIX`}}.tar.gz']
+ - type: 'manifest' # writes packer-manifest.json
diff --git a/contrib/cirrus/packer/rhel_base-setup.sh b/contrib/cirrus/packer/rhel_base-setup.sh
index 8b2073d4f..fbf9f61af 100644
--- a/contrib/cirrus/packer/rhel_base-setup.sh
+++ b/contrib/cirrus/packer/rhel_base-setup.sh
@@ -16,6 +16,8 @@ req_env_var "
install_ooe
+rhsm_enable
+
echo "Setting up repos"
# Frequently needed
ooe.sh sudo yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
@@ -32,12 +34,15 @@ gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
EOM
-rhsm_enable
+echo "Updating all packages"
+ooe.sh sudo yum -y update
echo "Installing/removing packages"
-ooe.sh sudo yum -y install google-compute-engine google-compute-engine-oslogin
-ooe.sh sudo yum -y erase "cloud-init" "rh-amazon-rhui-client*" || true
+ooe.sh sudo yum -y install rng-tools google-compute-engine google-compute-engine-oslogin
+
+echo "Enabling critical services"
ooe.sh sudo systemctl enable \
+ rngd \
google-accounts-daemon \
google-clock-skew-daemon \
google-instance-setup \
@@ -47,6 +52,29 @@ ooe.sh sudo systemctl enable \
rhel_exit_handler # release subscription!
+echo "Configuring boot"
+cat << "EOF" | sudo tee /etc/default/grub
+GRUB_TIMEOUT=0
+GRUB_DISTRIBUTOR="$(sed 's, release .*$,,g' /etc/system-release)"
+GRUB_DEFAULT=saved
+GRUB_DISABLE_SUBMENU=true
+GRUB_TERMINAL="serial console"
+GRUB_SERIAL_COMMAND="serial --speed=38400"
+GRUB_CMDLINE_LINUX="crashkernel=auto console=ttyS0,38400n8"
+GRUB_DISABLE_RECOVERY="true"
+EOF
+sudo grub2-mkconfig -o /boot/grub2/grub.cfg
+
+echo "Configuring networking"
+ooe.sh sudo nmcli connection modify 'System eth0' 802-3-ethernet.mtu 1460
+ooe.sh sudo nmcli connection modify 'System eth0' connection.autoconnect yes
+ooe.sh sudo nmcli connection modify 'System eth0' connection.autoconnect-priority
+ooe.sh sudo nmcli connection modify 'System eth0' ipv4.method auto
+ooe.sh sudo nmcli connection modify 'System eth0' ipv4.dhcp-send-hostname yes
+ooe.sh sudo nmcli connection modify 'System eth0' ipv4.dhcp-timeout 0
+ooe.sh sudo nmcli connection modify 'System eth0' ipv4.never-default no
+ooe.sh /usr/bin/google_instance_setup
+
rh_finalize
echo "SUCCESS!"
diff --git a/contrib/cirrus/packer/rhel_setup.sh b/contrib/cirrus/packer/rhel_setup.sh
index 99376fd65..ac6866a57 100644
--- a/contrib/cirrus/packer/rhel_setup.sh
+++ b/contrib/cirrus/packer/rhel_setup.sh
@@ -31,6 +31,7 @@ ooe.sh sudo subscription-manager repos \
ooe.sh sudo yum -y update
ooe.sh sudo yum -y install \
+ PyYAML \
atomic-registries \
btrfs-progs-devel \
bzip2 \
@@ -64,9 +65,11 @@ ooe.sh sudo yum -y install \
protobuf-python \
python \
python2-future \
+ python2-pyyaml \
python34-dateutil \
python34-psutil \
python34-pytoml \
+ python34-PyYAML \
runc \
skopeo-containers \
unzip \
diff --git a/contrib/imgts/Dockerfile b/contrib/imgts/Dockerfile
new file mode 100644
index 000000000..0746eca4c
--- /dev/null
+++ b/contrib/imgts/Dockerfile
@@ -0,0 +1,20 @@
+FROM centos:7
+
+# Only needed for installing build-time dependencies
+COPY /contrib/imgts/google-cloud-sdk.repo /etc/yum.repos.d/google-cloud-sdk.repo
+RUN yum -y update && \
+ yum -y install epel-release && \
+ yum -y install google-cloud-sdk && \
+ yum clean all
+
+COPY /contrib/imgts/entrypoint.sh /usr/local/bin/entrypoint.sh
+ENV GCPJSON="__unknown__" \
+ GCPNAME="__unknown__" \
+ GCPPROJECT="__unknown__" \
+ IMGNAMES="__unknown__" \
+ TIMESTAMP="__unknown__" \
+ BUILDID="__unknown__" \
+ REPOREF="__unknown__"
+RUN chmod 755 /usr/local/bin/entrypoint.sh
+
+ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]
diff --git a/contrib/imgts/README.md b/contrib/imgts/README.md
new file mode 100644
index 000000000..ad5ed4172
--- /dev/null
+++ b/contrib/imgts/README.md
@@ -0,0 +1,11 @@
+![PODMAN logo](../../logo/podman-logo-source.svg)
+
+A container image for tracking automation metadata.
+Currently this is used to update last-used timestamps on
+VM images.
+
+Example build (from repository root):
+
+```bash
+sudo podman build -t $IMAGE_NAME -f contrib/imgts/Dockerfile .
+```
diff --git a/contrib/imgts/entrypoint.sh b/contrib/imgts/entrypoint.sh
new file mode 100755
index 000000000..65a76d8e4
--- /dev/null
+++ b/contrib/imgts/entrypoint.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+
+set -e
+
+RED="\e[1;36;41m"
+YEL="\e[1;33;44m"
+NOR="\e[0m"
+
+die() {
+ echo -e "$2" >&2
+ exit "$1"
+}
+
+SENTINEL="__unknown__" # default set in dockerfile
+
+[[ "$GCPJSON" != "$SENTINEL" ]] || \
+ die 1 "Must specify service account JSON in \$GCPJSON"
+[[ "$GCPNAME" != "$SENTINEL" ]] || \
+ die 2 "Must specify service account name in \$GCPNAME"
+[[ "$GCPPROJECT" != "$SENTINEL" ]] || \
+ die 4 "Must specify GCP Project ID in \$GCPPROJECT"
+[[ -n "$GCPPROJECT" ]] || \
+ die 5 "Must specify non-empty GCP Project ID in \$GCPPROJECT"
+[[ "$IMGNAMES" != "$SENTINEL" ]] || \
+ die 6 "Must specify space separated list of GCE image names in \$IMGNAMES"
+[[ "$BUILDID" != "$SENTINEL" ]] || \
+ die 7 "Must specify the number of current build in \$BUILDID"
+[[ "$REPOREF" != "$SENTINEL" ]] || \
+ die 8 "Must specify a PR number or Branch name in \$REPOREF"
+
+ARGS="--update-labels=last-used=$(date +%s)"
+# optional
+[[ -z "$BUILDID" ]] || ARGS="$ARGS --update-labels=build-id=$BUILDID"
+[[ -z "$REPOREF" ]] || ARGS="$ARGS --update-labels=repo-ref=$REPOREF"
+
+gcloud config set account "$GCPNAME"
+gcloud config set project "$GCPPROJECT"
+echo "$GCPJSON" > /tmp/gcp.json
+gcloud auth activate-service-account --key-file=/tmp/gcp.json || rm /tmp/gcp.json
+for image in $IMGNAMES
+do
+ gcloud compute images update "$image" $ARGS &
+done
+set +e # Actual update failures are only warnings
+wait || die 0 "${RED}WARNING:$NOR ${YEL}Failed to update labels on one or more images:$NOR '$IMGNAMES'"
diff --git a/contrib/imgts/google-cloud-sdk.repo b/contrib/imgts/google-cloud-sdk.repo
new file mode 100644
index 000000000..45b1e43bb
--- /dev/null
+++ b/contrib/imgts/google-cloud-sdk.repo
@@ -0,0 +1,8 @@
+[google-cloud-sdk]
+name=Google Cloud SDK
+baseurl=https://packages.cloud.google.com/yum/repos/cloud-sdk-el7-x86_64
+enabled=1
+gpgcheck=1
+repo_gpgcheck=1
+gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg
+ https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
diff --git a/docs/podman-image-trust.1.md b/docs/podman-image-trust.1.md
index 3b6564315..668fee0f3 100644
--- a/docs/podman-image-trust.1.md
+++ b/docs/podman-image-trust.1.md
@@ -9,22 +9,24 @@ podman\-trust - Manage container registry image trust policy
[**-h**|**--help**]
[**-j**|**--json**]
[**--raw**]
-[**-f**|**--pubkeysfile** KEY1 [**f**|**--pubkeysfile** KEY2,...]]
+[**-f**|**--pubkeysfile** KEY1 [**-f**|**--pubkeysfile** KEY2,...]]
[**-t**|**--type** signedBy|accept|reject]
REGISTRY[/REPOSITORY]
# DESCRIPTION
-Manages the trust policy of the host system. Trust policy describes
-a registry scope (registry and/or repository) that must be signed by public keys. Trust
-is defined in **/etc/containers/policy.json**. Trust is enforced when a user attempts to pull
-an image from a registry.
+Manages which registries you trust as a source of container images based on its location. The location is determined by the transport and the registry host of the image. Using this container image `docker://docker.io/library/busybox` as an example, `docker` is the transport and `docker.io` is the registry host.
-Trust scope is evaluated by most specific to least specific. In other words, policy may
-be defined for an entire registry, but refined for a particular repository in that
-registry. See below for examples.
+The trust policy describes a registry scope (registry and/or repository). This trust can use public keys for signed images.
+
+Trust is defined in **/etc/containers/policy.json** and is enforced when a user attempts to pull an image from a registry that is managed by policy.json.
+
+The scope of the trust is evaluated from most specific to the least specific. In other words, a policy may be defined for an entire registry. Or it could be defined for a particular repository in that registry. Or it could be defined down to a specific signed image inside of the registry. See below for examples.
+
+Trust **type** provides a way to:
+
+Whitelist ("accept") or
+Blacklist ("reject") registries.
-Trust **type** provides a way to whitelist ("accept") or blacklist
-("reject") registries.
Trust may be updated using the command **podman image trust set** for an existing trust scope.
@@ -34,10 +36,10 @@ Trust may be updated using the command **podman image trust set** for an existin
**-f** **--pubkeysfile**
A path to an exported public key on the local system. Key paths
- will be referenced in policy.json. Any path may be used but path
- **/etc/pki/containers** is recommended. Option may be used multiple times to
- require an image be sigend by multiple keys. One of **--pubkeys** or
- **--pubkeysfile** is required for **signedBy** type.
+ will be referenced in policy.json. Any path may be used but the path
+ **/etc/pki/containers** is recommended. Options may be used multiple times to
+ require an image be signed by multiple keys. One of **--pubkeys** or
+ **--pubkeysfile** is required for the **signedBy** type.
**-t** **--type**
The trust type for this policy entry. Accepted values:
@@ -59,23 +61,30 @@ Trust may be updated using the command **podman image trust set** for an existin
Accept all unsigned images from a registry
- podman image trust set --type accept docker.io
+ sudo podman image trust set --type accept docker.io
Modify default trust policy
- podman image trust set -t reject default
+ sudo podman image trust set -t reject default
Display system trust policy
- podman image trust show
+ sudo podman image trust show
Display trust policy file
- podman image trust show --raw
+ sudo podman image trust show --raw
Display trust as JSON
- podman image trust show --json
+ sudo podman image trust show --json
+
+# SEE ALSO
+
+policy-json(5)
# HISTORY
+
+January 2019, updated by Tom Sweeney (tsweeney at redhat dot com)
+
December 2018, originally compiled by Qi Wang (qiwan at redhat dot com)
diff --git a/docs/podman.1.md b/docs/podman.1.md
index 74e700fac..6200a07f0 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -1,19 +1,21 @@
% podman(1)
## NAME
-podman - Simple management tool for containers and images
+podman - Simple management tool for pods, containers and images
## SYNOPSIS
**podman** [*options*] *command*
## DESCRIPTION
-podman is a simple client only tool to help with debugging issues when daemons
-such as CRI runtime and the kubelet are not responding or failing. A shared API
-layer could be created to share code between the daemon and podman. podman does not
-require any daemon running. podman utilizes the same underlying components that
-crio uses i.e. containers/image, container/storage, oci-runtime-tool/generate,
-runc or any other OCI compatible runtime. podman shares state with crio and so
-has the capability to debug pods/images created by crio.
+Podman (Pod Manager) is a fully featured container engine that is a simple daemonless tool.
+Podman provides a Docker-CLI comparable command line that eases the transition from other
+container engines and allows the management of pods, containers and images. Simply put: `alias docker=podman`.
+Most Podman commands can be run as a regular user, without requiring additional
+privileges.
+
+Podman uses Buildah(1) internally to create container images. Both tools share image
+(not container) storage, hence each can use or manipulate images (but not containers)
+created by the other.
**podman [GLOBAL OPTIONS]**
@@ -220,7 +222,7 @@ Images are pulled under `XDG_DATA_HOME` when specified, otherwise in the home di
Currently the slirp4netns package is required to be installed to create a network device, otherwise rootless containers need to run in the network namespace of the host.
## SEE ALSO
-`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `crio(8)`, `libpod.conf(5)`, `oci-hooks(5)`, `policy.json(5)`, `subuid(5)`, `subgid(5)`, `slirp4netns(1)`
+`containers-mounts.conf(5)`, `containers-registries.conf(5)`, `containers-storage.conf(5)`, `buildah(1)`, `crio(8)`, `libpod.conf(5)`, `oci-hooks(5)`, `policy.json(5)`, `subuid(5)`, `subgid(5)`, `slirp4netns(1)`
## HISTORY
Dec 2016, Originally compiled by Dan Walsh <dwalsh@redhat.com>
diff --git a/libpod/image/image.go b/libpod/image/image.go
index ea326d820..a32336f49 100644
--- a/libpod/image/image.go
+++ b/libpod/image/image.go
@@ -823,9 +823,9 @@ func (i *Image) Inspect(ctx context.Context) (*inspect.ImageData, error) {
return nil, err
}
- var repoDigests []string
- for _, name := range i.Names() {
- repoDigests = append(repoDigests, strings.SplitN(name, ":", 2)[0]+"@"+i.Digest().String())
+ repoDigests, err := i.RepoDigests()
+ if err != nil {
+ return nil, err
}
driver, err := i.DriverData()
diff --git a/pkg/trust/trust.go b/pkg/trust/trust.go
index 31e41903e..9a75474ae 100644
--- a/pkg/trust/trust.go
+++ b/pkg/trust/trust.go
@@ -175,43 +175,30 @@ func CreateTmpFile(dir, pattern string, content []byte) (string, error) {
return tmpfile.Name(), nil
}
-func getGPGIdFromKeyPath(path []string) []string {
- var uids []string
- for _, k := range path {
- cmd := exec.Command("gpg2", "--with-colons", k)
- results, err := cmd.Output()
- if err != nil {
- logrus.Warnf("error get key identity: %s", err)
- continue
- }
- uids = append(uids, parseUids(results)...)
+// GetGPGIdFromKeyPath return user keyring from key path
+func GetGPGIdFromKeyPath(path string) []string {
+ cmd := exec.Command("gpg2", "--with-colons", path)
+ results, err := cmd.Output()
+ if err != nil {
+ logrus.Errorf("error getting key identity: %s", err)
+ return nil
}
- return uids
+ return parseUids(results)
}
-func getGPGIdFromKeyData(keys []string) []string {
- var uids []string
- for _, k := range keys {
- decodeKey, err := base64.StdEncoding.DecodeString(k)
- if err != nil {
- logrus.Warnf("error decoding key data")
- continue
- }
- tmpfileName, err := CreateTmpFile("", "", decodeKey)
- if err != nil {
- logrus.Warnf("error creating key date temp file %s", err)
- }
- defer os.Remove(tmpfileName)
- k = tmpfileName
- cmd := exec.Command("gpg2", "--with-colons", k)
- results, err := cmd.Output()
- if err != nil {
- logrus.Warnf("error get key identity: %s", err)
- continue
- }
- uids = append(uids, parseUids(results)...)
+// GetGPGIdFromKeyData return user keyring from keydata
+func GetGPGIdFromKeyData(key string) []string {
+ decodeKey, err := base64.StdEncoding.DecodeString(key)
+ if err != nil {
+ logrus.Errorf("%s, error decoding key data", err)
+ return nil
}
- return uids
+ tmpfileName, err := CreateTmpFile("", "", decodeKey)
+ if err != nil {
+ logrus.Errorf("error creating key date temp file %s", err)
+ }
+ defer os.Remove(tmpfileName)
+ return GetGPGIdFromKeyPath(tmpfileName)
}
func parseUids(colonDelimitKeys []byte) []string {
@@ -234,68 +221,15 @@ func parseUids(colonDelimitKeys []byte) []string {
return parseduids
}
-var typeDescription = map[string]string{"insecureAcceptAnything": "accept", "signedBy": "signed", "reject": "reject"}
-
-func trustTypeDescription(trustType string) string {
- trustDescription, exist := typeDescription[trustType]
- if !exist {
- logrus.Warnf("invalid trust type %s", trustType)
- }
- return trustDescription
-}
-
-// GetPolicy return the struct to show policy.json in json format and a map (reponame, ShowOutput) pair for image trust show command
-func GetPolicy(policyContentStruct PolicyContent, systemRegistriesDirPath string) (map[string]map[string]interface{}, map[string]ShowOutput, error) {
- registryConfigs, err := LoadAndMergeConfig(systemRegistriesDirPath)
+// GetPolicy parse policy.json into PolicyContent struct
+func GetPolicy(policyPath string) (PolicyContent, error) {
+ var policyContentStruct PolicyContent
+ policyContent, err := ioutil.ReadFile(policyPath)
if err != nil {
- return nil, nil, err
+ return policyContentStruct, errors.Wrapf(err, "unable to read policy file %s", policyPath)
}
-
- trustShowOutputMap := make(map[string]ShowOutput)
- policyJSON := make(map[string]map[string]interface{})
- if len(policyContentStruct.Default) > 0 {
- policyJSON["* (default)"] = make(map[string]interface{})
- policyJSON["* (default)"]["type"] = policyContentStruct.Default[0].Type
-
- var defaultPolicyStruct ShowOutput
- defaultPolicyStruct.Repo = "default"
- defaultPolicyStruct.Trusttype = trustTypeDescription(policyContentStruct.Default[0].Type)
- trustShowOutputMap["* (default)"] = defaultPolicyStruct
- }
- for transname, transval := range policyContentStruct.Transports {
- for repo, repoval := range transval {
- tempTrustShowOutput := ShowOutput{
- Repo: repo,
- Trusttype: repoval[0].Type,
- }
- policyJSON[repo] = make(map[string]interface{})
- policyJSON[repo]["type"] = repoval[0].Type
- policyJSON[repo]["transport"] = transname
- keyDataArr := []string{}
- keyPathArr := []string{}
- keyarr := []string{}
- for _, repoele := range repoval {
- if len(repoele.KeyPath) > 0 {
- keyarr = append(keyarr, repoele.KeyPath)
- keyPathArr = append(keyPathArr, repoele.KeyPath)
- }
- if len(repoele.KeyData) > 0 {
- keyarr = append(keyarr, string(repoele.KeyData))
- keyDataArr = append(keyDataArr, string(repoele.KeyData))
- }
- }
- policyJSON[repo]["keys"] = keyarr
- uids := append(getGPGIdFromKeyPath(keyPathArr), getGPGIdFromKeyData(keyDataArr)...)
- tempTrustShowOutput.GPGid = strings.Join(uids, ",")
-
- policyJSON[repo]["sigstore"] = ""
- registryNamespace := HaveMatchRegistry(repo, registryConfigs)
- if registryNamespace != nil {
- policyJSON[repo]["sigstore"] = registryNamespace.SigStore
- tempTrustShowOutput.Sigstore = registryNamespace.SigStore
- }
- trustShowOutputMap[repo] = tempTrustShowOutput
- }
+ if err := json.Unmarshal(policyContent, &policyContentStruct); err != nil {
+ return policyContentStruct, errors.Wrapf(err, "could not parse trust policies")
}
- return policyJSON, trustShowOutputMap, nil
+ return policyContentStruct, nil
}
diff --git a/pkg/varlinkapi/mount.go b/pkg/varlinkapi/mount.go
index 84e6b2709..3b4fe87e3 100644
--- a/pkg/varlinkapi/mount.go
+++ b/pkg/varlinkapi/mount.go
@@ -6,7 +6,7 @@ import (
// ListContainerMounts ...
func (i *LibpodAPI) ListContainerMounts(call iopodman.VarlinkCall) error {
- var mounts []string
+ mounts := make(map[string]string)
allContainers, err := i.Runtime.GetAllContainers()
if err != nil {
return call.ReplyErrorOccurred(err.Error())
@@ -17,7 +17,7 @@ func (i *LibpodAPI) ListContainerMounts(call iopodman.VarlinkCall) error {
return call.ReplyErrorOccurred(err.Error())
}
if mounted {
- mounts = append(mounts, mountPoint)
+ mounts[container.ID()] = mountPoint
}
}
return call.ReplyListContainerMounts(mounts)
diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go
index 2022dff1b..637c04e0a 100644
--- a/test/e2e/info_test.go
+++ b/test/e2e/info_test.go
@@ -35,7 +35,7 @@ var _ = Describe("Podman Info", func() {
It("podman info json output", func() {
session := podmanTest.Podman([]string{"info", "--format=json"})
- session.Wait()
+ session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
})
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index bff2427d5..9b1c55bb4 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -7,6 +7,7 @@ import (
"os"
"regexp"
"sort"
+ "strings"
. "github.com/containers/libpod/test/utils"
"github.com/docker/go-units"
@@ -148,10 +149,12 @@ var _ = Describe("Podman ps", func() {
_, ec, _ := podmanTest.RunLsContainer("test1")
Expect(ec).To(Equal(0))
- result := podmanTest.Podman([]string{"ps", "-a", "--format", "\"table {{.ID}} {{.Image}} {{.Labels}}\""})
+ result := podmanTest.Podman([]string{"ps", "-a", "--format", "table {{.ID}} {{.Image}} {{.Labels}}"})
result.WaitWithDefaultTimeout()
+ Expect(strings.Contains(result.OutputToStringArray()[0], "table")).To(BeFalse())
+ Expect(strings.Contains(result.OutputToStringArray()[0], "ID")).To(BeTrue())
+ Expect(strings.Contains(result.OutputToStringArray()[1], "alpine:latest")).To(BeTrue())
Expect(result.ExitCode()).To(Equal(0))
- Expect(result.IsJSONOutputValid()).To(BeTrue())
})
It("podman ps ancestor filter flag", func() {
diff --git a/vendor.conf b/vendor.conf
index 76c2b8810..4a62c6be7 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -15,7 +15,7 @@ github.com/containerd/cgroups 39b18af02c4120960f517a3a4c2588fabb61d02c
github.com/containerd/continuity 004b46473808b3e7a4a3049c20e4376c91eb966d
github.com/containernetworking/cni v0.7.0-alpha1
github.com/containernetworking/plugins v0.7.4
-github.com/containers/image v1.3
+github.com/containers/image 67b1f789f2ce8a3654592a582fff26c396326236
github.com/containers/storage v1.8
github.com/containers/psgo v1.1
github.com/coreos/go-systemd v14
diff --git a/vendor/github.com/containers/image/copy/copy.go b/vendor/github.com/containers/image/copy/copy.go
index 89c7e580f..e783416ad 100644
--- a/vendor/github.com/containers/image/copy/copy.go
+++ b/vendor/github.com/containers/image/copy/copy.go
@@ -6,6 +6,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "os"
"reflect"
"runtime"
"strings"
@@ -22,6 +23,7 @@ import (
"github.com/opencontainers/go-digest"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
+ "golang.org/x/crypto/ssh/terminal"
"golang.org/x/sync/semaphore"
pb "gopkg.in/cheggaaa/pb.v1"
)
@@ -84,6 +86,7 @@ type copier struct {
dest types.ImageDestination
rawSource types.ImageSource
reportWriter io.Writer
+ progressOutput io.Writer
progressInterval time.Duration
progress chan types.ProgressProperties
blobInfoCache types.BlobInfoCache
@@ -152,11 +155,19 @@ func Image(ctx context.Context, policyContext *signature.PolicyContext, destRef,
}
}()
+ // If reportWriter is not a TTY (e.g., when piping to a file), do not
+ // print the progress bars to avoid long and hard to parse output.
+ // createProgressBar() will print a single line instead.
+ progressOutput := reportWriter
+ if !isTTY(reportWriter) {
+ progressOutput = ioutil.Discard
+ }
copyInParallel := dest.HasThreadSafePutBlob() && rawSource.HasThreadSafeGetBlob()
c := &copier{
dest: dest,
rawSource: rawSource,
reportWriter: reportWriter,
+ progressOutput: progressOutput,
progressInterval: options.ProgressInterval,
progress: options.Progress,
copyInParallel: copyInParallel,
@@ -394,17 +405,30 @@ func shortDigest(d digest.Digest) string {
return d.Encoded()[:12]
}
-// createProgressBar creates a pb.ProgressBar.
-func createProgressBar(srcInfo types.BlobInfo, kind string, writer io.Writer) *pb.ProgressBar {
+// createProgressBar creates a pb.ProgressBar. Note that if the copier's
+// reportWriter is ioutil.Discard, the progress bar's output will be discarded
+// and a single line will be printed instead.
+func (c *copier) createProgressBar(srcInfo types.BlobInfo, kind string) *pb.ProgressBar {
bar := pb.New(int(srcInfo.Size)).SetUnits(pb.U_BYTES)
bar.SetMaxWidth(80)
bar.ShowTimeLeft = false
bar.ShowPercent = false
bar.Prefix(fmt.Sprintf("Copying %s %s:", kind, shortDigest(srcInfo.Digest)))
- bar.Output = writer
+ bar.Output = c.progressOutput
+ if bar.Output == ioutil.Discard {
+ c.Printf("Copying %s %s\n", kind, srcInfo.Digest)
+ }
return bar
}
+// isTTY returns true if the io.Writer is a file and a tty.
+func isTTY(w io.Writer) bool {
+ if f, ok := w.(*os.File); ok {
+ return terminal.IsTerminal(int(f.Fd()))
+ }
+ return false
+}
+
// copyLayers copies layers from ic.src/ic.c.rawSource to dest, using and updating ic.manifestUpdates if necessary and ic.canModifyManifest.
func (ic *imageCopier) copyLayers(ctx context.Context) error {
srcInfos := ic.src.LayerInfos()
@@ -456,7 +480,7 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
bar.Finish()
} else {
cld.destInfo = srcLayer
- logrus.Debugf("Skipping foreign layer %q copy to %s\n", cld.destInfo.Digest, ic.c.dest.Reference().Transport().Name())
+ logrus.Debugf("Skipping foreign layer %q copy to %s", cld.destInfo.Digest, ic.c.dest.Reference().Transport().Name())
bar.Prefix(fmt.Sprintf("Skipping blob %s (foreign layer):", shortDigest(srcLayer.Digest)))
bar.Add64(bar.Total)
bar.Finish()
@@ -469,12 +493,13 @@ func (ic *imageCopier) copyLayers(ctx context.Context) error {
progressBars := make([]*pb.ProgressBar, numLayers)
for i, srcInfo := range srcInfos {
- bar := createProgressBar(srcInfo, "blob", nil)
+ bar := ic.c.createProgressBar(srcInfo, "blob")
progressBars[i] = bar
}
progressPool := pb.NewPool(progressBars...)
- progressPool.Output = ic.c.reportWriter
+ progressPool.Output = ic.c.progressOutput
+
if err := progressPool.Start(); err != nil {
return errors.Wrapf(err, "error creating progress-bar pool")
}
@@ -568,7 +593,7 @@ func (c *copier) copyConfig(ctx context.Context, src types.Image) error {
if err != nil {
return errors.Wrapf(err, "Error reading config blob %s", srcInfo.Digest)
}
- bar := createProgressBar(srcInfo, "config", c.reportWriter)
+ bar := c.createProgressBar(srcInfo, "config")
defer bar.Finish()
bar.Start()
destInfo, err := c.copyBlobFromStream(ctx, bytes.NewReader(configBlob), srcInfo, nil, false, true, bar)
diff --git a/vendor/github.com/containers/image/docker/docker_client.go b/vendor/github.com/containers/image/docker/docker_client.go
index 23d2ac70f..43eb22ba2 100644
--- a/vendor/github.com/containers/image/docker/docker_client.go
+++ b/vendor/github.com/containers/image/docker/docker_client.go
@@ -91,7 +91,6 @@ type dockerClient struct {
password string
signatureBase signatureStorageBase
scope authScope
- extraScope *authScope // If non-nil, a temporary extra token scope (necessary for mounting from another repo)
// The following members are detected registry properties:
// They are set after a successful detectProperties(), and never change afterwards.
scheme string // Empty value also used to indicate detectProperties() has not yet succeeded.
@@ -282,7 +281,7 @@ func CheckAuth(ctx context.Context, sys *types.SystemContext, username, password
client.username = username
client.password = password
- resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth)
+ resp, err := client.makeRequest(ctx, "GET", "/v2/", nil, nil, v2Auth, nil)
if err != nil {
return err
}
@@ -362,8 +361,8 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
q.Set("n", strconv.Itoa(limit))
u.RawQuery = q.Encode()
- logrus.Debugf("trying to talk to v1 search endpoint\n")
- resp, err := client.makeRequest(ctx, "GET", u.String(), nil, nil, noAuth)
+ logrus.Debugf("trying to talk to v1 search endpoint")
+ resp, err := client.makeRequest(ctx, "GET", u.String(), nil, nil, noAuth, nil)
if err != nil {
logrus.Debugf("error getting search results from v1 endpoint %q: %v", registry, err)
} else {
@@ -379,8 +378,8 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
}
}
- logrus.Debugf("trying to talk to v2 search endpoint\n")
- resp, err := client.makeRequest(ctx, "GET", "/v2/_catalog", nil, nil, v2Auth)
+ logrus.Debugf("trying to talk to v2 search endpoint")
+ resp, err := client.makeRequest(ctx, "GET", "/v2/_catalog", nil, nil, v2Auth, nil)
if err != nil {
logrus.Debugf("error getting search results from v2 endpoint %q: %v", registry, err)
} else {
@@ -409,20 +408,20 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima
// makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// The host name and schema is taken from the client or autodetected, and the path is relative to it, i.e. the path usually starts with /v2/.
-func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader, auth sendAuth) (*http.Response, error) {
+func (c *dockerClient) makeRequest(ctx context.Context, method, path string, headers map[string][]string, stream io.Reader, auth sendAuth, extraScope *authScope) (*http.Response, error) {
if err := c.detectProperties(ctx); err != nil {
return nil, err
}
url := fmt.Sprintf("%s://%s%s", c.scheme, c.registry, path)
- return c.makeRequestToResolvedURL(ctx, method, url, headers, stream, -1, auth)
+ return c.makeRequestToResolvedURL(ctx, method, url, headers, stream, -1, auth, extraScope)
}
// makeRequestToResolvedURL creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client.
// streamLen, if not -1, specifies the length of the data expected on stream.
// makeRequest should generally be preferred.
// TODO(runcom): too many arguments here, use a struct
-func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url string, headers map[string][]string, stream io.Reader, streamLen int64, auth sendAuth) (*http.Response, error) {
+func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url string, headers map[string][]string, stream io.Reader, streamLen int64, auth sendAuth, extraScope *authScope) (*http.Response, error) {
req, err := http.NewRequest(method, url, stream)
if err != nil {
return nil, err
@@ -441,7 +440,7 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url
req.Header.Add("User-Agent", c.sys.DockerRegistryUserAgent)
}
if auth == v2Auth {
- if err := c.setupRequestAuth(req); err != nil {
+ if err := c.setupRequestAuth(req, extraScope); err != nil {
return nil, err
}
}
@@ -460,7 +459,7 @@ func (c *dockerClient) makeRequestToResolvedURL(ctx context.Context, method, url
// 2) gcr.io is sending 401 without a WWW-Authenticate header in the real request
//
// debugging: https://github.com/containers/image/pull/211#issuecomment-273426236 and follows up
-func (c *dockerClient) setupRequestAuth(req *http.Request) error {
+func (c *dockerClient) setupRequestAuth(req *http.Request, extraScope *authScope) error {
if len(c.challenges) == 0 {
return nil
}
@@ -474,10 +473,10 @@ func (c *dockerClient) setupRequestAuth(req *http.Request) error {
case "bearer":
cacheKey := ""
scopes := []authScope{c.scope}
- if c.extraScope != nil {
+ if extraScope != nil {
// Using ':' as a separator here is unambiguous because getBearerToken below uses the same separator when formatting a remote request (and because repository names can't contain colons).
- cacheKey = fmt.Sprintf("%s:%s", c.extraScope.remoteName, c.extraScope.actions)
- scopes = append(scopes, *c.extraScope)
+ cacheKey = fmt.Sprintf("%s:%s", extraScope.remoteName, extraScope.actions)
+ scopes = append(scopes, *extraScope)
}
var token bearerToken
t, inCache := c.tokenCache.Load(cacheKey)
@@ -564,7 +563,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
ping := func(scheme string) error {
url := fmt.Sprintf(resolvedPingV2URL, scheme, c.registry)
- resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
+ resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
if err != nil {
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
return err
@@ -591,7 +590,7 @@ func (c *dockerClient) detectPropertiesHelper(ctx context.Context) error {
// best effort to understand if we're talking to a V1 registry
pingV1 := func(scheme string) bool {
url := fmt.Sprintf(resolvedPingV1URL, scheme, c.registry)
- resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
+ resp, err := c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
if err != nil {
logrus.Debugf("Ping %s err %s (%#v)", url, err.Error(), err)
return false
@@ -625,7 +624,7 @@ func (c *dockerClient) detectProperties(ctx context.Context) error {
// using the original data structures.
func (c *dockerClient) getExtensionsSignatures(ctx context.Context, ref dockerReference, manifestDigest digest.Digest) (*extensionSignatureList, error) {
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(ref.ref), manifestDigest)
- res, err := c.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
+ res, err := c.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containers/image/docker/docker_image.go b/vendor/github.com/containers/image/docker/docker_image.go
index 2ab95f329..530c7513e 100644
--- a/vendor/github.com/containers/image/docker/docker_image.go
+++ b/vendor/github.com/containers/image/docker/docker_image.go
@@ -66,7 +66,7 @@ func GetRepositoryTags(ctx context.Context, sys *types.SystemContext, ref types.
tags := make([]string, 0)
for {
- res, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
+ res, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
if err != nil {
return nil, err
}
diff --git a/vendor/github.com/containers/image/docker/docker_image_dest.go b/vendor/github.com/containers/image/docker/docker_image_dest.go
index 973d160d0..e9882c024 100644
--- a/vendor/github.com/containers/image/docker/docker_image_dest.go
+++ b/vendor/github.com/containers/image/docker/docker_image_dest.go
@@ -113,7 +113,7 @@ func (c *sizeCounter) Write(p []byte) (n int, err error) {
// HasThreadSafePutBlob indicates whether PutBlob can be executed concurrently.
func (d *dockerImageDestination) HasThreadSafePutBlob() bool {
- return false
+ return true
}
// PutBlob writes contents of stream and returns data representing the result (with all data filled in).
@@ -140,7 +140,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// FIXME? Chunked upload, progress reporting, etc.
uploadPath := fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref))
logrus.Debugf("Uploading %s", uploadPath)
- res, err := d.c.makeRequest(ctx, "POST", uploadPath, nil, nil, v2Auth)
+ res, err := d.c.makeRequest(ctx, "POST", uploadPath, nil, nil, v2Auth, nil)
if err != nil {
return types.BlobInfo{}, err
}
@@ -157,7 +157,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
digester := digest.Canonical.Digester()
sizeCounter := &sizeCounter{}
tee := io.TeeReader(stream, io.MultiWriter(digester.Hash(), sizeCounter))
- res, err = d.c.makeRequestToResolvedURL(ctx, "PATCH", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, tee, inputInfo.Size, v2Auth)
+ res, err = d.c.makeRequestToResolvedURL(ctx, "PATCH", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, tee, inputInfo.Size, v2Auth, nil)
if err != nil {
logrus.Debugf("Error uploading layer chunked, response %#v", res)
return types.BlobInfo{}, err
@@ -176,7 +176,7 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// TODO: check inputInfo.Digest == computedDigest https://github.com/containers/image/pull/70#discussion_r77646717
locationQuery.Set("digest", computedDigest.String())
uploadLocation.RawQuery = locationQuery.Encode()
- res, err = d.c.makeRequestToResolvedURL(ctx, "PUT", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, nil, -1, v2Auth)
+ res, err = d.c.makeRequestToResolvedURL(ctx, "PUT", uploadLocation.String(), map[string][]string{"Content-Type": {"application/octet-stream"}}, nil, -1, v2Auth, nil)
if err != nil {
return types.BlobInfo{}, err
}
@@ -194,10 +194,10 @@ func (d *dockerImageDestination) PutBlob(ctx context.Context, stream io.Reader,
// blobExists returns true iff repo contains a blob with digest, and if so, also its size.
// If the destination does not contain the blob, or it is unknown, blobExists ordinarily returns (false, -1, nil);
// it returns a non-nil error only on an unexpected failure.
-func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest) (bool, int64, error) {
+func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.Named, digest digest.Digest, extraScope *authScope) (bool, int64, error) {
checkPath := fmt.Sprintf(blobsPath, reference.Path(repo), digest.String())
logrus.Debugf("Checking %s", checkPath)
- res, err := d.c.makeRequest(ctx, "HEAD", checkPath, nil, nil, v2Auth)
+ res, err := d.c.makeRequest(ctx, "HEAD", checkPath, nil, nil, v2Auth, extraScope)
if err != nil {
return false, -1, err
}
@@ -218,7 +218,7 @@ func (d *dockerImageDestination) blobExists(ctx context.Context, repo reference.
}
// mountBlob tries to mount blob srcDigest from srcRepo to the current destination.
-func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo reference.Named, srcDigest digest.Digest) error {
+func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo reference.Named, srcDigest digest.Digest, extraScope *authScope) error {
u := url.URL{
Path: fmt.Sprintf(blobUploadPath, reference.Path(d.ref.ref)),
RawQuery: url.Values{
@@ -228,7 +228,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
}
mountPath := u.String()
logrus.Debugf("Trying to mount %s", mountPath)
- res, err := d.c.makeRequest(ctx, "POST", mountPath, nil, nil, v2Auth)
+ res, err := d.c.makeRequest(ctx, "POST", mountPath, nil, nil, v2Auth, extraScope)
if err != nil {
return err
}
@@ -246,7 +246,7 @@ func (d *dockerImageDestination) mountBlob(ctx context.Context, srcRepo referenc
return errors.Wrap(err, "Error determining upload URL after a mount attempt")
}
logrus.Debugf("... started an upload instead of mounting, trying to cancel at %s", uploadLocation.String())
- res2, err := d.c.makeRequestToResolvedURL(ctx, "DELETE", uploadLocation.String(), nil, nil, -1, v2Auth)
+ res2, err := d.c.makeRequestToResolvedURL(ctx, "DELETE", uploadLocation.String(), nil, nil, -1, v2Auth, extraScope)
if err != nil {
logrus.Debugf("Error trying to cancel an inadvertent upload: %s", err)
} else {
@@ -276,7 +276,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
}
// First, check whether the blob happens to already exist at the destination.
- exists, size, err := d.blobExists(ctx, d.ref.ref, info.Digest)
+ exists, size, err := d.blobExists(ctx, d.ref.ref, info.Digest, nil)
if err != nil {
return false, types.BlobInfo{}, err
}
@@ -286,15 +286,6 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
}
// Then try reusing blobs from other locations.
-
- // Checking candidateRepo, and mounting from it, requires an expanded token scope.
- // We still want to reuse the ping information and other aspects of the client, so rather than make a fresh copy, there is this a bit ugly extraScope hack.
- if d.c.extraScope != nil {
- return false, types.BlobInfo{}, errors.New("Internal error: dockerClient.extraScope was set before TryReusingBlob")
- }
- defer func() {
- d.c.extraScope = nil
- }()
for _, candidate := range cache.CandidateLocations(d.ref.Transport(), bicTransportScope(d.ref), info.Digest, canSubstitute) {
candidateRepo, err := parseBICLocationReference(candidate.Location)
if err != nil {
@@ -314,7 +305,10 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
}
// Whatever happens here, don't abort the entire operation. It's likely we just don't have permissions, and if it is a critical network error, we will find out soon enough anyway.
- d.c.extraScope = &authScope{
+
+ // Checking candidateRepo, and mounting from it, requires an
+ // expanded token scope.
+ extraScope := &authScope{
remoteName: reference.Path(candidateRepo),
actions: "pull",
}
@@ -325,7 +319,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
// Even worse, docker/distribution does not actually reasonably implement canceling uploads
// (it would require a "delete" action in the token, and Quay does not give that to anyone, so we can't ask);
// so, be a nice client and don't create unnecesary upload sessions on the server.
- exists, size, err := d.blobExists(ctx, candidateRepo, candidate.Digest)
+ exists, size, err := d.blobExists(ctx, candidateRepo, candidate.Digest, extraScope)
if err != nil {
logrus.Debugf("... Failed: %v", err)
continue
@@ -335,7 +329,7 @@ func (d *dockerImageDestination) TryReusingBlob(ctx context.Context, info types.
continue // logrus.Debug() already happened in blobExists
}
if candidateRepo.Name() != d.ref.ref.Name() {
- if err := d.mountBlob(ctx, candidateRepo, candidate.Digest); err != nil {
+ if err := d.mountBlob(ctx, candidateRepo, candidate.Digest, extraScope); err != nil {
logrus.Debugf("... Mount failed: %v", err)
continue
}
@@ -369,7 +363,7 @@ func (d *dockerImageDestination) PutManifest(ctx context.Context, m []byte) erro
if mimeType != "" {
headers["Content-Type"] = []string{mimeType}
}
- res, err := d.c.makeRequest(ctx, "PUT", path, headers, bytes.NewReader(m), v2Auth)
+ res, err := d.c.makeRequest(ctx, "PUT", path, headers, bytes.NewReader(m), v2Auth, nil)
if err != nil {
return err
}
@@ -574,7 +568,7 @@ sigExists:
}
path := fmt.Sprintf(extensionsSignaturePath, reference.Path(d.ref.ref), d.manifestDigest.String())
- res, err := d.c.makeRequest(ctx, "PUT", path, nil, bytes.NewReader(body), v2Auth)
+ res, err := d.c.makeRequest(ctx, "PUT", path, nil, bytes.NewReader(body), v2Auth, nil)
if err != nil {
return err
}
diff --git a/vendor/github.com/containers/image/docker/docker_image_src.go b/vendor/github.com/containers/image/docker/docker_image_src.go
index c88ff2f34..063511535 100644
--- a/vendor/github.com/containers/image/docker/docker_image_src.go
+++ b/vendor/github.com/containers/image/docker/docker_image_src.go
@@ -89,7 +89,7 @@ func (s *dockerImageSource) fetchManifest(ctx context.Context, tagOrDigest strin
path := fmt.Sprintf(manifestPath, reference.Path(s.ref.ref), tagOrDigest)
headers := make(map[string][]string)
headers["Accept"] = manifest.DefaultRequestedManifestMIMETypes
- res, err := s.c.makeRequest(ctx, "GET", path, headers, nil, v2Auth)
+ res, err := s.c.makeRequest(ctx, "GET", path, headers, nil, v2Auth, nil)
if err != nil {
return nil, "", err
}
@@ -137,7 +137,7 @@ func (s *dockerImageSource) getExternalBlob(ctx context.Context, urls []string)
err error
)
for _, url := range urls {
- resp, err = s.c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth)
+ resp, err = s.c.makeRequestToResolvedURL(ctx, "GET", url, nil, nil, -1, noAuth, nil)
if err == nil {
if resp.StatusCode != http.StatusOK {
err = errors.Errorf("error fetching external blob from %q: %d (%s)", url, resp.StatusCode, http.StatusText(resp.StatusCode))
@@ -176,7 +176,7 @@ func (s *dockerImageSource) GetBlob(ctx context.Context, info types.BlobInfo, ca
path := fmt.Sprintf(blobsPath, reference.Path(s.ref.ref), info.Digest.String())
logrus.Debugf("Downloading %s", path)
- res, err := s.c.makeRequest(ctx, "GET", path, nil, nil, v2Auth)
+ res, err := s.c.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil)
if err != nil {
return nil, 0, err
}
@@ -340,7 +340,7 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
return err
}
getPath := fmt.Sprintf(manifestPath, reference.Path(ref.ref), refTail)
- get, err := c.makeRequest(ctx, "GET", getPath, headers, nil, v2Auth)
+ get, err := c.makeRequest(ctx, "GET", getPath, headers, nil, v2Auth, nil)
if err != nil {
return err
}
@@ -362,7 +362,7 @@ func deleteImage(ctx context.Context, sys *types.SystemContext, ref dockerRefere
// When retrieving the digest from a registry >= 2.3 use the following header:
// "Accept": "application/vnd.docker.distribution.manifest.v2+json"
- delete, err := c.makeRequest(ctx, "DELETE", deletePath, headers, nil, v2Auth)
+ delete, err := c.makeRequest(ctx, "DELETE", deletePath, headers, nil, v2Auth, nil)
if err != nil {
return err
}
diff --git a/vendor/github.com/containers/image/version/version.go b/vendor/github.com/containers/image/version/version.go
index 6644bcff3..10075992d 100644
--- a/vendor/github.com/containers/image/version/version.go
+++ b/vendor/github.com/containers/image/version/version.go
@@ -8,7 +8,7 @@ const (
// VersionMinor is for functionality in a backwards-compatible manner
VersionMinor = 1
// VersionPatch is for backwards-compatible bug fixes
- VersionPatch = 0
+ VersionPatch = 5
// VersionDev indicates development branch. Releases will be empty string.
VersionDev = "-dev"
diff --git a/vendor/github.com/urfave/cli/help.go b/vendor/github.com/urfave/cli/help.go
index 65874fa2f..a0e949f72 100644
--- a/vendor/github.com/urfave/cli/help.go
+++ b/vendor/github.com/urfave/cli/help.go
@@ -82,7 +82,7 @@ OPTIONS:
var helpCommand = Command{
Name: "help",
Aliases: []string{"h"},
- Usage: "Shows a list of commands or help for one command",
+ Usage: "Show a list of commands or help for one command",
ArgsUsage: "[command]",
Action: func(c *Context) error {
args := c.Args()