summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml39
-rw-r--r--.papr.sh2
-rwxr-xr-xAPI.md36
-rw-r--r--Makefile9
-rw-r--r--README.md2
-rw-r--r--RELEASE_NOTES.md38
-rw-r--r--changelog.txt97
-rw-r--r--cmd/podman/exists.go10
-rw-r--r--cmd/podman/formats/formats.go13
-rw-r--r--cmd/podman/history.go8
-rw-r--r--cmd/podman/images.go14
-rw-r--r--cmd/podman/info.go10
-rw-r--r--cmd/podman/inspect.go45
-rw-r--r--cmd/podman/mount.go34
-rw-r--r--cmd/podman/pull.go8
-rw-r--r--cmd/podman/rmi.go15
-rw-r--r--cmd/podman/shared/container.go16
-rw-r--r--cmd/podman/tag.go6
-rw-r--r--cmd/podman/umount.go65
-rw-r--r--cmd/podman/varlink/io.podman.varlink18
-rw-r--r--completions/bash/podman6
-rwxr-xr-xcontrib/cirrus/integration_test.sh2
-rw-r--r--contrib/spec/podman.spec.in2
-rw-r--r--docs/podman-mount.1.md10
-rw-r--r--docs/podman-rm.1.md8
-rw-r--r--docs/podman-umount.1.md6
-rw-r--r--docs/podman.1.md2
-rwxr-xr-xhack/get_ci_vm.sh230
-rw-r--r--install.md60
-rw-r--r--libpod.conf23
-rw-r--r--libpod/adapter/client.go22
-rw-r--r--libpod/adapter/containers_remote.go50
-rw-r--r--libpod/adapter/images_remote.go19
-rw-r--r--libpod/adapter/runtime.go50
-rw-r--r--libpod/adapter/runtime_remote.go167
-rw-r--r--libpod/boltdb_state.go12
-rw-r--r--libpod/boltdb_state_linux.go2
-rw-r--r--libpod/boltdb_state_unsupported.go2
-rw-r--r--libpod/common_test.go8
-rw-r--r--libpod/container.go31
-rw-r--r--libpod/container_internal.go4
-rw-r--r--libpod/container_internal_test.go2
-rw-r--r--libpod/info.go6
-rw-r--r--libpod/oci.go6
-rw-r--r--libpod/options.go6
-rw-r--r--libpod/runtime.go77
-rw-r--r--libpod/runtime_ctr.go4
-rw-r--r--pkg/rootless/rootless_linux.c9
-rw-r--r--pkg/spec/spec.go4
-rw-r--r--pkg/varlinkapi/containers.go86
-rw-r--r--test/e2e/attach_test.go2
-rw-r--r--test/e2e/checkpoint_test.go2
-rw-r--r--test/e2e/commit_test.go2
-rw-r--r--test/e2e/common_test.go240
-rw-r--r--test/e2e/create_staticip_test.go2
-rw-r--r--test/e2e/create_test.go2
-rw-r--r--test/e2e/diff_test.go2
-rw-r--r--test/e2e/exec_test.go2
-rw-r--r--test/e2e/exists_test.go9
-rw-r--r--test/e2e/export_test.go2
-rw-r--r--test/e2e/generate_kube_test.go2
-rw-r--r--test/e2e/images_test.go15
-rw-r--r--test/e2e/import_test.go2
-rw-r--r--test/e2e/info_test.go2
-rw-r--r--test/e2e/inspect_test.go4
-rw-r--r--test/e2e/kill_test.go2
-rw-r--r--test/e2e/libpod_suite_remoteclient_test.go157
-rw-r--r--test/e2e/libpod_suite_test.go220
-rw-r--r--test/e2e/load_test.go2
-rw-r--r--test/e2e/logs_test.go2
-rw-r--r--test/e2e/mount_test.go2
-rw-r--r--test/e2e/namespace_test.go2
-rw-r--r--test/e2e/pause_test.go2
-rw-r--r--test/e2e/pod_create_test.go2
-rw-r--r--test/e2e/pod_infra_container_test.go2
-rw-r--r--test/e2e/pod_inspect_test.go2
-rw-r--r--test/e2e/pod_kill_test.go2
-rw-r--r--test/e2e/pod_pause_test.go2
-rw-r--r--test/e2e/pod_pod_namespaces.go2
-rw-r--r--test/e2e/pod_ps_test.go2
-rw-r--r--test/e2e/pod_restart_test.go2
-rw-r--r--test/e2e/pod_rm_test.go2
-rw-r--r--test/e2e/pod_start_test.go2
-rw-r--r--test/e2e/pod_stats_test.go2
-rw-r--r--test/e2e/pod_stop_test.go2
-rw-r--r--test/e2e/pod_top_test.go2
-rw-r--r--test/e2e/port_test.go2
-rw-r--r--test/e2e/prune_test.go2
-rw-r--r--test/e2e/ps_test.go2
-rw-r--r--test/e2e/pull_test.go2
-rw-r--r--test/e2e/push_test.go2
-rw-r--r--test/e2e/refresh_test.go2
-rw-r--r--test/e2e/restart_test.go2
-rw-r--r--test/e2e/rm_test.go2
-rw-r--r--test/e2e/rmi_test.go4
-rw-r--r--test/e2e/rootless_test.go6
-rw-r--r--test/e2e/run_cgroup_parent_test.go2
-rw-r--r--test/e2e/run_cleanup_test.go2
-rw-r--r--test/e2e/run_cpu_test.go2
-rw-r--r--test/e2e/run_device_test.go2
-rw-r--r--test/e2e/run_dns_test.go2
-rw-r--r--test/e2e/run_entrypoint_test.go2
-rw-r--r--test/e2e/run_exit_test.go2
-rw-r--r--test/e2e/run_memory_test.go2
-rw-r--r--test/e2e/run_networking_test.go2
-rw-r--r--test/e2e/run_ns_test.go2
-rw-r--r--test/e2e/run_passwd_test.go2
-rw-r--r--test/e2e/run_privileged_test.go2
-rw-r--r--test/e2e/run_restart_test.go2
-rw-r--r--test/e2e/run_selinux_test.go2
-rw-r--r--test/e2e/run_signal_test.go2
-rw-r--r--test/e2e/run_staticip_test.go2
-rw-r--r--test/e2e/run_test.go2
-rw-r--r--test/e2e/run_userns_test.go2
-rw-r--r--test/e2e/runlabel_test.go2
-rw-r--r--test/e2e/save_test.go2
-rw-r--r--test/e2e/search_test.go2
-rw-r--r--test/e2e/start_test.go2
-rw-r--r--test/e2e/stats_test.go2
-rw-r--r--test/e2e/stop_test.go2
-rw-r--r--test/e2e/systemd_test.go2
-rw-r--r--test/e2e/tag_test.go2
-rw-r--r--test/e2e/top_test.go2
-rw-r--r--test/e2e/trust_test.go2
-rw-r--r--test/e2e/version_test.go2
-rw-r--r--test/e2e/volume_create_test.go2
-rw-r--r--test/e2e/volume_inspect_test.go2
-rw-r--r--test/e2e/volume_ls_test.go2
-rw-r--r--test/e2e/volume_prune_test.go2
-rw-r--r--test/e2e/volume_rm_test.go2
-rw-r--r--test/e2e/wait_test.go2
-rw-r--r--test/utils/utils.go24
-rw-r--r--vendor.conf4
-rw-r--r--vendor/github.com/containers/storage/containers_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/aufs/aufs.go5
-rw-r--r--vendor/github.com/containers/storage/drivers/btrfs/btrfs.go5
-rw-r--r--vendor/github.com/containers/storage/drivers/devmapper/driver.go5
-rw-r--r--vendor/github.com/containers/storage/drivers/driver.go3
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/check.go66
-rw-r--r--vendor/github.com/containers/storage/drivers/overlay/overlay.go46
-rw-r--r--vendor/github.com/containers/storage/drivers/template.go45
-rw-r--r--vendor/github.com/containers/storage/drivers/vfs/driver.go8
-rw-r--r--vendor/github.com/containers/storage/drivers/windows/windows.go5
-rw-r--r--vendor/github.com/containers/storage/drivers/zfs/zfs.go65
-rw-r--r--vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go2
-rw-r--r--vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go21
-rw-r--r--vendor/github.com/containers/storage/drivers/zfs/zfs_solaris.go59
-rw-r--r--vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go2
-rw-r--r--vendor/github.com/containers/storage/images.go4
-rw-r--r--vendor/github.com/containers/storage/images_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/layers.go44
-rw-r--r--vendor/github.com/containers/storage/layers_ffjson.go2
-rw-r--r--vendor/github.com/containers/storage/pkg/archive/example_changes.go97
-rw-r--r--vendor/github.com/containers/storage/store.go60
-rw-r--r--vendor/github.com/varlink/go/.gitignore1
-rw-r--r--vendor/github.com/varlink/go/.travis.yml6
-rw-r--r--vendor/github.com/varlink/go/cmd/varlink/main.go295
-rw-r--r--vendor/github.com/varlink/go/varlink/bridge.go59
-rw-r--r--vendor/github.com/varlink/go/varlink/bridge_windows.go57
-rw-r--r--vendor/github.com/varlink/go/varlink/connection.go7
-rw-r--r--vendor/github.com/varlink/go/varlink/service.go67
-rw-r--r--vendor/github.com/varlink/go/varlink/socketactivation.go63
-rw-r--r--vendor/github.com/varlink/go/varlink/socketactivation_windows.go7
-rw-r--r--version/version.go2
164 files changed, 2605 insertions, 737 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 199c2a533..3192d15ae 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -25,6 +25,16 @@ env:
CIRRUS_CLONE_DEPTH: 200
####
+ #### Cache-image names to test with
+ ###
+ FEDORA_CACHE_IMAGE_NAME: "fedora-29-libpod-9afa57a9"
+ PRIOR_FEDORA_CACHE_IMAGE_NAME: "fedora-28-libpod-9afa57a9"
+ UBUNTU_CACHE_IMAGE_NAME: "ubuntu-18-libpod-9afa57a9"
+ RHEL_CACHE_IMAGE_NAME: "rhel-8-notready"
+ PRIOR_RHEL_CACHE_IMAGE_NAME: "rhel-7-notready"
+ CENTOS_CACHE_IMAGE_NAME: "centos-7-notready"
+
+ ####
#### Variables for composing new cache-images (used in PR testing) from
#### base-images (pre-existing in GCE)
####
@@ -38,6 +48,8 @@ env:
PACKER_BUILDS: "ubuntu-18,fedora-29,fedora-28" # TODO: fah-29,rhel-7,centos-7
# Version of packer to use
PACKER_VER: "1.3.1"
+ # 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
UBUNTU_BASE_IMAGE: "ubuntu-1804-bionic-v20181203a"
CENTOS_BASE_IMAGE: "centos-7-v20181113"
@@ -113,7 +125,7 @@ build_each_commit_task:
memory: "4Gb"
disk: 40
matrix:
- image_name: "fedora-29-libpod-9afa57a9"
+ image_name: "${FEDORA_CACHE_IMAGE_NAME}"
timeout_in: 30m
@@ -139,14 +151,14 @@ testing_task:
# 'matrix' combinations.
matrix:
# Images are generated separately, from build_images_task (below)
- image_name: fedora-29-libpod-9afa57a9
- image_name: fedora-28-libpod-9afa57a9
- image_name: ubuntu-18-libpod-9afa57a9
+ image_name: "${FEDORA_CACHE_IMAGE_NAME}"
+ image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
+ image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
# TODO: tests fail
- # image_name: "rhel-7-something-something"
- # image_name: "centos-7-something-something"
- # image_name: "fah-29-libpod-5070733157859328"
+ # image_name: "${RHEL_CACHE_IMAGE_NAME}
+ # image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}
+ # image_name: "${CENTOS_CACHE_IMAGE_NAME}"
timeout_in: 120m
@@ -176,12 +188,13 @@ optional_testing_task:
gce_instance:
image_project: "libpod-218412"
matrix:
- image_name: fedora-29-libpod-9afa57a9
- image_name: fedora-28-libpod-9afa57a9
- image_name: ubuntu-18-libpod-9afa57a9
+ image_name: "${FEDORA_CACHE_IMAGE_NAME}"
+ image_name: "${PRIOR_FEDORA_CACHE_IMAGE_NAME}"
+ image_name: "${UBUNTU_CACHE_IMAGE_NAME}"
# TODO: Make these work (also build_images_task below)
- #image_name: "rhel-server-ec2-7-5-165-1-libpod-fce09afe"
- #image_name: "centos-7-v20180911-libpod-fce09afe"
+ # image_name: "${RHEL_CACHE_IMAGE_NAME}
+ # image_name: "${PRIOR_RHEL_CACHE_IMAGE_NAME}
+ # image_name: "${CENTOS_CACHE_IMAGE_NAME}"
timeout_in: 60m
@@ -214,7 +227,7 @@ cache_images_task:
cpu: 4
memory: "4Gb"
disk: 200
- image_name: "image-builder-image-1541772081" # Simply CentOS 7 + packer dependencies
+ image_name: "${IMAGE_BUILDER_CACHE_IMAGE_NAME}"
# Additional permissions for building GCE images, within a GCE VM
scopes:
- compute
diff --git a/.papr.sh b/.papr.sh
index a42952824..c5aada904 100644
--- a/.papr.sh
+++ b/.papr.sh
@@ -110,6 +110,7 @@ fi
if [ $build -eq 1 ]; then
make_install_tools
make TAGS="${TAGS}" GOPATH=$GOPATH
+ make podman-remote TAGS="${TAGS}" GOPATH=$GOPATH
fi
# Install Podman
@@ -126,4 +127,5 @@ if [ $integrationtest -eq 1 ]; then
make TAGS="${TAGS}" test-binaries
make varlink_generate GOPATH=/go
make ginkgo GOPATH=/go $INTEGRATION_TEST_ENVS
+ make ginkgo-remote GOPATH=/go $INTEGRATION_TEST_ENVS
fi
diff --git a/API.md b/API.md
index 0cbdffea4..872d3ee07 100755
--- a/API.md
+++ b/API.md
@@ -9,14 +9,22 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func Commit(name: string, image_name: string, changes: []string, author: string, message: string, pause: bool, manifestType: string) string](#Commit)
+[func ContainerArtifacts(name: string, artifactName: string) string](#ContainerArtifacts)
+
[func ContainerCheckpoint(name: string, keep: bool, leaveRunning: bool, tcpEstablished: bool) string](#ContainerCheckpoint)
+[func ContainerConfig(name: string) string](#ContainerConfig)
+
[func ContainerExists(name: string) int](#ContainerExists)
+[func ContainerInspectData(name: string) string](#ContainerInspectData)
+
[func ContainerRestore(name: string, keep: bool, tcpEstablished: bool) string](#ContainerRestore)
[func ContainerRunlabel(runlabel: Runlabel) ](#ContainerRunlabel)
+[func ContainerStateData(name: string) string](#ContainerStateData)
+
[func CreateContainer(create: Create) string](#CreateContainer)
[func CreateImage() NotImplemented](#CreateImage)
@@ -239,12 +247,24 @@ attributes: _CMD, ENTRYPOINT, ENV, EXPOSE, LABEL, ONBUILD, STOPSIGNAL, USER, VOL
container while it is being committed, pass a _true_ bool for the pause argument. If the container cannot
be found by the ID or name provided, a (ContainerNotFound)[#ContainerNotFound] error will be returned; otherwise,
the resulting image's ID will be returned as a string.
+### <a name="ContainerArtifacts"></a>func ContainerArtifacts
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method ContainerArtifacts(name: [string](https://godoc.org/builtin#string), artifactName: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
+ContainerArtifacts returns a container's artifacts in string form. This call is for
+development of Podman only and generally should not be used.
### <a name="ContainerCheckpoint"></a>func ContainerCheckpoint
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
method ContainerCheckpoint(name: [string](https://godoc.org/builtin#string), keep: [bool](https://godoc.org/builtin#bool), leaveRunning: [bool](https://godoc.org/builtin#bool), tcpEstablished: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div>
ContainerCheckPoint performs a checkpopint on a container by its name or full/partial container
ID. On successful checkpoint, the id of the checkpointed container is returned.
+### <a name="ContainerConfig"></a>func ContainerConfig
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method ContainerConfig(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
+ContainerConfig returns a container's config in string form. This call is for
+development of Podman only and generally should not be used.
### <a name="ContainerExists"></a>func ContainerExists
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -258,6 +278,12 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.ContainerExists '{"name":
"exists": 0
}
~~~
+### <a name="ContainerInspectData"></a>func ContainerInspectData
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method ContainerInspectData(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
+ContainerInspectData returns a container's inspect data in string form. This call is for
+development of Podman only and generally should not be used.
### <a name="ContainerRestore"></a>func ContainerRestore
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -270,6 +296,12 @@ of the container's ID.
method ContainerRunlabel(runlabel: [Runlabel](#Runlabel)) </div>
ContainerRunlabel runs executes a command as described by a given container image label.
+### <a name="ContainerStateData"></a>func ContainerStateData
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method ContainerStateData(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
+ContainerStateData returns a container's state config in string form. This call is for
+development of Podman only and generally should not be used.
### <a name="CreateContainer"></a>func CreateContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -1373,6 +1405,8 @@ virtualSize [int](https://godoc.org/builtin#int)
containers [int](https://godoc.org/builtin#int)
labels [map[string]](#map[string])
+
+isParent [bool](https://godoc.org/builtin#bool)
### <a name="ImageSearch"></a>type ImageSearch
ImageSearch is the returned structure for SearchImage. It is returned
@@ -1460,7 +1494,7 @@ graph_status [InfoGraphStatus](#InfoGraphStatus)
run_root [string](https://godoc.org/builtin#string)
### <a name="ListContainerData"></a>type ListContainerData
-ListContainer is the returned struct for an individual container
+ListContainerData is the returned struct for an individual container
id [string](https://godoc.org/builtin#string)
diff --git a/Makefile b/Makefile
index 838de9774..f0f6a1fab 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
GO ?= go
DESTDIR ?= /
-EPOCH_TEST_COMMIT ?= bd40dcfc2bc7c9014ea1f33482fb63aacbcdfe87
+EPOCH_TEST_COMMIT ?= 4406e1cfeed18fe89c0ad4e20a3c3b2f4b9ffcae
HEAD ?= HEAD
CHANGELOG_BASE ?= HEAD~
CHANGELOG_TARGET ?= HEAD
@@ -171,7 +171,10 @@ localunit: test/goecho/goecho varlink_generate
ginkgo:
ginkgo -v -tags "$(BUILDTAGS)" -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/.
-localintegration: varlink_generate test-binaries ginkgo
+ginkgo-remote:
+ ginkgo -v -tags "$(BUILDTAGS) remoteclient" -cover -flakeAttempts 3 -progress -trace -noColor test/e2e/.
+
+localintegration: varlink_generate test-binaries ginkgo ginkgo-remote
localsystem: .install.ginkgo .install.gomega
ginkgo -v -noColor test/system/
@@ -188,7 +191,7 @@ run-perftest: perftest
vagrant-check:
BOX=$(BOX) sh ./vagrant.sh
-binaries: varlink_generate podman
+binaries: varlink_generate podman podman-remote
install.catatonit:
./hack/install_catatonit.sh
diff --git a/README.md b/README.md
index b75f9dcb4..93e780524 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ Libpod provides a library for applications looking to use the Container Pod conc
popularized by Kubernetes. libpod also contains the `podman` tool, for managing
Pods, Containers, and Container Images.
-* [Latest Version: 0.12.1](https://github.com/containers/libpod/releases/latest)
+* [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)
## Overview and scope
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 2d7ca6cbf..b8b475362 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,43 @@
# Release Notes
+## 1.0.0
+### Features
+- The `podman exec` command now includes a `--workdir` option to set working directory for the executed command
+- The `podman create` and `podman run` commands now support the `--init` flag to use a minimal init process in the container
+- Added the `podman image sign` command to GPG sign images
+- The `podman run --device` flag now accepts directories, and will added any device nodes in the directory to the container
+- Added the `podman play kube` command to create pods and containers from Kubernetes pod YAML
+
+### Bugfixes
+- Fixed a bug where passing `podman create` or `podman run` volumes with an empty host or container path could cause a segfault
+- Fixed a bug where `storage.conf` was sometimes ignored for rootless containers
+- Fixed a bug where Podman run as root would error if CAP_SYS_RESOURCE was not available
+- Fixed a bug where Podman would fail to start containers after a system restart due to an out-of-date default Apparmor profile
+- Fixed a bug where Podman's bash completions were not working
+- Fixed a bug where `podman login` would use existing login credentials even if new credentials were provided
+- Fixed a bug where Podman could create some directories with the wrong permissions, breaking containers with user namespaces
+- Fixed a bug where `podman runlabel` was not properly setting container names when the `--name` was specified
+- Fixed a bug where `podman runlabel` sometimes included extra spaces in command output
+- Fixed a bug where `podman commit` was including invalid port numbers in created images when committing containers with published ports
+- Fixed a bug where `podman exec` was not honoring the container's environment variables
+- Fixed a bug where `podman run --device` would fail when a symlink to a device was specified
+- Fixed a bug where `podman build` was not properly picking up OCI runtime paths specified in `libpod.conf`
+- Fixed a bug where Podman would mount `/dev/shm` into the container read-only for read-only containers (`/dev/shm` should always be read-write)
+- Fixed a bug where Podman would ignore any mount whose container mountpoint was `/dev/shm`
+- Fixed a bug where `podman export` did not work with the default `fuse-overlayfs` storage driver
+- Fixed a bug where `podman inspect -f '{{ json .Config }}'` on images would not output anything (it now prints the image's config)
+- Fixed a bug where `podman rmi -fa` displayed the wrong error message when trying to remove images used by pod infra containers
+
+### Misc
+- Rootless containers now unconditionally use postrun cleanup processes, ensuring resources are freed when the container stops
+- A new version of Buildah is included for `podman build`, featuring improved build speed and numerous bugfixes
+- Pulling images has been parallelized, allowing individual layers to be pulled in parallel
+- The `podman start --attach` command now defaults the `sig-proxy` option to `true`, matching `podman create` and `podman run`
+- The `podman info` command now prints the path of the configuration file controlling container storage
+- Added `podman list` and `podman ls` as aliases for `podman ps`, and `podman container ps` and `podman container list` as aliases for `podman container ls`
+- Changed `podman generate kube` to generate Kubernetes service YAML in the same file as pod YAML, generating a single file instead of two
+- To improve compatability with the Docker command line, `podman inspect -f '{{ json .ContainerConfig }}'` on images is no longer valid; please use `podman inspect -f '{{ json .Config }}'` instead
+
## 0.12.1.2
### Bugfixes
- Fixed a bug where an empty path for named volumes could make it impossible to create containers
diff --git a/changelog.txt b/changelog.txt
index b0680a02c..8ee11cdc4 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,100 @@
+- Changelog for v1.0.0 (2018-1-11)
+ * Update release notes for v1.0
+ * Remove clientintegration from Makefile
+ * Regenerate EasyJSON to fix JSON issues
+ * Update gitvalidation to avoid reverts w/o signoffs
+ * Cirrus: Post-Merge Testing for v1.0 Branch
+ * Move python code from contrib to it's own repo python-podman
+ * Use defaults if paths are not specified in storage.conf
+ * (Minor) Cirrus: Print timestamp at start
+ * fix up sigstore path
+ * Trivial readme updates
+ * podman: bump RLIMIT_NOFILE also without CAP_SYS_RESOURCE
+ * Fix handling of nil volumes
+ * sign: make all error messages lowercase
+ * sign: use filepath.Join instead of fmt.Sprintf
+ * createconfig: always cleanup a rootless container
+ * Fix 'image trust' from PR1899
+ * libpod/image: Use ParseNormalizedNamed in RepoDigests
+ * apparmor: apply default profile at container initialization
+ * Fix up image sign and trust
+ * List the long variant of each option before its shorter counterpart
+ * Use existing interface to request IP address during restore
+ * Added checkpoint/restore test for same IP
+ * Enable checkpoint test with established TCP connections
+ * .github/ISSUE_TEMPLATE: Suggest '/kind bug' and '/kind feature'
+ * pkg/hooks/exec: Include failed command in hook errors
+ * hooks/exec/runtimeconfigfilter: Log config changes
+ * hooks: Add pre-create hooks for runtime-config manipulation
+ * Add Validate completions
+ * Add a --workdir option to 'podman exec'
+ * Default --sig-proxy to true for 'podman start --attach'
+ * Test that 'podman start --sig-proxy' does not work without --attach
+ * [WIP]Support podman image sign
+ * vendor latest buildah
+ * Honor image environment variables with exec
+ * Minor: Remove redundant basename command in ooe.sh
+ * Rename libpod.Config back to ContainerConfig
+ * Add ability to build golang remote client
+ * vendor latest buildah
+ * Add the configuration file used to setup storage to podman info
+ * podman: set umask to 022
+ * podman-login: adhere to user input
+ * Vendor in latest containers/buildah code
+ * Readd Python testing
+ * Update vendor of runc
+ * [skip ci] Docs: Add Bot Interactions section
+ * container runlabel NAME implementation
+ * Bump time for build_each_commit step
+ * add container-init support
+ * If local storage file exists, then use it rather then defaults.
+ * vendor in new containers/storage
+ * Fix completions
+ * Touch up some troubleshooting nits
+ * Log container command before starting the container
+ * Use sprintf to generate port numbers while committing
+ * Add troubleshooting for sparse files
+ * Fix handling of symbolic links
+ * podman build is not using the default oci-runtime
+ * Re-enable checkpoint/restore CI tests on Fedora
+ * Fixes to handle /dev/shm correctly.
+ * rootless tests using stop is more reliable
+ * Allow alias for list, ls, ps to work
+ * Refactor: use idtools.ParseIDMap instead of bundling own version
+ * cirrus: Use updated images including new crui
+ * Switch all referencs to image.ContainerConfig to image.Config
+ * Allow users to specify a directory for additonal devices
+ * Change all 'can not' to 'cannot' for proper usage
+ * Invalid index for array
+ * Vendor in latest psgo code to fix race conditions
+ * test: add test for rootless export
+ * export: fix usage with rootless containers
+ * rootless: add function to join user and mount namespace
+ * libpod: always store the conmon pid file
+ * Use existing CRIU packages in CI setup
+ * skip test for blkio.weight when kernel does not support it
+ * Add Play
+ * Cirrus: Skip build all commits test on master
+ * prepare for move to validate on 1.11 only
+ * [skip ci] Gate: Update docs w/ safer local command
+ * Support podman image trust command
+ * Makefile: validate that each commit can at least build
+ * perf test a stress test to profile CPU load of podman
+ * all flakes must die
+ * Add information on --restart
+ * generate service object inline
+ * Cirrus: One IRC notice only
+ * docs/tutorials: add a basic network config
+ * display proper error when rmi -fa with infra containers
+ * add --get-login command to podman-login.
+ * Show image only once with images -q
+ * Add script to create CI VMs for debugging
+ * Cirrus: Migrate PAPR testing of F28 to Cirrus
+ * Skip checkpoint tests on Fedora <30
+ * Cirrus: Add text editors to cache-images
+ * Clean up some existing varlink endpoints
+ * mount: allow mount only when using vfs
+
- Changelog for v0.12.1.2 (2018-12-13)
* Add release notes for 0.12.1.2
* runlabel should sub podman for docker|/usr/bin/docker
diff --git a/cmd/podman/exists.go b/cmd/podman/exists.go
index bd1bc24ec..a7601aaa2 100644
--- a/cmd/podman/exists.go
+++ b/cmd/podman/exists.go
@@ -67,12 +67,12 @@ func imageExistsCmd(c *cli.Context) error {
if len(args) > 1 || len(args) < 1 {
return errors.New("you may only check for the existence of one image at a time")
}
- localRuntime, err := adapter.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer localRuntime.Runtime.Shutdown(false)
- if _, err := localRuntime.NewImageFromLocal(args[0]); err != nil {
+ defer runtime.Shutdown(false)
+ if _, err := runtime.NewImageFromLocal(args[0]); err != nil {
//TODO we need to ask about having varlink defined errors exposed
//so we can reuse them
if errors.Cause(err) == image.ErrNoSuchImage || err.Error() == "io.podman.ImageNotFound" {
@@ -88,13 +88,13 @@ func containerExistsCmd(c *cli.Context) error {
if len(args) > 1 || len(args) < 1 {
return errors.New("you may only check for the existence of one container at a time")
}
- runtime, err := libpodruntime.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
defer runtime.Shutdown(false)
if _, err := runtime.LookupContainer(args[0]); err != nil {
- if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ if errors.Cause(err) == libpod.ErrNoSuchCtr || err.Error() == "io.podman.ContainerNotFound" {
os.Exit(1)
}
return err
diff --git a/cmd/podman/formats/formats.go b/cmd/podman/formats/formats.go
index 3da0ea385..c454c39bd 100644
--- a/cmd/podman/formats/formats.go
+++ b/cmd/podman/formats/formats.go
@@ -20,6 +20,8 @@ const (
JSONString = "json"
// IDString const to save on duplicates for Go templates
IDString = "{{.ID}}"
+
+ parsingErrorStr = "Template parsing error"
)
// Writer interface for outputs
@@ -96,7 +98,7 @@ func (t StdoutTemplateArray) Out() error {
t.Template = strings.Replace(strings.TrimSpace(t.Template[5:]), " ", "\t", -1)
headerTmpl, err := template.New("header").Funcs(headerFunctions).Parse(t.Template)
if err != nil {
- return errors.Wrapf(err, "Template parsing error")
+ return errors.Wrapf(err, parsingErrorStr)
}
err = headerTmpl.Execute(w, t.Fields)
if err != nil {
@@ -107,13 +109,12 @@ func (t StdoutTemplateArray) Out() error {
t.Template = strings.Replace(t.Template, " ", "\t", -1)
tmpl, err := template.New("image").Funcs(basicFunctions).Parse(t.Template)
if err != nil {
- return errors.Wrapf(err, "Template parsing error")
+ return errors.Wrapf(err, parsingErrorStr)
}
- for i, img := range t.Output {
+ for i, raw := range t.Output {
basicTmpl := tmpl.Funcs(basicFunctions)
- err = basicTmpl.Execute(w, img)
- if err != nil {
- return err
+ if err := basicTmpl.Execute(w, raw); err != nil {
+ return errors.Wrapf(err, parsingErrorStr)
}
if i != len(t.Output)-1 {
fmt.Fprintln(w, "")
diff --git a/cmd/podman/history.go b/cmd/podman/history.go
index 7c8c619c8..8a9b6cd94 100644
--- a/cmd/podman/history.go
+++ b/cmd/podman/history.go
@@ -7,9 +7,9 @@ import (
"time"
"github.com/containers/libpod/cmd/podman/formats"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/containers/libpod/libpod/image"
- units "github.com/docker/go-units"
+ "github.com/docker/go-units"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
@@ -72,7 +72,7 @@ func historyCmd(c *cli.Context) error {
return err
}
- runtime, err := libpodruntime.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
@@ -88,7 +88,7 @@ func historyCmd(c *cli.Context) error {
return errors.Errorf("podman history takes at most 1 argument")
}
- image, err := runtime.ImageRuntime().NewFromLocal(args[0])
+ image, err := runtime.NewImageFromLocal(args[0])
if err != nil {
return err
}
diff --git a/cmd/podman/images.go b/cmd/podman/images.go
index 8b8ce78bd..031f06618 100644
--- a/cmd/podman/images.go
+++ b/cmd/podman/images.go
@@ -2,8 +2,6 @@ package main
import (
"context"
- "github.com/containers/libpod/cmd/podman/imagefilters"
- "github.com/containers/libpod/libpod/adapter"
"reflect"
"sort"
"strings"
@@ -11,6 +9,8 @@ import (
"unicode"
"github.com/containers/libpod/cmd/podman/formats"
+ "github.com/containers/libpod/cmd/podman/imagefilters"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/containers/libpod/libpod/image"
"github.com/docker/go-units"
"github.com/opencontainers/go-digest"
@@ -152,13 +152,13 @@ func imagesCmd(c *cli.Context) error {
return err
}
- localRuntime, err := adapter.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "Could not get runtime")
}
- defer localRuntime.Runtime.Shutdown(false)
+ defer runtime.Shutdown(false)
if len(c.Args()) == 1 {
- newImage, err = localRuntime.NewImageFromLocal(c.Args().Get(0))
+ newImage, err = runtime.NewImageFromLocal(c.Args().Get(0))
if err != nil {
return err
}
@@ -171,7 +171,7 @@ func imagesCmd(c *cli.Context) error {
ctx := getContext()
if len(c.StringSlice("filter")) > 0 || newImage != nil {
- filterFuncs, err = CreateFilterFuncs(ctx, localRuntime, c, newImage)
+ filterFuncs, err = CreateFilterFuncs(ctx, runtime, c, newImage)
if err != nil {
return err
}
@@ -195,7 +195,7 @@ func imagesCmd(c *cli.Context) error {
children to the image once built. until buildah supports caching builds,
it will not generate these intermediate images.
*/
- images, err := localRuntime.GetImages()
+ images, err := runtime.GetImages()
if err != nil {
return errors.Wrapf(err, "unable to get images")
}
diff --git a/cmd/podman/info.go b/cmd/podman/info.go
index 4b80f94db..c33ede548 100644
--- a/cmd/podman/info.go
+++ b/cmd/podman/info.go
@@ -1,11 +1,11 @@
package main
import (
- "github.com/containers/libpod/libpod/adapter"
"runtime"
"github.com/containers/libpod/cmd/podman/formats"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/pkg/errors"
"github.com/urfave/cli"
)
@@ -39,20 +39,20 @@ func infoCmd(c *cli.Context) error {
}
info := map[string]interface{}{}
- localRuntime, err := adapter.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
- defer localRuntime.Runtime.Shutdown(false)
+ defer runtime.Shutdown(false)
- infoArr, err := localRuntime.Runtime.Info()
+ infoArr, err := runtime.Info()
if err != nil {
return errors.Wrapf(err, "error getting info")
}
// TODO This is no a problem child because we don't know if we should add information
// TODO about the client or the backend. Only do for traditional podman for now.
- if !localRuntime.Remote && c.Bool("debug") {
+ if !runtime.Remote && c.Bool("debug") {
debugInfo := debugInfo(c)
infoArr = append(infoArr, libpod.InfoData{Type: "debug", Data: debugInfo})
}
diff --git a/cmd/podman/inspect.go b/cmd/podman/inspect.go
index 6ffcde55f..3ef740463 100644
--- a/cmd/podman/inspect.go
+++ b/cmd/podman/inspect.go
@@ -2,12 +2,13 @@ package main
import (
"context"
+ "encoding/json"
"strings"
"github.com/containers/libpod/cmd/podman/formats"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/cmd/podman/shared"
- "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/adapter"
+ cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
"github.com/urfave/cli"
@@ -63,7 +64,7 @@ func inspectCmd(c *cli.Context) error {
return err
}
- runtime, err := libpodruntime.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "error creating libpod runtime")
}
@@ -87,6 +88,9 @@ func inspectCmd(c *cli.Context) error {
}
inspectedObjects, iterateErr := iterateInput(getContext(), c, args, runtime, inspectType)
+ if iterateErr != nil {
+ return iterateErr
+ }
var out formats.Writer
if outputFormat != "" && outputFormat != formats.JSONString {
@@ -97,12 +101,11 @@ func inspectCmd(c *cli.Context) error {
out = formats.JSONStructArray{Output: inspectedObjects}
}
- formats.Writer(out).Out()
- return iterateErr
+ return formats.Writer(out).Out()
}
// func iterateInput iterates the images|containers the user has requested and returns the inspect data and error
-func iterateInput(ctx context.Context, c *cli.Context, args []string, runtime *libpod.Runtime, inspectType string) ([]interface{}, error) {
+func iterateInput(ctx context.Context, c *cli.Context, args []string, runtime *adapter.LocalRuntime, inspectType string) ([]interface{}, error) {
var (
data interface{}
inspectedItems []interface{}
@@ -122,13 +125,18 @@ func iterateInput(ctx context.Context, c *cli.Context, args []string, runtime *l
inspectError = errors.Wrapf(err, "error getting libpod container inspect data %s", ctr.ID())
break
}
- data, err = shared.GetCtrInspectInfo(ctr, libpodInspectData)
+ artifact, err := getArtifact(ctr)
+ if inspectError != nil {
+ inspectError = err
+ break
+ }
+ data, err = shared.GetCtrInspectInfo(ctr.Config(), libpodInspectData, artifact)
if err != nil {
inspectError = errors.Wrapf(err, "error parsing container data %q", ctr.ID())
break
}
case inspectTypeImage:
- image, err := runtime.ImageRuntime().NewFromLocal(input)
+ image, err := runtime.NewImageFromLocal(input)
if err != nil {
inspectError = errors.Wrapf(err, "error getting image %q", input)
break
@@ -141,7 +149,7 @@ func iterateInput(ctx context.Context, c *cli.Context, args []string, runtime *l
case inspectAll:
ctr, err := runtime.LookupContainer(input)
if err != nil {
- image, err := runtime.ImageRuntime().NewFromLocal(input)
+ image, err := runtime.NewImageFromLocal(input)
if err != nil {
inspectError = errors.Wrapf(err, "error getting image %q", input)
break
@@ -157,7 +165,12 @@ func iterateInput(ctx context.Context, c *cli.Context, args []string, runtime *l
inspectError = errors.Wrapf(err, "error getting libpod container inspect data %s", ctr.ID())
break
}
- data, err = shared.GetCtrInspectInfo(ctr, libpodInspectData)
+ artifact, inspectError := getArtifact(ctr)
+ if inspectError != nil {
+ inspectError = err
+ break
+ }
+ data, err = shared.GetCtrInspectInfo(ctr.Config(), libpodInspectData, artifact)
if err != nil {
inspectError = errors.Wrapf(err, "error parsing container data %s", ctr.ID())
break
@@ -170,3 +183,15 @@ func iterateInput(ctx context.Context, c *cli.Context, args []string, runtime *l
}
return inspectedItems, inspectError
}
+
+func getArtifact(ctr *adapter.Container) (*cc.CreateConfig, error) {
+ var createArtifact cc.CreateConfig
+ artifact, err := ctr.GetArtifact("create-config")
+ if err != nil {
+ return nil, err
+ }
+ if err := json.Unmarshal(artifact, &createArtifact); err != nil {
+ return nil, err
+ }
+ return &createArtifact, nil
+}
diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go
index c91115597..86a6b2ad1 100644
--- a/cmd/podman/mount.go
+++ b/cmd/podman/mount.go
@@ -24,13 +24,18 @@ var (
mountFlags = []cli.Flag{
cli.BoolFlag{
- Name: "notruncate",
- Usage: "do not truncate output",
+ Name: "all, a",
+ Usage: "Mount all containers",
},
cli.StringFlag{
Name: "format",
Usage: "Change the output format to Go template",
},
+ cli.BoolFlag{
+ Name: "notruncate",
+ Usage: "do not truncate output",
+ },
+ LatestFlag,
}
mountCommand = cli.Command{
Name: "mount",
@@ -80,20 +85,31 @@ func mountCmd(c *cli.Context) error {
}
}
+ if c.Bool("all") && c.Bool("latest") {
+ return errors.Errorf("--all and --latest cannot be used together")
+ }
+
+ mountContainers, err := getAllOrLatestContainers(c, runtime, -1, "all")
+ if err != nil {
+ if len(mountContainers) == 0 {
+ return err
+ }
+ fmt.Println(err.Error())
+ }
+
formats := map[string]bool{
"": true,
of.JSONString: true,
}
- args := c.Args()
json := c.String("format") == of.JSONString
if !formats[c.String("format")] {
return errors.Errorf("%q is not a supported format", c.String("format"))
}
var lastError error
- if len(args) > 0 {
- for _, name := range args {
+ if len(mountContainers) > 0 {
+ for _, ctr := range mountContainers {
if json {
if lastError != nil {
logrus.Error(lastError)
@@ -101,14 +117,6 @@ func mountCmd(c *cli.Context) error {
lastError = errors.Wrapf(err, "json option cannot be used with a container id")
continue
}
- ctr, err := runtime.LookupContainer(name)
- if err != nil {
- if lastError != nil {
- logrus.Error(lastError)
- }
- lastError = errors.Wrapf(err, "error looking up container %q", name)
- continue
- }
mountPoint, err := ctr.Mount()
if err != nil {
if lastError != nil {
diff --git a/cmd/podman/pull.go b/cmd/podman/pull.go
index 47130805e..2a78d0c54 100644
--- a/cmd/podman/pull.go
+++ b/cmd/podman/pull.go
@@ -9,7 +9,7 @@ import (
dockerarchive "github.com/containers/image/docker/archive"
"github.com/containers/image/transports/alltransports"
"github.com/containers/image/types"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
+ "github.com/containers/libpod/libpod/adapter"
image2 "github.com/containers/libpod/libpod/image"
"github.com/containers/libpod/pkg/util"
"github.com/pkg/errors"
@@ -64,7 +64,7 @@ specified, the image with the 'latest' tag (if it exists) is pulled
// pullCmd gets the data from the command line and calls pullImage
// to copy an image from a registry to a local machine
func pullCmd(c *cli.Context) error {
- runtime, err := libpodruntime.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
@@ -116,14 +116,14 @@ func pullCmd(c *cli.Context) error {
if err != nil {
return errors.Wrapf(err, "error parsing %q", image)
}
- newImage, err := runtime.ImageRuntime().LoadFromArchiveReference(getContext(), srcRef, c.String("signature-policy"), writer)
+ newImage, err := runtime.LoadFromArchiveReference(getContext(), srcRef, c.String("signature-policy"), writer)
if err != nil {
return errors.Wrapf(err, "error pulling image from %q", image)
}
imgID = newImage[0].ID()
} else {
authfile := getAuthFile(c.String("authfile"))
- newImage, err := runtime.ImageRuntime().New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true)
+ newImage, err := runtime.New(getContext(), image, c.String("signature-policy"), authfile, writer, &dockerRegistryOptions, image2.SigningOptions{}, true)
if err != nil {
return errors.Wrapf(err, "error pulling image %q", image)
}
diff --git a/cmd/podman/rmi.go b/cmd/podman/rmi.go
index 5e8ac81a2..fbf860eb2 100644
--- a/cmd/podman/rmi.go
+++ b/cmd/podman/rmi.go
@@ -4,8 +4,7 @@ import (
"fmt"
"os"
- "github.com/containers/libpod/cmd/podman/libpodruntime"
- "github.com/containers/libpod/libpod/image"
+ "github.com/containers/libpod/libpod/adapter"
"github.com/containers/storage"
"github.com/pkg/errors"
"github.com/urfave/cli"
@@ -58,7 +57,7 @@ func rmiCmd(c *cli.Context) error {
return err
}
removeAll := c.Bool("all")
- runtime, err := libpodruntime.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not get runtime")
}
@@ -74,7 +73,7 @@ func rmiCmd(c *cli.Context) error {
images := args[:]
- removeImage := func(img *image.Image) {
+ removeImage := func(img *adapter.ContainerImage) {
deleted = true
msg, deleteErr = runtime.RemoveImage(ctx, img, c.Bool("force"))
if deleteErr != nil {
@@ -91,8 +90,8 @@ func rmiCmd(c *cli.Context) error {
}
if removeAll {
- var imagesToDelete []*image.Image
- imagesToDelete, err = runtime.ImageRuntime().GetImages()
+ var imagesToDelete []*adapter.ContainerImage
+ imagesToDelete, err = runtime.GetImages()
if err != nil {
return errors.Wrapf(err, "unable to query local images")
}
@@ -112,7 +111,7 @@ func rmiCmd(c *cli.Context) error {
removeImage(i)
}
lastNumberofImages = len(imagesToDelete)
- imagesToDelete, err = runtime.ImageRuntime().GetImages()
+ imagesToDelete, err = runtime.GetImages()
if err != nil {
return err
}
@@ -130,7 +129,7 @@ func rmiCmd(c *cli.Context) error {
// See https://github.com/containers/libpod/issues/930 as
// an exemplary inconsistency issue.
for _, i := range images {
- newImage, err := runtime.ImageRuntime().NewFromLocal(i)
+ newImage, err := runtime.NewImageFromLocal(i)
if err != nil {
fmt.Fprintln(os.Stderr, err)
continue
diff --git a/cmd/podman/shared/container.go b/cmd/podman/shared/container.go
index a904ef75a..9040c4a5c 100644
--- a/cmd/podman/shared/container.go
+++ b/cmd/podman/shared/container.go
@@ -2,7 +2,6 @@ package shared
import (
"context"
- "encoding/json"
"fmt"
"github.com/google/shlex"
"io"
@@ -446,8 +445,7 @@ func getStrFromSquareBrackets(cmd string) string {
// GetCtrInspectInfo takes container inspect data and collects all its info into a ContainerData
// structure for inspection related methods
-func GetCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerInspectData) (*inspect.ContainerData, error) {
- config := ctr.Config()
+func GetCtrInspectInfo(config *libpod.ContainerConfig, ctrInspectData *inspect.ContainerInspectData, createArtifact *cc.CreateConfig) (*inspect.ContainerData, error) {
spec := config.Spec
cpus, mems, period, quota, realtimePeriod, realtimeRuntime, shares := getCPUInfo(spec)
@@ -456,16 +454,6 @@ func GetCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerI
pidsLimit := getPidsInfo(spec)
cgroup := getCgroup(spec)
- var createArtifact cc.CreateConfig
- artifact, err := ctr.GetArtifact("create-config")
- if err == nil {
- if err := json.Unmarshal(artifact, &createArtifact); err != nil {
- return nil, err
- }
- } else {
- logrus.Errorf("couldn't get some inspect information, error getting artifact %q: %v", ctr.ID(), err)
- }
-
data := &inspect.ContainerData{
ctrInspectData,
&inspect.HostConfig{
@@ -493,7 +481,7 @@ func GetCtrInspectInfo(ctr *libpod.Container, ctrInspectData *inspect.ContainerI
PidsLimit: pidsLimit,
Privileged: config.Privileged,
ReadonlyRootfs: spec.Root.Readonly,
- Runtime: ctr.RuntimeName(),
+ Runtime: config.OCIRuntime,
NetworkMode: string(createArtifact.NetMode),
IpcMode: string(createArtifact.IpcMode),
Cgroup: cgroup,
diff --git a/cmd/podman/tag.go b/cmd/podman/tag.go
index c99e5d173..d19cf69a2 100644
--- a/cmd/podman/tag.go
+++ b/cmd/podman/tag.go
@@ -23,13 +23,13 @@ func tagCmd(c *cli.Context) error {
if len(args) < 2 {
return errors.Errorf("image name and at least one new name must be specified")
}
- localRuntime, err := adapter.GetRuntime(c)
+ runtime, err := adapter.GetRuntime(c)
if err != nil {
return errors.Wrapf(err, "could not create runtime")
}
- defer localRuntime.Runtime.Shutdown(false)
+ defer runtime.Shutdown(false)
- newImage, err := localRuntime.NewImageFromLocal(args[0])
+ newImage, err := runtime.NewImageFromLocal(args[0])
if err != nil {
return err
}
diff --git a/cmd/podman/umount.go b/cmd/podman/umount.go
index 24f0f178b..7c9b5897b 100644
--- a/cmd/podman/umount.go
+++ b/cmd/podman/umount.go
@@ -21,6 +21,7 @@ var (
Name: "force, f",
Usage: "force the complete umount all of the currently mounted containers",
},
+ LatestFlag,
}
description = `
@@ -51,59 +52,37 @@ func umountCmd(c *cli.Context) error {
force := c.Bool("force")
umountAll := c.Bool("all")
- args := c.Args()
- if len(args) == 0 && !umountAll {
- return errors.Errorf("container ID must be specified")
+ if err := checkAllAndLatest(c); err != nil {
+ return err
}
- if len(args) > 0 && umountAll {
- return errors.Errorf("when using the --all switch, you may not pass any container IDs")
+
+ containers, err := getAllOrLatestContainers(c, runtime, -1, "all")
+ if err != nil {
+ if len(containers) == 0 {
+ return err
+ }
+ fmt.Println(err.Error())
}
umountContainerErrStr := "error unmounting container"
var lastError error
- if len(args) > 0 {
- for _, name := range args {
- ctr, err := runtime.LookupContainer(name)
- if err != nil {
- if lastError != nil {
- logrus.Error(lastError)
- }
- lastError = errors.Wrapf(err, "%s %s", umountContainerErrStr, name)
- continue
- }
-
- if err = ctr.Unmount(force); err != nil {
- if lastError != nil {
- logrus.Error(lastError)
- }
- lastError = errors.Wrapf(err, "%s %s", umountContainerErrStr, name)
- continue
- }
- fmt.Printf("%s\n", ctr.ID())
- }
- } else {
- containers, err := runtime.GetContainers()
- if err != nil {
- return errors.Wrapf(err, "error reading Containers")
+ for _, ctr := range containers {
+ ctrState, err := ctr.State()
+ if ctrState == libpod.ContainerStateRunning || err != nil {
+ continue
}
- for _, ctr := range containers {
- ctrState, err := ctr.State()
- if ctrState == libpod.ContainerStateRunning || err != nil {
- continue
- }
- if err = ctr.Unmount(force); err != nil {
- if umountAll && errors.Cause(err) == storage.ErrLayerNotMounted {
- continue
- }
- if lastError != nil {
- logrus.Error(lastError)
- }
- lastError = errors.Wrapf(err, "%s %s", umountContainerErrStr, ctr.ID())
+ if err = ctr.Unmount(force); err != nil {
+ if umountAll && errors.Cause(err) == storage.ErrLayerNotMounted {
continue
}
- fmt.Printf("%s\n", ctr.ID())
+ if lastError != nil {
+ logrus.Error(lastError)
+ }
+ lastError = errors.Wrapf(err, "%s %s", umountContainerErrStr, ctr.ID())
+ continue
}
+ fmt.Printf("%s\n", ctr.ID())
}
return lastError
}
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index a3e8c050e..79300f9bc 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -61,7 +61,7 @@ type ImageSearch (
star_count: int
)
-# ListContainer is the returned struct for an individual container
+# ListContainerData is the returned struct for an individual container
type ListContainerData (
id: string,
image: string,
@@ -1035,6 +1035,22 @@ method GenerateKubeService() -> (notimplemented: NotImplemented)
# like that created by GenerateKube. See also [GenerateKube](GenerateKube).
method ReplayKube() -> (notimplemented: NotImplemented)
+# ContainerConfig returns a container's config in string form. This call is for
+# development of Podman only and generally should not be used.
+method ContainerConfig(name: string) -> (config: string)
+
+# ContainerArtifacts returns a container's artifacts in string form. This call is for
+# development of Podman only and generally should not be used.
+method ContainerArtifacts(name: string, artifactName: string) -> (config: string)
+
+# ContainerInspectData returns a container's inspect data in string form. This call is for
+# development of Podman only and generally should not be used.
+method ContainerInspectData(name: string) -> (config: string)
+
+# ContainerStateData returns a container's state config in string form. This call is for
+# development of Podman only and generally should not be used.
+method ContainerStateData(name: string) -> (config: string)
+
# ImageNotFound means the image could not be found by the provided name or ID in local storage.
error ImageNotFound (name: string)
diff --git a/completions/bash/podman b/completions/bash/podman
index 6333dfdf2..08891563c 100644
--- a/completions/bash/podman
+++ b/completions/bash/podman
@@ -1514,6 +1514,8 @@ _podman_umount() {
-h
--force
-f
+ --latest
+ -l
"
local options_with_args="
"
@@ -1531,8 +1533,12 @@ _podman_umount() {
_podman_mount() {
local boolean_options="
+ --all
+ -a
--help
-h
+ -l
+ --latest
--notruncate
"
diff --git a/contrib/cirrus/integration_test.sh b/contrib/cirrus/integration_test.sh
index a50bd448f..371c2c914 100755
--- a/contrib/cirrus/integration_test.sh
+++ b/contrib/cirrus/integration_test.sh
@@ -24,6 +24,8 @@ case "${OS_RELEASE_ID}-${OS_RELEASE_VER}" in
centos-7) ;&
rhel-7)
make install PREFIX=/usr ETCDIR=/etc
+ make podman-remote
+ install bin/podman-remote /usr/bin
make test-binaries
make localintegration
;;
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 16cf01976..bf75522dc 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -39,7 +39,7 @@
%global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7})
Name: podman
-Version: 0.12.2
+Version: 1.0.1
Release: #COMMITDATE#.git%{shortcommit0}%{?dist}
Summary: Manage Pods, Containers and Container Images
License: ASL 2.0
diff --git a/docs/podman-mount.1.md b/docs/podman-mount.1.md
index ccc2d386d..2cccf5ee0 100644
--- a/docs/podman-mount.1.md
+++ b/docs/podman-mount.1.md
@@ -19,10 +19,20 @@ returned.
## OPTIONS
+**--all, a**
+
+Mount all containers.
+
**--format**
Print the mounted containers in specified format (json)
+**--latest, -l**
+
+Instead of providing the container name or ID, use the last created container.
+If you use methods other than Podman to run containers such as CRI-O, the last
+started container could be from either of those methods.
+
**--notruncate**
Do not truncate IDs in output.
diff --git a/docs/podman-rm.1.md b/docs/podman-rm.1.md
index 56664a8c1..4fcb0b6c5 100644
--- a/docs/podman-rm.1.md
+++ b/docs/podman-rm.1.md
@@ -11,14 +11,14 @@ podman\-rm - Remove one or more containers
## OPTIONS
-**--force, f**
-
-Force the removal of a running and paused containers
-
**--all, a**
Remove all containers. Can be used in conjunction with -f as well.
+**--force, f**
+
+Force the removal of a running and paused containers
+
**--latest, -l**
Instead of providing the container name or ID, use the last created container. If you use methods other than Podman
diff --git a/docs/podman-umount.1.md b/docs/podman-umount.1.md
index 70f30869a..cceb63019 100644
--- a/docs/podman-umount.1.md
+++ b/docs/podman-umount.1.md
@@ -29,6 +29,12 @@ processes have mounted it.
Note: This could cause other processes that are using the file system to fail,
as the mount point could be removed without their knowledge.
+**--latest, -l**
+
+Instead of providing the container name or ID, use the last created container.
+If you use methods other than Podman to run containers such as CRI-O, the last
+started container could be from either of those methods.
+
## EXAMPLE
podman umount containerID
diff --git a/docs/podman.1.md b/docs/podman.1.md
index a73ebb55e..74e700fac 100644
--- a/docs/podman.1.md
+++ b/docs/podman.1.md
@@ -68,7 +68,7 @@ Default state dir is configured in /etc/containers/storage.conf.
**--runtime**=**value**
-Path to the OCI compatible binary used to run containers
+Name of the OCI runtime as specified in libpod.conf or absolute path to the OCI compatible binary used to run containers.
**--storage-driver, -s**=**value**
diff --git a/hack/get_ci_vm.sh b/hack/get_ci_vm.sh
index e9a755dd4..b058b4273 100755
--- a/hack/get_ci_vm.sh
+++ b/hack/get_ci_vm.sh
@@ -2,9 +2,14 @@
set -e
-cd $(dirname $0)/../
-
-VMNAME="${USER}-twidling-$1"
+RED="\e[1;36;41m"
+YEL="\e[1;33;44m"
+NOR="\e[0m"
+USAGE_WARNING="
+${YEL}WARNING: This will not work without local sudo access to run podman,${NOR}
+ ${YEL}and prior authorization to use the libpod GCP project. Also,${NOR}
+ ${YEL}possession of the proper ssh private key is required.${NOR}
+"
# TODO: Many/most of these values should come from .cirrus.yml
ZONE="us-central1-a"
CPUS="2"
@@ -12,74 +17,187 @@ MEMORY="4Gb"
DISK="200"
PROJECT="libpod-218412"
GOSRC="/var/tmp/go/src/github.com/containers/libpod"
+# Command shortcuts save some typing
+PGCLOUD="sudo podman run -it --rm -e AS_ID=$UID -e AS_USER=$USER --security-opt label=disable -v /home/$USER:$HOME -v /tmp:/tmp:ro quay.io/cevich/gcloud_centos:latest --configuration=libpod --project=$PROJECT"
+SCP_CMD="$PGCLOUD compute scp"
+
+LIBPODROOT=$(realpath "$(dirname $0)/../")
+# else: Assume $PWD is the root of the libpod repository
+[[ "$LIBPODROOT" != "/" ]] || LIBPODROOT=$PWD
+
+showrun() {
+ if [[ "$1" == "--background" ]]
+ then
+ shift
+ # Properly escape any nested spaces, so command can be copy-pasted
+ echo '+ '$(printf " %q" "$@")' &' > /dev/stderr
+ "$@" &
+ echo -e "${RED}<backgrounded>${NOR}"
+ else
+ echo '+ '$(printf " %q" "$@") > /dev/stderr
+ "$@"
+ fi
+}
+
+TEMPFILE=$(mktemp -p '' $(basename $0)_XXXXX.tar.bz2)
+cleanup() {
+ set +e
+ wait
+ rm -f "$TEMPFILE"
+}
+trap cleanup EXIT
-PGCLOUD="sudo podman run -it --rm -e AS_ID=$UID -e AS_USER=$USER -v /home/$USER:$HOME:z quay.io/cevich/gcloud_centos:latest"
-CREATE_CMD="$PGCLOUD compute instances create --zone=$ZONE --image=$1 --custom-cpu=$CPUS --custom-memory=$MEMORY --boot-disk-size=$DISK --labels=in-use-by=$USER $VMNAME"
-SSH_CMD="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o CheckHostIP=no -F /dev/null"
-CLEANUP_CMD="$PGCLOUD compute instances delete --zone $ZONE --delete-disks=all $VMNAME"
+delvm() {
+ cleanup
+ echo -e "\n"
+ echo -e "\n${YEL}Offering to Delete $VMNAME ${RED}(Might take a minute or two)${NOR}"
+ showrun $CLEANUP_CMD # prompts for Yes/No
+}
-# COLOR!
-RED="\e[1;36;41m"
-YEL="\e[1;33;44m"
-NOR="\e[0m"
+image_hints() {
+ egrep '[[:space:]]+[[:alnum:]].+_CACHE_IMAGE_NAME:[[:space:]+"[[:print:]]+"' \
+ "$LIBPODROOT/.cirrus.yml" | cut -d: -f 2 | tr -d '"[:blank:]' | \
+ grep -v 'notready' | grep -v 'image-builder' | sort -u
+}
-if [[ -z "$1" ]]
-then
- echo -e "\n${RED}Error: No image-name specified. Some possible values (from .cirrus.yml).${NOR}"
- egrep 'image_name' ".cirrus.yml" | grep -v '#' | cut -d: -f 2 | tr -d [:blank:]
+show_usage() {
+ echo -e "\n${RED}ERROR: $1${NOR}"
+ echo -e "${YEL}Usage: $(basename $0) [-s | -p] <image_name>${NOR}\n"
+ if [[ -r ".cirrus.yml" ]]
+ then
+ echo -e "${YEL}Some possible image_name values (from .cirrus.yml):${NOR}"
+ image_hints
+ echo ""
+ fi
exit 1
-fi
+}
+
+get_env_vars() {
+ python -c '
+import yaml
+env=yaml.load(open(".cirrus.yml"))["env"]
+keys=[k for k in env if "ENCRYPTED" not in str(env[k])]
+for k,v in env.items():
+ v=str(v)
+ if "ENCRYPTED" not in v:
+ print "{0}=\"{1}\"".format(k, v),
+ '
+}
+
+parse_args(){
+ if [[ -z "$1" ]]
+ then
+ show_usage "Must specify at least one command-line parameter."
+ elif [[ "$1" == "-p" ]]
+ then
+ DEPS="PACKAGE_DEPS=true SOURCE_DEPS=false"
+ IMAGE_NAME="$2"
+
+ elif [[ "$1" == "-s" ]]
+ then
+ DEPS="PACKAGE_DEPS=false SOURCE_DEPS=true"
+ IMAGE_NAME="$2"
+ else # no -s or -p
+ DEPS="$(get_env_vars)"
+ IMAGE_NAME="$1"
+ fi
+
+ if [[ -z "$IMAGE_NAME" ]]
+ then
+ show_usage "No image-name specified."
+ fi
+
+ if [[ "$USER" =~ "root" ]]
+ then
+ show_usage "This script must be run as a regular user."
+ fi
+
+ echo -e "$USAGE_WARNING"
+
+ SETUP_CMD="env $DEPS $GOSRC/contrib/cirrus/setup_environment.sh"
+ VMNAME="${VMNAME:-${USER}-${IMAGE_NAME}}"
+ CREATE_CMD="$PGCLOUD compute instances create --zone=$ZONE --image=${IMAGE_NAME} --custom-cpu=$CPUS --custom-memory=$MEMORY --boot-disk-size=$DISK --labels=in-use-by=$USER $VMNAME"
+ SSH_CMD="$PGCLOUD compute ssh root@$VMNAME"
+ CLEANUP_CMD="$PGCLOUD compute instances delete --zone $ZONE --delete-disks=all $VMNAME"
+}
+
+##### main
+
+parse_args $@
-echo -e "\n${YEL}WARNING: This will not work without local sudo access to run podman,${NOR}"
-echo -e " ${YEL}and prior authorization to use the libpod GCP project. Also,${NOR}"
-echo -e " ${YEL}possession of the proper ssh private key is required.${NOR}"
+cd $LIBPODROOT
-if [[ "$USER" =~ "root" ]]
+# Attempt to determine if named 'libpod' gcloud configuration exists
+showrun $PGCLOUD info > $TEMPFILE
+if egrep -q "Account:.*None" "$TEMPFILE"
then
- echo -e "\n${RED}ERROR: This script must be run as a regular user${NOR}"
- exit 2
+ echo -e "\n${YEL}WARNING: Can't find gcloud configuration for libpod, running init.${NOR}"
+ echo -e " ${RED}Please choose "#1: Re-initialize" and "login" if asked.${NOR}"
+ showrun $PGCLOUD init --project=$PROJECT --console-only --skip-diagnostics
+
+ # Verify it worked (account name == someone@example.com)
+ $PGCLOUD info > $TEMPFILE
+ if egrep -q "Account:.*None" "$TEMPFILE"
+ then
+ echo -e "${RED}ERROR: Could not initialize libpod configuration in gcloud.${NOR}"
+ exit 5
+ fi
+
+ # If this is the only config, make it the default to avoid persistent warnings from gcloud
+ [[ -r "$HOME/.config/gcloud/configurations/config_default" ]] || \
+ ln "$HOME/.config/gcloud/configurations/config_libpod" \
+ "$HOME/.config/gcloud/configurations/config_default"
fi
-if [[ ! -r "$HOME/.config/gcloud/active_config" ]]
+# Couldn't make rsync work with gcloud's ssh wrapper :(
+echo -e "\n${YEL}Packing up repository into a tarball $VMNAME.${NOR}"
+showrun --background tar cjf $TEMPFILE --warning=no-file-changed -C $LIBPODROOT .
+
+trap delvm INT # Allow deleting VM if CTRL-C during create
+# This fails if VM already exists: permit this usage to re-init
+echo -e "\n${YEL}Trying to creating a VM named $VMNAME ${RED}(might take a minute/two. Errors ignored).${NOR}"
+showrun $CREATE_CMD || true # allow re-running commands below when "delete: N"
+
+# Any subsequent failure should prompt for VM deletion
+trap delvm EXIT
+
+echo -e "\n${YEL}Waiting up to 30s for ssh port to open${NOR}"
+ATTEMPTS=10
+for (( COUNT=1 ; COUNT <= $ATTEMPTS ; COUNT++ ))
+do
+ if $SSH_CMD --command "true"; then break; else sleep 3s; fi
+done
+if (( COUNT > $ATTEMPTS ))
then
- echo -e "\n${RED}ERROR: Can't find gcloud configuration, attempting to run init.${NOR}"
- $PGCLOUD init --project=$PROJECT
+ echo -e "\n${RED}Failed${NOR}"
+ exit 7
fi
+echo -e "${YEL}Got it${NOR}"
-cleanup() {
- echo -e "\n${YEL}Deleting $VMNAME ${RED}(Might take a minute or two)${NOR}
-+ $CLEANUP_CMD
-"
- $CLEANUP_CMD # prompts for Yes/No
-}
-
-trap cleanup EXIT
+if $SSH_CMD --command "test -r /root/.bash_profile_original"
+then
+ echo -e "\n${YEL}Resetting environment configuration${NOR}"
+ showrun $SSH_CMD --command "cp /root/.bash_profile_original /root/.bash_profile"
+fi
-echo -e "\n${YEL}Trying to creating a VM named $VMNAME (not fatal if already exists).${NOR}"
-echo "+ $CREATE_CMD"
-$CREATE_CMD || true # allow re-running commands below when "delete: N"
+echo -e "\n${YEL}Removing and re-creating $GOSRC on $VMNAME.${NOR}"
+showrun $SSH_CMD --command "rm -rf $GOSRC"
+showrun $SSH_CMD --command "mkdir -p $GOSRC"
-echo -e "\n${YEL}Attempting to retrieve IP address of existing ${VMNAME}${NOR}."
-IP=`$PGCLOUD compute instances list --filter=name=$VMNAME --limit=1 '--format=csv(networkInterfaces.accessConfigs.natIP)' | tr --complement --delete .[:digit:]`
+echo -e "\n${YEL}Transfering tarball to $VMNAME.${NOR}"
+wait
+showrun $SCP_CMD $TEMPFILE root@$VMNAME:$TEMPFILE
-echo -e "\n${YEL}Creating $GOSRC directory.${NOR}"
-SSH_MKDIR="$SSH_CMD root@$IP mkdir -vp $GOSRC"
-echo "+ $SSH_MKDIR"
-$SSH_MKDIR
+echo -e "\n${YEL}Unpacking tarball into $GOSRC on $VMNAME.${NOR}"
+showrun $SSH_CMD --command "tar xjf $TEMPFILE -C $GOSRC"
-echo -e "\n${YEL}Synchronizing local repository to $IP:${GOSRC}${NOR} ."
-export RSYNC_RSH="$SSH_CMD"
-RSYNC_CMD="rsync --quiet --recursive --update --links --safe-links --perms --sparse $PWD/ root@$IP:$GOSRC/"
-echo "+ export RSYNC_RSH=\"$SSH_CMD\""
-echo "+ $RSYNC_CMD"
-$RSYNC_CMD
+echo -e "\n${YEL}Removing tarball on $VMNAME.${NOR}"
+showrun $SSH_CMD --command "rm -f $TEMPFILE"
echo -e "\n${YEL}Executing environment setup${NOR}"
-ENV_CMD="$SSH_CMD root@$IP env CI=true $GOSRC/contrib/cirrus/setup_environment.sh"
-echo "+ $ENV_CMD"
-$SSH_CMD root@$IP $GOSRC/contrib/cirrus/setup_environment.sh
-
-echo -e "\n${YEL}Connecting to $VMNAME ${RED}(option to delete VM upon logout).${NOR}"
-SSH_CMD="$SSH_CMD -t root@$IP"
-echo "+ $SSH_CMD"
-$SSH_CMD "cd $GOSRC ; bash -il"
+[[ "$1" == "-p" ]] && echo -e "${RED}Using package-based dependencies.${NOR}"
+[[ "$1" == "-s" ]] && echo -e "${RED}Using source-based dependencies.${NOR}"
+showrun $SSH_CMD --command "$SETUP_CMD"
+
+echo -e "\n${YEL}Connecting to $VMNAME ${RED}(option to delete VM upon logout).${NOR}\n"
+showrun $SSH_CMD -- -t "cd $GOSRC && exec env $DEPS bash -il"
diff --git a/install.md b/install.md
index efb568b66..c5268c04d 100644
--- a/install.md
+++ b/install.md
@@ -1,5 +1,65 @@
# libpod Installation Instructions
+## Installing packaged versions of Podman
+
+#### [Arch Linux](https://www.archlinux.org)
+
+Podman is available in the AUR through the [libpod package](https://aur.archlinux.org/packages/libpod/)
+
+#### [Fedora](https://www.fedoraproject.org), [CentOS](https://www.centos.org)
+
+```bash
+sudo yum -y install podman
+```
+
+
+#### [Fedora-CoreOS](https://coreos.fedoraproject.org), [Fedora SilverBlue](https://silverblue.fedoraproject.org)
+
+Built-in, no need to install
+
+#### [Gentoo](https://www.gentoo.org)
+
+```bash
+sudo emerge app-emulation/libpod
+```
+
+#### [openSUSE](https://www.opensuse.org)
+
+```bash
+sudo zypper install podman
+```
+
+#### [openSUSE Kubic](https://kubic.opensuse.org)
+
+Built-in, no need to install
+
+#### [RHEL7](https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux)
+
+Subscribe, then enable Extras channel and install podman.
+
+```bash
+sudo subscription-manager repos --enable=rhel-7-server-extras-rpms
+sudo yum -y install podman
+```
+
+#### [RHEL8 Beta](https://www.redhat.com/en/blog/powering-its-future-while-preserving-present-introducing-red-hat-enterprise-linux-8-beta?intcmp=701f2000001Cz6OAAS)
+
+```bash
+sudo yum module enable -y container-tools:1.0
+sudo yum module install -y container-tools:1.0
+```
+
+#### [Ubuntu](https://www.ubuntu.com)
+
+```bash
+sudo apt-get update -qq
+sudo apt-get install -qq -y software-properties-common
+sudo add-apt-repository -y ppa:projectatomic/ppa
+sudo apt-get -qq -y install podman
+```
+
+## Building from scratch
+
### Prerequisites
#### runc installed
diff --git a/libpod.conf b/libpod.conf
index cfdf83775..acd6c8982 100644
--- a/libpod.conf
+++ b/libpod.conf
@@ -4,17 +4,6 @@
# Default transport method for pulling and pushing for images
image_default_transport = "docker://"
-# Paths to look for a valid OCI runtime (runc, runv, etc)
-runtime_path = [
- "/usr/bin/runc",
- "/usr/sbin/runc",
- "/usr/local/bin/runc",
- "/usr/local/sbin/runc",
- "/sbin/runc",
- "/bin/runc",
- "/usr/lib/cri-o-runc/sbin/runc"
-]
-
# Paths to look for the Conmon container manager binary
conmon_path = [
"/usr/libexec/podman/conmon",
@@ -98,3 +87,15 @@ pause_command = "/pause"
# Default libpod support for container labeling
# label=true
+
+# Paths to look for a valid OCI runtime (runc, runv, etc)
+[runtimes]
+runc = [
+ "/usr/bin/runc",
+ "/usr/sbin/runc",
+ "/usr/local/bin/runc",
+ "/usr/local/sbin/runc",
+ "/sbin/runc",
+ "/bin/runc",
+ "/usr/lib/cri-o-runc/sbin/runc"
+]
diff --git a/libpod/adapter/client.go b/libpod/adapter/client.go
index 383c242c9..b3bb9acae 100644
--- a/libpod/adapter/client.go
+++ b/libpod/adapter/client.go
@@ -3,12 +3,32 @@
package adapter
import (
+ "os"
+
+ "github.com/sirupsen/logrus"
"github.com/varlink/go/varlink"
)
+// DefaultAddress is the default address of the varlink socket
+const DefaultAddress = "unix:/run/podman/io.podman"
+
// Connect provides a varlink connection
func (r RemoteRuntime) Connect() (*varlink.Connection, error) {
- connection, err := varlink.NewConnection("unix:/run/podman/io.podman")
+ var err error
+ var connection *varlink.Connection
+ if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); bridge != "" {
+ logrus.Infof("Connecting with varlink bridge")
+ logrus.Debugf("%s", bridge)
+ connection, err = varlink.NewBridge(bridge)
+ } else {
+ address := os.Getenv("PODMAN_VARLINK_ADDRESS")
+ if address == "" {
+ address = DefaultAddress
+ }
+ logrus.Infof("Connecting with varlink address")
+ logrus.Debugf("%s", address)
+ connection, err = varlink.NewConnection(address)
+ }
if err != nil {
return nil, err
}
diff --git a/libpod/adapter/containers_remote.go b/libpod/adapter/containers_remote.go
new file mode 100644
index 000000000..9623304e5
--- /dev/null
+++ b/libpod/adapter/containers_remote.go
@@ -0,0 +1,50 @@
+// +build remoteclient
+
+package adapter
+
+import (
+ "encoding/json"
+
+ iopodman "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/inspect"
+)
+
+// Inspect returns an inspect struct from varlink
+func (c *Container) Inspect(size bool) (*inspect.ContainerInspectData, error) {
+ reply, err := iopodman.ContainerInspectData().Call(c.Runtime.Conn, c.ID())
+ if err != nil {
+ return nil, err
+ }
+ data := inspect.ContainerInspectData{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return &data, err
+}
+
+// ID returns the ID of the container
+func (c *Container) ID() string {
+ return c.config.ID
+}
+
+// GetArtifact returns a container's artifacts
+func (c *Container) GetArtifact(name string) ([]byte, error) {
+ var data []byte
+ reply, err := iopodman.ContainerArtifacts().Call(c.Runtime.Conn, c.ID(), name)
+ if err != nil {
+ return nil, err
+ }
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return data, err
+}
+
+// Config returns a container's Config ... same as ctr.Config()
+func (c *Container) Config() *libpod.ContainerConfig {
+ if c.config != nil {
+ return c.config
+ }
+ return c.Runtime.Config(c.ID())
+}
diff --git a/libpod/adapter/images_remote.go b/libpod/adapter/images_remote.go
index 77b0629a7..e7b38dccc 100644
--- a/libpod/adapter/images_remote.go
+++ b/libpod/adapter/images_remote.go
@@ -3,15 +3,22 @@
package adapter
import (
- "github.com/containers/libpod/libpod"
+ "context"
+ "encoding/json"
+
+ iopodman "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/pkg/inspect"
)
-// Images returns information for the host system and its components
-func (r RemoteRuntime) Images() ([]libpod.InfoData, error) {
- conn, err := r.Connect()
+// Inspect returns returns an ImageData struct from over a varlink connection
+func (i *ContainerImage) Inspect(ctx context.Context) (*inspect.ImageData, error) {
+ reply, err := iopodman.InspectImage().Call(i.Runtime.Conn, i.ID())
if err != nil {
return nil, err
}
- _ = conn
- return nil, nil
+ data := inspect.ImageData{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return &data, nil
}
diff --git a/libpod/adapter/runtime.go b/libpod/adapter/runtime.go
index 13141f886..1f3599082 100644
--- a/libpod/adapter/runtime.go
+++ b/libpod/adapter/runtime.go
@@ -3,6 +3,10 @@
package adapter
import (
+ "context"
+ "io"
+
+ "github.com/containers/image/types"
"github.com/containers/libpod/cmd/podman/libpodruntime"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/libpod/image"
@@ -11,8 +15,8 @@ import (
// LocalRuntime describes a typical libpod runtime
type LocalRuntime struct {
- Runtime *libpod.Runtime
- Remote bool
+ *libpod.Runtime
+ Remote bool
}
// ContainerImage ...
@@ -20,6 +24,11 @@ type ContainerImage struct {
*image.Image
}
+// Container ...
+type Container struct {
+ *libpod.Container
+}
+
// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
func GetRuntime(c *cli.Context) (*LocalRuntime, error) {
runtime, err := libpodruntime.GetRuntime(c)
@@ -53,3 +62,40 @@ func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) {
}
return &ContainerImage{img}, nil
}
+
+// LoadFromArchiveReference calls into local storage to load an image from an archive
+func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) {
+ var containerImages []*ContainerImage
+ imgs, err := r.Runtime.ImageRuntime().LoadFromArchiveReference(ctx, srcRef, signaturePolicyPath, writer)
+ if err != nil {
+ return nil, err
+ }
+ for _, i := range imgs {
+ ci := ContainerImage{i}
+ containerImages = append(containerImages, &ci)
+ }
+ return containerImages, nil
+}
+
+// New calls into local storage to look for an image in local storage or to pull it
+func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool) (*ContainerImage, error) {
+ img, err := r.Runtime.ImageRuntime().New(ctx, name, signaturePolicyPath, authfile, writer, dockeroptions, signingoptions, forcePull)
+ if err != nil {
+ return nil, err
+ }
+ return &ContainerImage{img}, nil
+}
+
+// RemoveImage calls into local storage and removes an image
+func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, force bool) (string, error) {
+ return r.Runtime.RemoveImage(ctx, img.Image, force)
+}
+
+// LookupContainer ...
+func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
+ ctr, err := r.Runtime.LookupContainer(idOrName)
+ if err != nil {
+ return nil, err
+ }
+ return &Container{ctr}, nil
+}
diff --git a/libpod/adapter/runtime_remote.go b/libpod/adapter/runtime_remote.go
index 27301d90b..7189348bc 100644
--- a/libpod/adapter/runtime_remote.go
+++ b/libpod/adapter/runtime_remote.go
@@ -4,12 +4,18 @@ package adapter
import (
"context"
+ "encoding/json"
"fmt"
+ "io"
"strings"
"time"
- iopodman "github.com/containers/libpod/cmd/podman/varlink"
- digest "github.com/opencontainers/go-digest"
+ "github.com/containers/image/types"
+ "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/libpod/image"
+ "github.com/opencontainers/go-digest"
+ "github.com/sirupsen/logrus"
"github.com/urfave/cli"
"github.com/varlink/go/varlink"
)
@@ -19,13 +25,13 @@ type RemoteImageRuntime struct{}
// RemoteRuntime describes a wrapper runtime struct
type RemoteRuntime struct {
+ Conn *varlink.Connection
+ Remote bool
}
// LocalRuntime describes a typical libpod runtime
type LocalRuntime struct {
- Runtime *RemoteRuntime
- Remote bool
- Conn *varlink.Connection
+ *RemoteRuntime
}
// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
@@ -35,11 +41,14 @@ func GetRuntime(c *cli.Context) (*LocalRuntime, error) {
if err != nil {
return nil, err
}
- return &LocalRuntime{
- Runtime: &runtime,
- Remote: true,
- Conn: conn,
- }, nil
+ rr := RemoteRuntime{
+ Conn: conn,
+ Remote: true,
+ }
+ foo := LocalRuntime{
+ &rr,
+ }
+ return &foo, nil
}
// Shutdown is a bogus wrapper for compat with the libpod runtime
@@ -67,6 +76,18 @@ type remoteImage struct {
Runtime *LocalRuntime
}
+// Container ...
+type Container struct {
+ remoteContainer
+}
+
+// remoteContainer ....
+type remoteContainer struct {
+ Runtime *LocalRuntime
+ config *libpod.ContainerConfig
+ state *libpod.ContainerState
+}
+
// GetImages returns a slice of containerimages over a varlink connection
func (r *LocalRuntime) GetImages() ([]*ContainerImage, error) {
var newImages []*ContainerImage
@@ -119,6 +140,42 @@ func (r *LocalRuntime) NewImageFromLocal(name string) (*ContainerImage, error) {
}
+// LoadFromArchiveReference creates an image from a local archive
+func (r *LocalRuntime) LoadFromArchiveReference(ctx context.Context, srcRef types.ImageReference, signaturePolicyPath string, writer io.Writer) ([]*ContainerImage, error) {
+ // TODO We need to find a way to leak certDir, creds, and the tlsverify into this function, normally this would
+ // come from cli options but we don't want want those in here either.
+ imageID, err := iopodman.PullImage().Call(r.Conn, srcRef.DockerReference().String(), "", "", signaturePolicyPath, true)
+ if err != nil {
+ return nil, err
+ }
+ newImage, err := r.NewImageFromLocal(imageID)
+ if err != nil {
+ return nil, err
+ }
+ return []*ContainerImage{newImage}, nil
+}
+
+// New calls into local storage to look for an image in local storage or to pull it
+func (r *LocalRuntime) New(ctx context.Context, name, signaturePolicyPath, authfile string, writer io.Writer, dockeroptions *image.DockerRegistryOptions, signingoptions image.SigningOptions, forcePull bool) (*ContainerImage, error) {
+ // TODO Creds needs to be figured out here too, like above
+ tlsBool := dockeroptions.DockerInsecureSkipTLSVerify
+ // Remember SkipTlsVerify is the opposite of tlsverify
+ // If tlsBook is true or undefined, we do not skip
+ SkipTlsVerify := false
+ if tlsBool == types.OptionalBoolFalse {
+ SkipTlsVerify = true
+ }
+ imageID, err := iopodman.PullImage().Call(r.Conn, name, dockeroptions.DockerCertPath, "", signaturePolicyPath, SkipTlsVerify)
+ if err != nil {
+ return nil, err
+ }
+ newImage, err := r.NewImageFromLocal(imageID)
+ if err != nil {
+ return nil, err
+ }
+ return newImage, nil
+}
+
func splitStringDate(d string) (time.Time, error) {
fields := strings.Fields(d)
t := fmt.Sprintf("%sT%sZ", fields[0], fields[1])
@@ -174,6 +231,92 @@ func (ci *ContainerImage) TagImage(tag string) error {
return err
}
-func (r RemoteRuntime) RemoveImage(force bool) error {
- return nil
+// RemoveImage calls varlink to remove an image
+func (r *LocalRuntime) RemoveImage(ctx context.Context, img *ContainerImage, force bool) (string, error) {
+ return iopodman.RemoveImage().Call(r.Conn, img.InputName, force)
+}
+
+// History returns the history of an image and its layers
+func (ci *ContainerImage) History(ctx context.Context) ([]*image.History, error) {
+ var imageHistories []*image.History
+
+ reply, err := iopodman.HistoryImage().Call(ci.Runtime.Conn, ci.InputName)
+ if err != nil {
+ return nil, err
+ }
+ for _, h := range reply {
+ created, err := splitStringDate(h.Created)
+ if err != nil {
+ return nil, err
+ }
+ ih := image.History{
+ ID: h.Id,
+ Created: &created,
+ CreatedBy: h.CreatedBy,
+ Size: h.Size,
+ Comment: h.Comment,
+ }
+ imageHistories = append(imageHistories, &ih)
+ }
+ return imageHistories, nil
+}
+
+// LookupContainer gets basic information about container over a varlink
+// connection and then translates it to a *Container
+func (r *LocalRuntime) LookupContainer(idOrName string) (*Container, error) {
+ state, err := r.ContainerState(idOrName)
+ if err != nil {
+ return nil, err
+ }
+ config := r.Config(idOrName)
+ if err != nil {
+ return nil, err
+ }
+
+ rc := remoteContainer{
+ r,
+ config,
+ state,
+ }
+
+ c := Container{
+ rc,
+ }
+ return &c, nil
+}
+
+func (r *LocalRuntime) GetLatestContainer() (*Container, error) {
+ return nil, libpod.ErrNotImplemented
+}
+
+// ContainerState returns the "state" of the container.
+func (r *LocalRuntime) ContainerState(name string) (*libpod.ContainerState, error) { //no-lint
+ reply, err := iopodman.ContainerStateData().Call(r.Conn, name)
+ if err != nil {
+ return nil, err
+ }
+ data := libpod.ContainerState{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ return nil, err
+ }
+ return &data, err
+
+}
+
+// Config returns a container config
+func (r *LocalRuntime) Config(name string) *libpod.ContainerConfig {
+ // TODO the Spec being returned is not populated. Matt and I could not figure out why. Will defer
+ // further looking into it for after devconf.
+ // The libpod function for this has no errors so we are kind of in a tough
+ // spot here. Logging the errors for now.
+ reply, err := iopodman.ContainerConfig().Call(r.Conn, name)
+ if err != nil {
+ logrus.Error("call to container.config failed")
+ }
+ data := libpod.ContainerConfig{}
+ if err := json.Unmarshal([]byte(reply), &data); err != nil {
+ logrus.Error("failed to unmarshal container inspect data")
+ }
+ return &data
+
}
diff --git a/libpod/boltdb_state.go b/libpod/boltdb_state.go
index e7a07a9a8..5bc15dd7f 100644
--- a/libpod/boltdb_state.go
+++ b/libpod/boltdb_state.go
@@ -205,7 +205,7 @@ func (s *BoltState) Refresh() error {
return errors.Wrapf(ErrInternal, "container %s missing state in DB", string(id))
}
- state := new(containerState)
+ state := new(ContainerState)
if err := json.Unmarshal(stateBytes, state); err != nil {
return errors.Wrapf(err, "error unmarshalling state for container %s", string(id))
@@ -325,7 +325,7 @@ func (s *BoltState) Container(id string) (*Container, error) {
ctr := new(Container)
ctr.config = new(ContainerConfig)
- ctr.state = new(containerState)
+ ctr.state = new(ContainerState)
db, err := s.getDBCon()
if err != nil {
@@ -361,7 +361,7 @@ func (s *BoltState) LookupContainer(idOrName string) (*Container, error) {
ctr := new(Container)
ctr.config = new(ContainerConfig)
- ctr.state = new(containerState)
+ ctr.state = new(ContainerState)
db, err := s.getDBCon()
if err != nil {
@@ -542,7 +542,7 @@ func (s *BoltState) UpdateContainer(ctr *Container) error {
return errors.Wrapf(ErrNSMismatch, "container %s is in namespace %q, does not match our namespace %q", ctr.ID(), ctr.config.Namespace, s.namespace)
}
- newState := new(containerState)
+ newState := new(ContainerState)
netNSPath := ""
ctrID := []byte(ctr.ID())
@@ -754,7 +754,7 @@ func (s *BoltState) AllContainers() ([]*Container, error) {
ctr := new(Container)
ctr.config = new(ContainerConfig)
- ctr.state = new(containerState)
+ ctr.state = new(ContainerState)
if err := s.getContainerFromDB(id, ctr, ctrBucket); err != nil {
// If the error is a namespace mismatch, we can
@@ -1140,7 +1140,7 @@ func (s *BoltState) PodContainers(pod *Pod) ([]*Container, error) {
err = podCtrs.ForEach(func(id, val []byte) error {
newCtr := new(Container)
newCtr.config = new(ContainerConfig)
- newCtr.state = new(containerState)
+ newCtr.state = new(ContainerState)
ctrs = append(ctrs, newCtr)
return s.getContainerFromDB(id, newCtr, ctrBkt)
diff --git a/libpod/boltdb_state_linux.go b/libpod/boltdb_state_linux.go
index d91f311e5..09a9be606 100644
--- a/libpod/boltdb_state_linux.go
+++ b/libpod/boltdb_state_linux.go
@@ -8,7 +8,7 @@ import (
// replaceNetNS handle network namespace transitions after updating a
// container's state.
-func replaceNetNS(netNSPath string, ctr *Container, newState *containerState) error {
+func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) error {
if netNSPath != "" {
// Check if the container's old state has a good netns
if ctr.state.NetNS != nil && netNSPath == ctr.state.NetNS.Path() {
diff --git a/libpod/boltdb_state_unsupported.go b/libpod/boltdb_state_unsupported.go
index 64610d304..244dc51a0 100644
--- a/libpod/boltdb_state_unsupported.go
+++ b/libpod/boltdb_state_unsupported.go
@@ -3,7 +3,7 @@
package libpod
// replaceNetNS is exclusive to the Linux platform and is a no-op elsewhere
-func replaceNetNS(netNSPath string, ctr *Container, newState *containerState) error {
+func replaceNetNS(netNSPath string, ctr *Container, newState *ContainerState) error {
return nil
}
diff --git a/libpod/common_test.go b/libpod/common_test.go
index 4af68a040..df730098e 100644
--- a/libpod/common_test.go
+++ b/libpod/common_test.go
@@ -48,7 +48,7 @@ func getTestContainer(id, name string, manager lock.Manager) (*Container, error)
},
},
},
- state: &containerState{
+ state: &ContainerState{
State: ContainerStateRunning,
ConfigPath: "/does/not/exist/specs/" + id,
RunDir: "/does/not/exist/tmp/",
@@ -166,10 +166,10 @@ func testContainersEqual(t *testing.T, a, b *Container, allowedEmpty bool) {
aConfig := new(ContainerConfig)
bConfig := new(ContainerConfig)
- aState := new(containerState)
- bState := new(containerState)
+ aState := new(ContainerState)
+ bState := new(ContainerState)
- blankState := new(containerState)
+ blankState := new(ContainerState)
assert.Equal(t, a.valid, b.valid)
diff --git a/libpod/container.go b/libpod/container.go
index ca83bbffe..b0589be3b 100644
--- a/libpod/container.go
+++ b/libpod/container.go
@@ -116,7 +116,7 @@ func (ns LinuxNS) String() string {
type Container struct {
config *ContainerConfig
- state *containerState
+ state *ContainerState
// Batched indicates that a container has been locked as part of a
// Batch() operation
@@ -136,10 +136,10 @@ type Container struct {
requestedIP net.IP
}
-// containerState contains the current state of the container
+// ContainerState contains the current state of the container
// It is stored on disk in a tmpfs and recreated on reboot
// easyjson:json
-type containerState struct {
+type ContainerState struct {
// The current state of the running container
State ContainerStatus `json:"state"`
// The path to the JSON OCI runtime spec for this container
@@ -350,6 +350,9 @@ type ContainerConfig struct {
PostConfigureNetNS bool `json:"postConfigureNetNS"`
+ // OCIRuntime used to create the container
+ OCIRuntime string `json:"runtime,omitempty"`
+
// ExitCommand is the container's exit command.
// This Command will be executed when the container exits
ExitCommand []string `json:"exitCommand,omitempty"`
@@ -412,14 +415,15 @@ func (c *Container) Spec() *spec.Spec {
// config does not exist (e.g., because the container was never started) return
// the spec from the config.
func (c *Container) specFromState() (*spec.Spec, error) {
- spec := c.config.Spec
+ returnSpec := c.config.Spec
if f, err := os.Open(c.state.ConfigPath); err == nil {
+ returnSpec = new(spec.Spec)
content, err := ioutil.ReadAll(f)
if err != nil {
return nil, errors.Wrapf(err, "error reading container config")
}
- if err := json.Unmarshal([]byte(content), &spec); err != nil {
+ if err := json.Unmarshal([]byte(content), &returnSpec); err != nil {
return nil, errors.Wrapf(err, "error unmarshalling container config")
}
} else {
@@ -429,7 +433,7 @@ func (c *Container) specFromState() (*spec.Spec, error) {
}
}
- return spec, nil
+ return returnSpec, nil
}
// ID returns the container's ID
@@ -1059,3 +1063,18 @@ func networkDisabled(c *Container) (bool, error) {
}
return false, nil
}
+
+// ContainerState returns containerstate struct
+func (c *Container) ContainerState() (*ContainerState, error) {
+ if !c.batched {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+
+ if err := c.syncContainer(); err != nil {
+ return nil, err
+ }
+ }
+ returnConfig := new(ContainerState)
+ deepcopier.Copy(c.state).To(returnConfig)
+ return c.state, nil
+}
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 90f4659da..39c1501da 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -388,7 +388,7 @@ func (c *Container) teardownStorage() error {
// Reset resets state fields to default values
// It is performed before a refresh and clears the state after a reboot
// It does not save the results - assumes the database will do that for us
-func resetState(state *containerState) error {
+func resetState(state *ContainerState) error {
state.PID = 0
state.Mountpoint = ""
state.Mounted = false
@@ -540,7 +540,7 @@ func (c *Container) isStopped() (bool, error) {
if err != nil {
return true, err
}
- return (c.state.State == ContainerStateStopped || c.state.State == ContainerStateExited), nil
+ return (c.state.State != ContainerStateRunning && c.state.State != ContainerStatePaused), nil
}
// save container state to the database
diff --git a/libpod/container_internal_test.go b/libpod/container_internal_test.go
index 124f1d20e..f1e2b70a7 100644
--- a/libpod/container_internal_test.go
+++ b/libpod/container_internal_test.go
@@ -37,7 +37,7 @@ func TestPostDeleteHooks(t *testing.T) {
},
StaticDir: dir, // not the bundle, but good enough for this test
},
- state: &containerState{
+ state: &ContainerState{
ExtensionStageHooks: map[string][]rspec.Hook{
"poststop": {
rspec.Hook{
diff --git a/libpod/info.go b/libpod/info.go
index a98f93897..191ce6810 100644
--- a/libpod/info.go
+++ b/libpod/info.go
@@ -4,7 +4,6 @@ import (
"bufio"
"bytes"
"fmt"
- "github.com/containers/buildah"
"io/ioutil"
"os"
"runtime"
@@ -12,6 +11,7 @@ import (
"strings"
"time"
+ "github.com/containers/buildah"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/utils"
@@ -184,12 +184,12 @@ func (r *Runtime) GetConmonVersion() (string, error) {
// GetOCIRuntimePath returns the path to the OCI Runtime Path the runtime is using
func (r *Runtime) GetOCIRuntimePath() string {
- return r.ociRuntimePath
+ return r.ociRuntimePath.Paths[0]
}
// GetOCIRuntimeVersion returns a string representation of the oci runtimes version
func (r *Runtime) GetOCIRuntimeVersion() (string, error) {
- output, err := utils.ExecCmd(r.ociRuntimePath, "--version")
+ output, err := utils.ExecCmd(r.ociRuntimePath.Paths[0], "--version")
if err != nil {
return "", err
}
diff --git a/libpod/oci.go b/libpod/oci.go
index 702f82491..3451ddaa8 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -75,10 +75,10 @@ type syncInfo struct {
}
// Make a new OCI runtime with provided options
-func newOCIRuntime(name string, path string, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool, reservePorts bool) (*OCIRuntime, error) {
+func newOCIRuntime(oruntime OCIRuntimePath, conmonPath string, conmonEnv []string, cgroupManager string, tmpDir string, logSizeMax int64, noPivotRoot bool, reservePorts bool) (*OCIRuntime, error) {
runtime := new(OCIRuntime)
- runtime.name = name
- runtime.path = path
+ runtime.name = oruntime.Name
+ runtime.path = oruntime.Paths[0]
runtime.conmonPath = conmonPath
runtime.conmonEnv = conmonEnv
runtime.cgroupManager = cgroupManager
diff --git a/libpod/options.go b/libpod/options.go
index 319e1f6c6..d965c058e 100644
--- a/libpod/options.go
+++ b/libpod/options.go
@@ -137,17 +137,17 @@ func WithStateType(storeType RuntimeStateStore) RuntimeOption {
}
// WithOCIRuntime specifies an OCI runtime to use for running containers.
-func WithOCIRuntime(runtimePath string) RuntimeOption {
+func WithOCIRuntime(runtime string) RuntimeOption {
return func(rt *Runtime) error {
if rt.valid {
return ErrRuntimeFinalized
}
- if runtimePath == "" {
+ if runtime == "" {
return errors.Wrapf(ErrInvalidArg, "must provide a valid path")
}
- rt.config.RuntimePath = []string{runtimePath}
+ rt.config.OCIRuntime = runtime
return nil
}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index c9471247c..5ff8b30f6 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -86,7 +86,7 @@ type Runtime struct {
imageContext *types.SystemContext
ociRuntime *OCIRuntime
netPlugin ocicni.CNIPlugin
- ociRuntimePath string
+ ociRuntimePath OCIRuntimePath
conmonPath string
valid bool
lock sync.RWMutex
@@ -96,6 +96,14 @@ type Runtime struct {
configuredFrom *runtimeConfiguredFrom
}
+// OCIRuntimePath contains information about an OCI runtime.
+type OCIRuntimePath struct {
+ // Name of the runtime to refer to by the --runtime flag
+ Name string `toml:"name"`
+ // Paths to check for this executable
+ Paths []string `toml:"paths"`
+}
+
// RuntimeConfig contains configuration options used to set up the runtime
type RuntimeConfig struct {
// StorageConfig is the configuration used by containers/storage
@@ -118,10 +126,10 @@ type RuntimeConfig struct {
// cause conflicts in containers/storage
// As such this is not exposed via the config file
StateType RuntimeStateStore `toml:"-"`
- // RuntimePath is the path to OCI runtime binary for launching
- // containers
- // The first path pointing to a valid file will be used
- RuntimePath []string `toml:"runtime_path"`
+ // OCIRuntime is the OCI runtime to use.
+ OCIRuntime string `toml:"runtime"`
+ // OCIRuntimes are the set of configured OCI runtimes (default is runc)
+ OCIRuntimes map[string][]string `toml:"runtimes"`
// ConmonPath is the path to the Conmon binary used for managing
// containers
// The first path pointing to a valid file will be used
@@ -213,14 +221,17 @@ var (
StorageConfig: storage.StoreOptions{},
ImageDefaultTransport: DefaultTransport,
StateType: BoltDBStateStore,
- RuntimePath: []string{
- "/usr/bin/runc",
- "/usr/sbin/runc",
- "/usr/local/bin/runc",
- "/usr/local/sbin/runc",
- "/sbin/runc",
- "/bin/runc",
- "/usr/lib/cri-o-runc/sbin/runc",
+ OCIRuntime: "runc",
+ OCIRuntimes: map[string][]string{
+ "runc": {
+ "/usr/bin/runc",
+ "/usr/sbin/runc",
+ "/usr/local/bin/runc",
+ "/usr/local/sbin/runc",
+ "/sbin/runc",
+ "/bin/runc",
+ "/usr/lib/cri-o-runc/sbin/runc",
+ },
},
ConmonPath: []string{
"/usr/libexec/podman/conmon",
@@ -414,8 +425,9 @@ func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime
runtime.config = new(RuntimeConfig)
runtime.configuredFrom = new(runtimeConfiguredFrom)
- // Set two fields not in the TOML config
+ // Set three fields not in the TOML config
runtime.config.StateType = defaultRuntimeConfig.StateType
+ runtime.config.OCIRuntime = defaultRuntimeConfig.OCIRuntime
runtime.config.StorageConfig = storage.StoreOptions{}
// Check to see if the given configuration file exists
@@ -453,22 +465,35 @@ func NewRuntimeFromConfig(configPath string, options ...RuntimeOption) (runtime
func makeRuntime(runtime *Runtime) (err error) {
// Find a working OCI runtime binary
foundRuntime := false
- for _, path := range runtime.config.RuntimePath {
- stat, err := os.Stat(path)
- if err != nil {
- continue
- }
- if stat.IsDir() {
- continue
- }
+ // If runtime is an absolute path, then use it as it is.
+ if runtime.config.OCIRuntime[0] == '/' {
foundRuntime = true
- runtime.ociRuntimePath = path
- break
+ runtime.ociRuntimePath = OCIRuntimePath{Name: filepath.Base(runtime.config.OCIRuntime), Paths: []string{runtime.config.OCIRuntime}}
+ } else {
+ // If not, look it up in the configuration.
+ paths := runtime.config.OCIRuntimes[runtime.config.OCIRuntime]
+ if paths != nil {
+ for _, path := range paths {
+ stat, err := os.Stat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ continue
+ }
+ return errors.Wrapf(err, "cannot stat %s", path)
+ }
+ if !stat.Mode().IsRegular() {
+ continue
+ }
+ foundRuntime = true
+ runtime.ociRuntimePath = OCIRuntimePath{Name: runtime.config.OCIRuntime, Paths: []string{path}}
+ break
+ }
+ }
}
if !foundRuntime {
return errors.Wrapf(ErrInvalidArg,
"could not find a working binary (configured options: %v)",
- runtime.config.RuntimePath)
+ runtime.config.OCIRuntimes)
}
// Find a working conmon binary
@@ -619,7 +644,7 @@ func makeRuntime(runtime *Runtime) (err error) {
}
// Make an OCI runtime to perform container operations
- ociRuntime, err := newOCIRuntime("runc", runtime.ociRuntimePath,
+ ociRuntime, err := newOCIRuntime(runtime.ociRuntimePath,
runtime.conmonPath, runtime.config.ConmonEnvVars,
runtime.config.CgroupManager, runtime.config.TmpDir,
runtime.config.MaxLogSize, runtime.config.NoPivotRoot,
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index ab79fe5fb..6d5ce5a7e 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -48,7 +48,7 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
ctr := new(Container)
ctr.config = new(ContainerConfig)
- ctr.state = new(containerState)
+ ctr.state = new(ContainerState)
ctr.config.ID = stringid.GenerateNonCryptoID()
@@ -62,6 +62,8 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
ctr.config.StopTimeout = CtrRemoveTimeout
+ ctr.config.OCIRuntime = r.config.OCIRuntime
+
// Set namespace based on current runtime namespace
// Do so before options run so they can override it
if r.config.Namespace != "" {
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index 1d28ff68d..279a03d3f 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -70,9 +70,12 @@ get_cmd_line_args (pid_t pid)
if (allocated == used)
{
allocated += 512;
- buffer = realloc (buffer, allocated);
- if (buffer == NULL)
- return NULL;
+ char *tmp = realloc (buffer, allocated);
+ if (buffer == NULL) {
+ free(buffer);
+ return NULL;
+ }
+ buffer=tmp;
}
}
close (fd);
diff --git a/pkg/spec/spec.go b/pkg/spec/spec.go
index 9ef0223f2..46105af4a 100644
--- a/pkg/spec/spec.go
+++ b/pkg/spec/spec.go
@@ -376,6 +376,10 @@ func CreateConfigToOCISpec(config *CreateConfig) (*spec.Spec, error) { //nolint
}
func blockAccessToKernelFilesystems(config *CreateConfig, g *generate.Generator) {
+ if config.PidMode.IsHost() && rootless.IsRootless() {
+ return
+ }
+
if !config.Privileged {
for _, mp := range []string{
"/proc/acpi",
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index 07d981786..a01e3cc2b 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -12,6 +12,7 @@ import (
"github.com/containers/libpod/cmd/podman/shared"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/libpod"
+ cc "github.com/containers/libpod/pkg/spec"
"github.com/containers/storage/pkg/archive"
"github.com/pkg/errors"
)
@@ -68,7 +69,12 @@ func (i *LibpodAPI) InspectContainer(call iopodman.VarlinkCall, name string) err
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
- data, err := shared.GetCtrInspectInfo(ctr, inspectInfo)
+ artifact, err := getArtifact(ctr)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+
+ data, err := shared.GetCtrInspectInfo(ctr.Config(), inspectInfo, artifact)
if err != nil {
return call.ReplyErrorOccurred(err.Error())
}
@@ -462,3 +468,81 @@ func (i *LibpodAPI) ContainerRestore(call iopodman.VarlinkCall, name string, kee
}
return call.ReplyContainerRestore(ctr.ID())
}
+
+func getArtifact(ctr *libpod.Container) (*cc.CreateConfig, error) {
+ var createArtifact cc.CreateConfig
+ artifact, err := ctr.GetArtifact("create-config")
+ if err != nil {
+ return nil, err
+ }
+ if err := json.Unmarshal(artifact, &createArtifact); err != nil {
+ return nil, err
+ }
+ return &createArtifact, nil
+}
+
+// ContainerConfig returns just the container.config struct
+func (i *LibpodAPI) ContainerConfig(call iopodman.VarlinkCall, name string) error {
+ ctr, err := i.Runtime.LookupContainer(name)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ config := ctr.Config()
+ b, err := json.Marshal(config)
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to serialize container config")
+ }
+ return call.ReplyContainerConfig(string(b))
+}
+
+// ContainerArtifacts returns an untouched container's artifact in string format
+func (i *LibpodAPI) ContainerArtifacts(call iopodman.VarlinkCall, name, artifactName string) error {
+ ctr, err := i.Runtime.LookupContainer(name)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ artifacts, err := ctr.GetArtifact(artifactName)
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to get container artifacts")
+ }
+ b, err := json.Marshal(artifacts)
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to serialize container artifacts")
+ }
+ return call.ReplyContainerArtifacts(string(b))
+}
+
+// ContainerInspectData returns the inspect data of a container in string format
+func (i *LibpodAPI) ContainerInspectData(call iopodman.VarlinkCall, name string) error {
+ ctr, err := i.Runtime.LookupContainer(name)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ data, err := ctr.Inspect(true)
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to inspect container")
+ }
+ b, err := json.Marshal(data)
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to serialize container inspect data")
+ }
+ return call.ReplyContainerInspectData(string(b))
+
+}
+
+// ContainerStateData returns a container's state data in string format
+func (i *LibpodAPI) ContainerStateData(call iopodman.VarlinkCall, name string) error {
+ ctr, err := i.Runtime.LookupContainer(name)
+ if err != nil {
+ return call.ReplyErrorOccurred(err.Error())
+ }
+ data, err := ctr.ContainerState()
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to obtain container state")
+ }
+ b, err := json.Marshal(data)
+ if err != nil {
+ return call.ReplyErrorOccurred("unable to serialize container inspect data")
+ }
+ return call.ReplyContainerStateData(string(b))
+}
diff --git a/test/e2e/attach_test.go b/test/e2e/attach_test.go
index 6bc576461..42866d5a1 100644
--- a/test/e2e/attach_test.go
+++ b/test/e2e/attach_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go
index ca2f35fc9..fda6eb085 100644
--- a/test/e2e/checkpoint_test.go
+++ b/test/e2e/checkpoint_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go
index 18771c09e..34b218621 100644
--- a/test/e2e/commit_test.go
+++ b/test/e2e/commit_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
new file mode 100644
index 000000000..a75601b65
--- /dev/null
+++ b/test/e2e/common_test.go
@@ -0,0 +1,240 @@
+package integration
+
+import (
+ "encoding/json"
+ "fmt"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "testing"
+
+ "github.com/containers/libpod/pkg/inspect"
+ . "github.com/containers/libpod/test/utils"
+ "github.com/containers/storage/pkg/reexec"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var (
+ PODMAN_BINARY string
+ CONMON_BINARY string
+ CNI_CONFIG_DIR string
+ RUNC_BINARY string
+ INTEGRATION_ROOT string
+ CGROUP_MANAGER = "systemd"
+ ARTIFACT_DIR = "/tmp/.artifacts"
+ RESTORE_IMAGES = []string{ALPINE, BB}
+ defaultWaitTimeout = 90
+)
+
+// PodmanTestIntegration struct for command line options
+type PodmanTestIntegration struct {
+ PodmanTest
+ ConmonBinary string
+ CrioRoot string
+ CNIConfigDir string
+ RunCBinary string
+ RunRoot string
+ StorageOptions string
+ SignaturePolicyPath string
+ CgroupManager string
+ Host HostOS
+}
+
+// PodmanSessionIntegration sturct for command line session
+type PodmanSessionIntegration struct {
+ *PodmanSession
+}
+
+// TestLibpod ginkgo master function
+func TestLibpod(t *testing.T) {
+ if reexec.Init() {
+ os.Exit(1)
+ }
+ if os.Getenv("NOCACHE") == "1" {
+ CACHE_IMAGES = []string{}
+ RESTORE_IMAGES = []string{}
+ }
+ RegisterFailHandler(Fail)
+ RunSpecs(t, "Libpod Suite")
+}
+
+var _ = BeforeSuite(func() {
+ //Cache images
+ cwd, _ := os.Getwd()
+ INTEGRATION_ROOT = filepath.Join(cwd, "../../")
+ podman := PodmanTestCreate("/tmp")
+ podman.ArtifactPath = ARTIFACT_DIR
+ if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) {
+ if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil {
+ fmt.Printf("%q\n", err)
+ os.Exit(1)
+ }
+ }
+ for _, image := range CACHE_IMAGES {
+ if err := podman.CreateArtifact(image); err != nil {
+ fmt.Printf("%q\n", err)
+ os.Exit(1)
+ }
+ }
+ host := GetHostDistributionInfo()
+ if host.Distribution == "rhel" && strings.HasPrefix(host.Version, "7") {
+ f, err := os.OpenFile("/proc/sys/user/max_user_namespaces", os.O_WRONLY, 0644)
+ if err != nil {
+ fmt.Println("Unable to enable userspace on RHEL 7")
+ os.Exit(1)
+ }
+ _, err = f.WriteString("15000")
+ if err != nil {
+ fmt.Println("Unable to enable userspace on RHEL 7")
+ os.Exit(1)
+ }
+ f.Close()
+ }
+})
+
+// PodmanTestCreate creates a PodmanTestIntegration instance for the tests
+func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
+ var (
+ podmanRemoteBinary string
+ )
+
+ host := GetHostDistributionInfo()
+ cwd, _ := os.Getwd()
+
+ podmanBinary := filepath.Join(cwd, "../../bin/podman")
+ if os.Getenv("PODMAN_BINARY") != "" {
+ podmanBinary = os.Getenv("PODMAN_BINARY")
+ }
+
+ if remote {
+ podmanRemoteBinary = filepath.Join(cwd, "../../bin/podman-remote")
+ if os.Getenv("PODMAN_REMOTE_BINARY") != "" {
+ podmanRemoteBinary = os.Getenv("PODMAN_REMOTE_BINARY")
+ }
+ }
+ conmonBinary := filepath.Join("/usr/libexec/podman/conmon")
+ altConmonBinary := "/usr/libexec/crio/conmon"
+ if _, err := os.Stat(conmonBinary); os.IsNotExist(err) {
+ conmonBinary = altConmonBinary
+ }
+ if os.Getenv("CONMON_BINARY") != "" {
+ conmonBinary = os.Getenv("CONMON_BINARY")
+ }
+ storageOptions := STORAGE_OPTIONS
+ if os.Getenv("STORAGE_OPTIONS") != "" {
+ storageOptions = os.Getenv("STORAGE_OPTIONS")
+ }
+ cgroupManager := CGROUP_MANAGER
+ if os.Getenv("CGROUP_MANAGER") != "" {
+ cgroupManager = os.Getenv("CGROUP_MANAGER")
+ }
+
+ // Ubuntu doesn't use systemd cgroups
+ if host.Distribution == "ubuntu" {
+ cgroupManager = "cgroupfs"
+ }
+
+ runCBinary, err := exec.LookPath("runc")
+ // If we cannot find the runc binary, setting to something static as we have no way
+ // to return an error. The tests will fail and point out that the runc binary could
+ // not be found nicely.
+ if err != nil {
+ runCBinary = "/usr/bin/runc"
+ }
+
+ CNIConfigDir := "/etc/cni/net.d"
+
+ p := &PodmanTestIntegration{
+ PodmanTest: PodmanTest{
+ PodmanBinary: podmanBinary,
+ ArtifactPath: ARTIFACT_DIR,
+ TempDir: tempDir,
+ RemoteTest: remote,
+ },
+ ConmonBinary: conmonBinary,
+ CrioRoot: filepath.Join(tempDir, "crio"),
+ CNIConfigDir: CNIConfigDir,
+ RunCBinary: runCBinary,
+ RunRoot: filepath.Join(tempDir, "crio-run"),
+ StorageOptions: storageOptions,
+ SignaturePolicyPath: filepath.Join(INTEGRATION_ROOT, "test/policy.json"),
+ CgroupManager: cgroupManager,
+ Host: host,
+ }
+ if remote {
+ p.PodmanTest.RemotePodmanBinary = podmanRemoteBinary
+ }
+
+ // Setup registries.conf ENV variable
+ p.setDefaultRegistriesConfigEnv()
+ // Rewrite the PodmanAsUser function
+ p.PodmanMakeOptions = p.makeOptions
+ return p
+}
+
+//MakeOptions assembles all the podman main options
+func (p *PodmanTestIntegration) makeOptions(args []string) []string {
+ podmanOptions := strings.Split(fmt.Sprintf("--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s",
+ p.CrioRoot, p.RunRoot, p.RunCBinary, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager), " ")
+ if os.Getenv("HOOK_OPTION") != "" {
+ podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION"))
+ }
+ podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...)
+ podmanOptions = append(podmanOptions, args...)
+ return podmanOptions
+}
+
+// RestoreArtifact puts the cached image into our test store
+func (p *PodmanTestIntegration) RestoreArtifact(image string) error {
+ fmt.Printf("Restoring %s...\n", image)
+ dest := strings.Split(image, "/")
+ destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1))
+ restore := p.Podman([]string{"load", "-q", "-i", destName})
+ restore.Wait(90)
+ return nil
+}
+
+// RestoreAllArtifacts unpacks all cached images
+func (p *PodmanTestIntegration) RestoreAllArtifacts() error {
+ if os.Getenv("NO_TEST_CACHE") != "" {
+ return nil
+ }
+ for _, image := range RESTORE_IMAGES {
+ if err := p.RestoreArtifact(image); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// CreateArtifact creates a cached image in the artifact dir
+func (p *PodmanTestIntegration) CreateArtifact(image string) error {
+ if os.Getenv("NO_TEST_CACHE") != "" {
+ return nil
+ }
+ fmt.Printf("Caching %s...", image)
+ dest := strings.Split(image, "/")
+ destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1))
+ if _, err := os.Stat(destName); os.IsNotExist(err) {
+ pull := p.Podman([]string{"pull", image})
+ pull.Wait(90)
+
+ save := p.Podman([]string{"save", "-o", destName, image})
+ save.Wait(90)
+ fmt.Printf("\n")
+ } else {
+ fmt.Printf(" already exists.\n")
+ }
+ return nil
+}
+
+// InspectImageJSON takes the session output of an inspect
+// image and returns json
+func (s *PodmanSessionIntegration) InspectImageJSON() []inspect.ImageData {
+ var i []inspect.ImageData
+ err := json.Unmarshal(s.Out.Contents(), &i)
+ Expect(err).To(BeNil())
+ return i
+}
diff --git a/test/e2e/create_staticip_test.go b/test/e2e/create_staticip_test.go
index 17ac5cb40..9bdc30342 100644
--- a/test/e2e/create_staticip_test.go
+++ b/test/e2e/create_staticip_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 684a7cd88..b28a0c428 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/diff_test.go b/test/e2e/diff_test.go
index 2c0060dd5..94e150467 100644
--- a/test/e2e/diff_test.go
+++ b/test/e2e/diff_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/exec_test.go b/test/e2e/exec_test.go
index a181501a5..5839b364d 100644
--- a/test/e2e/exec_test.go
+++ b/test/e2e/exec_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/exists_test.go b/test/e2e/exists_test.go
index d9652de4b..c4b5e4968 100644
--- a/test/e2e/exists_test.go
+++ b/test/e2e/exists_test.go
@@ -32,6 +32,7 @@ var _ = Describe("Podman image|container exists", func() {
GinkgoWriter.Write([]byte(timedResult))
})
+
It("podman image exists in local storage by fq name", func() {
session := podmanTest.Podman([]string{"image", "exists", ALPINE})
session.WaitWithDefaultTimeout()
@@ -48,6 +49,7 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session.ExitCode()).To(Equal(1))
})
It("podman container exists in local storage by name", func() {
+ SkipIfRemote()
setup := podmanTest.RunTopContainer("foobar")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
@@ -57,6 +59,7 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session.ExitCode()).To(Equal(0))
})
It("podman container exists in local storage by container ID", func() {
+ SkipIfRemote()
setup := podmanTest.RunTopContainer("")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
@@ -67,6 +70,7 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session.ExitCode()).To(Equal(0))
})
It("podman container exists in local storage by short container ID", func() {
+ SkipIfRemote()
setup := podmanTest.RunTopContainer("")
setup.WaitWithDefaultTimeout()
Expect(setup.ExitCode()).To(Equal(0))
@@ -77,12 +81,14 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session.ExitCode()).To(Equal(0))
})
It("podman container does not exist in local storage", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"container", "exists", "foobar"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(1))
})
It("podman pod exists in local storage by name", func() {
+ SkipIfRemote()
setup, rc, _ := podmanTest.CreatePod("foobar")
setup.WaitWithDefaultTimeout()
Expect(rc).To(Equal(0))
@@ -92,6 +98,7 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session.ExitCode()).To(Equal(0))
})
It("podman pod exists in local storage by container ID", func() {
+ SkipIfRemote()
setup, rc, podID := podmanTest.CreatePod("")
setup.WaitWithDefaultTimeout()
Expect(rc).To(Equal(0))
@@ -101,6 +108,7 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session.ExitCode()).To(Equal(0))
})
It("podman pod exists in local storage by short container ID", func() {
+ SkipIfRemote()
setup, rc, podID := podmanTest.CreatePod("")
setup.WaitWithDefaultTimeout()
Expect(rc).To(Equal(0))
@@ -110,6 +118,7 @@ var _ = Describe("Podman image|container exists", func() {
Expect(session.ExitCode()).To(Equal(0))
})
It("podman pod does not exist in local storage", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"pod", "exists", "foobar"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(1))
diff --git a/test/e2e/export_test.go b/test/e2e/export_test.go
index 42ea45041..de3f23667 100644
--- a/test/e2e/export_test.go
+++ b/test/e2e/export_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/generate_kube_test.go b/test/e2e/generate_kube_test.go
index 0ee078455..94e02dc55 100644
--- a/test/e2e/generate_kube_test.go
+++ b/test/e2e/generate_kube_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index af32c032b..595084403 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -106,6 +106,9 @@ var _ = Describe("Podman images", func() {
})
It("podman images filter before image", func() {
+ if podmanTest.RemoteTest {
+ Skip("Does not work on remote client")
+ }
dockerfile := `FROM docker.io/library/alpine:latest
`
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
@@ -116,6 +119,9 @@ var _ = Describe("Podman images", func() {
})
It("podman images filter after image", func() {
+ if podmanTest.RemoteTest {
+ Skip("Does not work on remote client")
+ }
rmi := podmanTest.Podman([]string{"rmi", "busybox"})
rmi.WaitWithDefaultTimeout()
Expect(rmi.ExitCode()).To(Equal(0))
@@ -130,6 +136,9 @@ var _ = Describe("Podman images", func() {
})
It("podman images filter dangling", func() {
+ if podmanTest.RemoteTest {
+ Skip("Does not work on remote client")
+ }
dockerfile := `FROM docker.io/library/alpine:latest
`
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
@@ -141,6 +150,9 @@ var _ = Describe("Podman images", func() {
})
It("podman check for image with sha256: prefix", func() {
+ if podmanTest.RemoteTest {
+ Skip("Does not work on remote client")
+ }
session := podmanTest.Podman([]string{"inspect", "--format=json", ALPINE})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -175,6 +187,9 @@ var _ = Describe("Podman images", func() {
})
It("podman images --all flag", func() {
+ if podmanTest.RemoteTest {
+ Skip("Does not work on remote client")
+ }
dockerfile := `FROM docker.io/library/alpine:latest
RUN mkdir hello
RUN touch test.txt
diff --git a/test/e2e/import_test.go b/test/e2e/import_test.go
index 6f132fd93..dc7451f7b 100644
--- a/test/e2e/import_test.go
+++ b/test/e2e/import_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go
index e972c86c8..2022dff1b 100644
--- a/test/e2e/info_test.go
+++ b/test/e2e/info_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/inspect_test.go b/test/e2e/inspect_test.go
index 87c4db935..e5c471bf9 100644
--- a/test/e2e/inspect_test.go
+++ b/test/e2e/inspect_test.go
@@ -43,6 +43,7 @@ var _ = Describe("Podman inspect", func() {
})
It("podman inspect bogus container", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"inspect", "foobar4321"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Not(Equal(0)))
@@ -66,6 +67,7 @@ var _ = Describe("Podman inspect", func() {
})
It("podman inspect container with size", func() {
+ SkipIfRemote()
_, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
@@ -77,6 +79,7 @@ var _ = Describe("Podman inspect", func() {
})
It("podman inspect container and image", func() {
+ SkipIfRemote()
ls, ec, _ := podmanTest.RunLsContainer("")
Expect(ec).To(Equal(0))
cid := ls.OutputToString()
@@ -88,6 +91,7 @@ var _ = Describe("Podman inspect", func() {
})
It("podman inspect -l with additional input should fail", func() {
+ SkipIfRemote()
result := podmanTest.Podman([]string{"inspect", "-l", "1234foobar"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(125))
diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go
index 913a843cb..5f1f5f4c1 100644
--- a/test/e2e/kill_test.go
+++ b/test/e2e/kill_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/libpod_suite_remoteclient_test.go b/test/e2e/libpod_suite_remoteclient_test.go
new file mode 100644
index 000000000..660c2f639
--- /dev/null
+++ b/test/e2e/libpod_suite_remoteclient_test.go
@@ -0,0 +1,157 @@
+// +build remoteclient
+
+package integration
+
+import (
+ "fmt"
+ "github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/inspect"
+ "github.com/onsi/ginkgo"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+)
+
+func SkipIfRemote() {
+ ginkgo.Skip("This function is not enabled for remote podman")
+}
+
+// Cleanup cleans up the temporary store
+func (p *PodmanTestIntegration) Cleanup() {
+ p.StopVarlink()
+ // TODO
+ // Stop all containers
+ // Rm all containers
+
+ if err := os.RemoveAll(p.TempDir); err != nil {
+ fmt.Printf("%q\n", err)
+ }
+
+ // Clean up the registries configuration file ENV variable set in Create
+ resetRegistriesConfigEnv()
+}
+
+// Podman is the exec call to podman on the filesystem
+func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration {
+ podmanSession := p.PodmanBase(args)
+ return &PodmanSessionIntegration{podmanSession}
+}
+
+//RunTopContainer runs a simple container in the background that
+// runs top. If the name passed != "", it will have a name
+func (p *PodmanTestIntegration) RunTopContainer(name string) *PodmanSessionIntegration {
+ // TODO
+ return nil
+}
+
+//RunLsContainer runs a simple container in the background that
+// simply runs ls. If the name passed != "", it will have a name
+func (p *PodmanTestIntegration) RunLsContainer(name string) (*PodmanSessionIntegration, int, string) {
+ // TODO
+ return nil, 0, ""
+}
+
+// InspectImageJSON takes the session output of an inspect
+// image and returns json
+//func (s *PodmanSessionIntegration) InspectImageJSON() []inspect.ImageData {
+// // TODO
+// return nil
+//}
+
+func (p *PodmanTestIntegration) setDefaultRegistriesConfigEnv() {
+ defaultFile := filepath.Join(INTEGRATION_ROOT, "test/registries.conf")
+ os.Setenv("REGISTRIES_CONFIG_PATH", defaultFile)
+}
+
+func (p *PodmanTestIntegration) setRegistriesConfigEnv(b []byte) {
+ outfile := filepath.Join(p.TempDir, "registries.conf")
+ os.Setenv("REGISTRIES_CONFIG_PATH", outfile)
+ ioutil.WriteFile(outfile, b, 0644)
+}
+
+func resetRegistriesConfigEnv() {
+ os.Setenv("REGISTRIES_CONFIG_PATH", "")
+}
+
+// InspectContainerToJSON takes the session output of an inspect
+// container and returns json
+func (s *PodmanSessionIntegration) InspectContainerToJSON() []inspect.ContainerData {
+ // TODO
+ return nil
+}
+
+// CreatePod creates a pod with no infra container
+// it optionally takes a pod name
+func (p *PodmanTestIntegration) CreatePod(name string) (*PodmanSessionIntegration, int, string) {
+ // TODO
+ return nil, 0, ""
+}
+
+func (p *PodmanTestIntegration) RunTopContainerInPod(name, pod string) *PodmanSessionIntegration {
+ // TODO
+ return nil
+}
+
+// BuildImage uses podman build and buildah to build an image
+// called imageName based on a string dockerfile
+func (p *PodmanTestIntegration) BuildImage(dockerfile, imageName string, layers string) {
+ // TODO
+}
+
+// CleanupPod cleans up the temporary store
+func (p *PodmanTestIntegration) CleanupPod() {
+ // TODO
+}
+
+// InspectPodToJSON takes the sessions output from a pod inspect and returns json
+func (s *PodmanSessionIntegration) InspectPodToJSON() libpod.PodInspect {
+ // TODO
+ return libpod.PodInspect{}
+}
+func (p *PodmanTestIntegration) RunLsContainerInPod(name, pod string) (*PodmanSessionIntegration, int, string) {
+ // TODO
+ return nil, 0, ""
+}
+
+// PullImages pulls multiple images
+func (p *PodmanTestIntegration) PullImages(images []string) error {
+ // TODO
+ return libpod.ErrNotImplemented
+}
+
+// PodmanPID execs podman and returns its PID
+func (p *PodmanTestIntegration) PodmanPID(args []string) (*PodmanSessionIntegration, int) {
+ // TODO
+ return nil, 0
+}
+
+// CleanupVolume cleans up the temporary store
+func (p *PodmanTestIntegration) CleanupVolume() {
+ // TODO
+}
+
+func PodmanTestCreate(tempDir string) *PodmanTestIntegration {
+ pti := PodmanTestCreateUtil(tempDir, true)
+ pti.StartVarlink()
+ return pti
+}
+
+func (p *PodmanTestIntegration) StartVarlink() {
+ if _, err := os.Stat("/path/to/whatever"); os.IsNotExist(err) {
+ os.MkdirAll("/run/podman", 0755)
+ }
+ args := []string{"varlink", "--timeout", "0", "unix:/run/podman/io.podman"}
+ podmanOptions := p.MakeOptions(args)
+ command := exec.Command(p.PodmanBinary, podmanOptions...)
+ fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
+ command.Start()
+ p.VarlinkSession = command.Process
+}
+
+func (p *PodmanTestIntegration) StopVarlink() {
+ varlinkSession := p.VarlinkSession
+ varlinkSession.Kill()
+ varlinkSession.Wait()
+}
diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go
index d312124ab..48304af7f 100644
--- a/test/e2e/libpod_suite_test.go
+++ b/test/e2e/libpod_suite_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
@@ -8,172 +10,16 @@ import (
"os/exec"
"path/filepath"
"strings"
- "testing"
"github.com/containers/libpod/libpod"
"github.com/containers/libpod/pkg/inspect"
. "github.com/containers/libpod/test/utils"
- "github.com/containers/storage/pkg/reexec"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/onsi/gomega/gexec"
)
-var (
- PODMAN_BINARY string
- CONMON_BINARY string
- CNI_CONFIG_DIR string
- RUNC_BINARY string
- INTEGRATION_ROOT string
- CGROUP_MANAGER = "systemd"
- ARTIFACT_DIR = "/tmp/.artifacts"
- RESTORE_IMAGES = []string{ALPINE, BB}
- defaultWaitTimeout = 90
-)
-
-// PodmanTestIntegration struct for command line options
-type PodmanTestIntegration struct {
- PodmanTest
- ConmonBinary string
- CrioRoot string
- CNIConfigDir string
- RunCBinary string
- RunRoot string
- StorageOptions string
- SignaturePolicyPath string
- CgroupManager string
- Host HostOS
-}
-
-// PodmanSessionIntegration sturct for command line session
-type PodmanSessionIntegration struct {
- *PodmanSession
-}
-
-// TestLibpod ginkgo master function
-func TestLibpod(t *testing.T) {
- if reexec.Init() {
- os.Exit(1)
- }
- if os.Getenv("NOCACHE") == "1" {
- CACHE_IMAGES = []string{}
- RESTORE_IMAGES = []string{}
- }
- RegisterFailHandler(Fail)
- RunSpecs(t, "Libpod Suite")
-}
-
-var _ = BeforeSuite(func() {
- //Cache images
- cwd, _ := os.Getwd()
- INTEGRATION_ROOT = filepath.Join(cwd, "../../")
- podman := PodmanTestCreate("/tmp")
- podman.ArtifactPath = ARTIFACT_DIR
- if _, err := os.Stat(ARTIFACT_DIR); os.IsNotExist(err) {
- if err = os.Mkdir(ARTIFACT_DIR, 0777); err != nil {
- fmt.Printf("%q\n", err)
- os.Exit(1)
- }
- }
- for _, image := range CACHE_IMAGES {
- if err := podman.CreateArtifact(image); err != nil {
- fmt.Printf("%q\n", err)
- os.Exit(1)
- }
- }
- host := GetHostDistributionInfo()
- if host.Distribution == "rhel" && strings.HasPrefix(host.Version, "7") {
- f, err := os.OpenFile("/proc/sys/user/max_user_namespaces", os.O_WRONLY, 0644)
- if err != nil {
- fmt.Println("Unable to enable userspace on RHEL 7")
- os.Exit(1)
- }
- _, err = f.WriteString("15000")
- if err != nil {
- fmt.Println("Unable to enable userspace on RHEL 7")
- os.Exit(1)
- }
- f.Close()
- }
-})
-
-// PodmanTestCreate creates a PodmanTestIntegration instance for the tests
-func PodmanTestCreate(tempDir string) *PodmanTestIntegration {
-
- host := GetHostDistributionInfo()
- cwd, _ := os.Getwd()
-
- podmanBinary := filepath.Join(cwd, "../../bin/podman")
- if os.Getenv("PODMAN_BINARY") != "" {
- podmanBinary = os.Getenv("PODMAN_BINARY")
- }
- conmonBinary := filepath.Join("/usr/libexec/podman/conmon")
- altConmonBinary := "/usr/libexec/crio/conmon"
- if _, err := os.Stat(conmonBinary); os.IsNotExist(err) {
- conmonBinary = altConmonBinary
- }
- if os.Getenv("CONMON_BINARY") != "" {
- conmonBinary = os.Getenv("CONMON_BINARY")
- }
- storageOptions := STORAGE_OPTIONS
- if os.Getenv("STORAGE_OPTIONS") != "" {
- storageOptions = os.Getenv("STORAGE_OPTIONS")
- }
- cgroupManager := CGROUP_MANAGER
- if os.Getenv("CGROUP_MANAGER") != "" {
- cgroupManager = os.Getenv("CGROUP_MANAGER")
- }
-
- // Ubuntu doesn't use systemd cgroups
- if host.Distribution == "ubuntu" {
- cgroupManager = "cgroupfs"
- }
-
- runCBinary, err := exec.LookPath("runc")
- // If we cannot find the runc binary, setting to something static as we have no way
- // to return an error. The tests will fail and point out that the runc binary could
- // not be found nicely.
- if err != nil {
- runCBinary = "/usr/bin/runc"
- }
-
- CNIConfigDir := "/etc/cni/net.d"
-
- p := &PodmanTestIntegration{
- PodmanTest: PodmanTest{
- PodmanBinary: podmanBinary,
- ArtifactPath: ARTIFACT_DIR,
- TempDir: tempDir,
- },
- ConmonBinary: conmonBinary,
- CrioRoot: filepath.Join(tempDir, "crio"),
- CNIConfigDir: CNIConfigDir,
- RunCBinary: runCBinary,
- RunRoot: filepath.Join(tempDir, "crio-run"),
- StorageOptions: storageOptions,
- SignaturePolicyPath: filepath.Join(INTEGRATION_ROOT, "test/policy.json"),
- CgroupManager: cgroupManager,
- Host: host,
- }
-
- // Setup registries.conf ENV variable
- p.setDefaultRegistriesConfigEnv()
- // Rewrite the PodmanAsUser function
- p.PodmanMakeOptions = p.makeOptions
- return p
-}
-
-//MakeOptions assembles all the podman main options
-func (p *PodmanTestIntegration) makeOptions(args []string) []string {
- podmanOptions := strings.Split(fmt.Sprintf("--root %s --runroot %s --runtime %s --conmon %s --cni-config-dir %s --cgroup-manager %s",
- p.CrioRoot, p.RunRoot, p.RunCBinary, p.ConmonBinary, p.CNIConfigDir, p.CgroupManager), " ")
- if os.Getenv("HOOK_OPTION") != "" {
- podmanOptions = append(podmanOptions, os.Getenv("HOOK_OPTION"))
- }
- podmanOptions = append(podmanOptions, strings.Split(p.StorageOptions, " ")...)
- podmanOptions = append(podmanOptions, args...)
- return podmanOptions
-}
+func SkipIfRemote() {}
// Podman is the exec call to podman on the filesystem
func (p *PodmanTestIntegration) Podman(args []string) *PodmanSessionIntegration {
@@ -272,59 +118,6 @@ func (s *PodmanSessionIntegration) InspectPodToJSON() libpod.PodInspect {
return i
}
-// InspectImageJSON takes the session output of an inspect
-// image and returns json
-func (s *PodmanSessionIntegration) InspectImageJSON() []inspect.ImageData {
- var i []inspect.ImageData
- err := json.Unmarshal(s.Out.Contents(), &i)
- Expect(err).To(BeNil())
- return i
-}
-
-// CreateArtifact creates a cached image in the artifact dir
-func (p *PodmanTestIntegration) CreateArtifact(image string) error {
- if os.Getenv("NO_TEST_CACHE") != "" {
- return nil
- }
- fmt.Printf("Caching %s...", image)
- dest := strings.Split(image, "/")
- destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1))
- if _, err := os.Stat(destName); os.IsNotExist(err) {
- pull := p.Podman([]string{"pull", image})
- pull.Wait(90)
-
- save := p.Podman([]string{"save", "-o", destName, image})
- save.Wait(90)
- fmt.Printf("\n")
- } else {
- fmt.Printf(" already exists.\n")
- }
- return nil
-}
-
-// RestoreArtifact puts the cached image into our test store
-func (p *PodmanTestIntegration) RestoreArtifact(image string) error {
- fmt.Printf("Restoring %s...\n", image)
- dest := strings.Split(image, "/")
- destName := fmt.Sprintf("/tmp/%s.tar", strings.Replace(strings.Join(strings.Split(dest[len(dest)-1], "/"), ""), ":", "-", -1))
- restore := p.Podman([]string{"load", "-q", "-i", destName})
- restore.Wait(90)
- return nil
-}
-
-// RestoreAllArtifacts unpacks all cached images
-func (p *PodmanTestIntegration) RestoreAllArtifacts() error {
- if os.Getenv("NO_TEST_CACHE") != "" {
- return nil
- }
- for _, image := range RESTORE_IMAGES {
- if err := p.RestoreArtifact(image); err != nil {
- return err
- }
- }
- return nil
-}
-
// CreatePod creates a pod with no infra container
// it optionally takes a pod name
func (p *PodmanTestIntegration) CreatePod(name string) (*PodmanSessionIntegration, int, string) {
@@ -406,3 +199,10 @@ func (p *PodmanTestIntegration) setRegistriesConfigEnv(b []byte) {
func resetRegistriesConfigEnv() {
os.Setenv("REGISTRIES_CONFIG_PATH", "")
}
+
+func PodmanTestCreate(tempDir string) *PodmanTestIntegration {
+ return PodmanTestCreateUtil(tempDir, false)
+}
+
+//func (p *PodmanTestIntegration) StartVarlink() {}
+//func (p *PodmanTestIntegration) StopVarlink() {}
diff --git a/test/e2e/load_test.go b/test/e2e/load_test.go
index 4d7007191..423f99ac8 100644
--- a/test/e2e/load_test.go
+++ b/test/e2e/load_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index 236ddb221..d3c4fb802 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/mount_test.go b/test/e2e/mount_test.go
index a93a0aa4a..94218e6a9 100644
--- a/test/e2e/mount_test.go
+++ b/test/e2e/mount_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/namespace_test.go b/test/e2e/namespace_test.go
index ebce09f54..a0b6e6187 100644
--- a/test/e2e/namespace_test.go
+++ b/test/e2e/namespace_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go
index e109bc077..f1ea17ead 100644
--- a/test/e2e/pause_test.go
+++ b/test/e2e/pause_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index 5abf9613b..cb2b0e7b0 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go
index 8c7c09c97..161bf7f9c 100644
--- a/test/e2e/pod_infra_container_test.go
+++ b/test/e2e/pod_infra_container_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go
index 51e95f788..457acb373 100644
--- a/test/e2e/pod_inspect_test.go
+++ b/test/e2e/pod_inspect_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go
index d9cec2cad..419a3a777 100644
--- a/test/e2e/pod_kill_test.go
+++ b/test/e2e/pod_kill_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_pause_test.go b/test/e2e/pod_pause_test.go
index 8f766d3db..a5192f84b 100644
--- a/test/e2e/pod_pause_test.go
+++ b/test/e2e/pod_pause_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_pod_namespaces.go b/test/e2e/pod_pod_namespaces.go
index b1d5abb1c..9815e37ef 100644
--- a/test/e2e/pod_pod_namespaces.go
+++ b/test/e2e/pod_pod_namespaces.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go
index 9e816bcfa..3b7198861 100644
--- a/test/e2e/pod_ps_test.go
+++ b/test/e2e/pod_ps_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_restart_test.go b/test/e2e/pod_restart_test.go
index d0964e8de..e8acfd2ec 100644
--- a/test/e2e/pod_restart_test.go
+++ b/test/e2e/pod_restart_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index 48767b33f..f63d2c8aa 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_start_test.go b/test/e2e/pod_start_test.go
index 346346425..77e8b586d 100644
--- a/test/e2e/pod_start_test.go
+++ b/test/e2e/pod_start_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_stats_test.go b/test/e2e/pod_stats_test.go
index d7b9a8f48..43d089a24 100644
--- a/test/e2e/pod_stats_test.go
+++ b/test/e2e/pod_stats_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_stop_test.go b/test/e2e/pod_stop_test.go
index 6c5319a3d..b3d7df252 100644
--- a/test/e2e/pod_stop_test.go
+++ b/test/e2e/pod_stop_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pod_top_test.go b/test/e2e/pod_top_test.go
index 3dc80ddfb..507d723b4 100644
--- a/test/e2e/pod_top_test.go
+++ b/test/e2e/pod_top_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/port_test.go b/test/e2e/port_test.go
index 09f3ab53a..fa633c379 100644
--- a/test/e2e/port_test.go
+++ b/test/e2e/port_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/prune_test.go b/test/e2e/prune_test.go
index 6679a676c..50a279232 100644
--- a/test/e2e/prune_test.go
+++ b/test/e2e/prune_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 9caa6e7f1..bff2427d5 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/pull_test.go b/test/e2e/pull_test.go
index ad8742984..bfae15152 100644
--- a/test/e2e/pull_test.go
+++ b/test/e2e/pull_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/push_test.go b/test/e2e/push_test.go
index 3447cd57e..42aefd1f7 100644
--- a/test/e2e/push_test.go
+++ b/test/e2e/push_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/refresh_test.go b/test/e2e/refresh_test.go
index bf8fff105..de331bf88 100644
--- a/test/e2e/refresh_test.go
+++ b/test/e2e/refresh_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/restart_test.go b/test/e2e/restart_test.go
index 30801c272..3c77444d8 100644
--- a/test/e2e/restart_test.go
+++ b/test/e2e/restart_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go
index c6a2b61ee..bc1431bce 100644
--- a/test/e2e/rm_test.go
+++ b/test/e2e/rm_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/rmi_test.go b/test/e2e/rmi_test.go
index 22bfbbe8c..c160e1bc5 100644
--- a/test/e2e/rmi_test.go
+++ b/test/e2e/rmi_test.go
@@ -111,6 +111,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi image that is a parent of another image", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"rmi", "-fa"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -148,6 +149,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi image that is created from another named imaged", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"rmi", "-fa"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -183,6 +185,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi with cached images", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"rmi", "-fa"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -252,6 +255,7 @@ var _ = Describe("Podman rmi", func() {
})
It("podman rmi -a with parent|child images", func() {
+ SkipIfRemote()
dockerfile := `FROM docker.io/library/alpine:latest AS base
RUN touch /1
ENV LOCAL=/1
diff --git a/test/e2e/rootless_test.go b/test/e2e/rootless_test.go
index 8e9f9fc8d..2b84d34c9 100644
--- a/test/e2e/rootless_test.go
+++ b/test/e2e/rootless_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
@@ -274,6 +276,10 @@ var _ = Describe("Podman rootless", func() {
runRootlessHelper([]string{"--net", "host"})
})
+ It("podman rootless rootfs --pid host", func() {
+ runRootlessHelper([]string{"--pid", "host"})
+ })
+
It("podman rootless rootfs --privileged", func() {
runRootlessHelper([]string{"--privileged"})
})
diff --git a/test/e2e/run_cgroup_parent_test.go b/test/e2e/run_cgroup_parent_test.go
index 57b3aa6b1..efc9a7009 100644
--- a/test/e2e/run_cgroup_parent_test.go
+++ b/test/e2e/run_cgroup_parent_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_cleanup_test.go b/test/e2e/run_cleanup_test.go
index 5b60efa86..aa823b4e6 100644
--- a/test/e2e/run_cleanup_test.go
+++ b/test/e2e/run_cleanup_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_cpu_test.go b/test/e2e/run_cpu_test.go
index 343fe656c..f74d3ed84 100644
--- a/test/e2e/run_cpu_test.go
+++ b/test/e2e/run_cpu_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_device_test.go b/test/e2e/run_device_test.go
index 7f1f7b2d0..4f26ac8ee 100644
--- a/test/e2e/run_device_test.go
+++ b/test/e2e/run_device_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_dns_test.go b/test/e2e/run_dns_test.go
index 444c568e0..6c649cdbc 100644
--- a/test/e2e/run_dns_test.go
+++ b/test/e2e/run_dns_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_entrypoint_test.go b/test/e2e/run_entrypoint_test.go
index 227037f92..a33e16b63 100644
--- a/test/e2e/run_entrypoint_test.go
+++ b/test/e2e/run_entrypoint_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_exit_test.go b/test/e2e/run_exit_test.go
index 788cbd8dd..03072f598 100644
--- a/test/e2e/run_exit_test.go
+++ b/test/e2e/run_exit_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_memory_test.go b/test/e2e/run_memory_test.go
index 91a311e85..e9262d4f0 100644
--- a/test/e2e/run_memory_test.go
+++ b/test/e2e/run_memory_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go
index 68b1f06de..1c09a4d0b 100644
--- a/test/e2e/run_networking_test.go
+++ b/test/e2e/run_networking_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_ns_test.go b/test/e2e/run_ns_test.go
index e4dcc5adc..9962185f2 100644
--- a/test/e2e/run_ns_test.go
+++ b/test/e2e/run_ns_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_passwd_test.go b/test/e2e/run_passwd_test.go
index 891f4fbd8..fcb81fb77 100644
--- a/test/e2e/run_passwd_test.go
+++ b/test/e2e/run_passwd_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_privileged_test.go b/test/e2e/run_privileged_test.go
index 770ea3e6b..0c0de30c5 100644
--- a/test/e2e/run_privileged_test.go
+++ b/test/e2e/run_privileged_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_restart_test.go b/test/e2e/run_restart_test.go
index 018c66b45..2659d2b11 100644
--- a/test/e2e/run_restart_test.go
+++ b/test/e2e/run_restart_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_selinux_test.go b/test/e2e/run_selinux_test.go
index 418382e16..57e488abc 100644
--- a/test/e2e/run_selinux_test.go
+++ b/test/e2e/run_selinux_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_signal_test.go b/test/e2e/run_signal_test.go
index 8f7894db8..9be8e7810 100644
--- a/test/e2e/run_signal_test.go
+++ b/test/e2e/run_signal_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_staticip_test.go b/test/e2e/run_staticip_test.go
index 749835b47..bf50e5eb7 100644
--- a/test/e2e/run_staticip_test.go
+++ b/test/e2e/run_staticip_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 1e7f4f0f4..22a36bb6c 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/run_userns_test.go b/test/e2e/run_userns_test.go
index b1f3d08b4..254897e70 100644
--- a/test/e2e/run_userns_test.go
+++ b/test/e2e/run_userns_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/runlabel_test.go b/test/e2e/runlabel_test.go
index 93a19ba30..9b4f584b0 100644
--- a/test/e2e/runlabel_test.go
+++ b/test/e2e/runlabel_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go
index 9f64e49a7..b354492b8 100644
--- a/test/e2e/save_test.go
+++ b/test/e2e/save_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go
index 0167e9062..1438fd97b 100644
--- a/test/e2e/search_test.go
+++ b/test/e2e/search_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go
index 9d7ac145c..c4ed6f545 100644
--- a/test/e2e/start_test.go
+++ b/test/e2e/start_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/stats_test.go b/test/e2e/stats_test.go
index be00d68b2..e7b0b5f6e 100644
--- a/test/e2e/stats_test.go
+++ b/test/e2e/stats_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go
index 5c229b9b4..8fffedbb9 100644
--- a/test/e2e/stop_test.go
+++ b/test/e2e/stop_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go
index ce67bb469..a7e7a1500 100644
--- a/test/e2e/systemd_test.go
+++ b/test/e2e/systemd_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/tag_test.go b/test/e2e/tag_test.go
index 53896d1a2..9f67eaf80 100644
--- a/test/e2e/tag_test.go
+++ b/test/e2e/tag_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/top_test.go b/test/e2e/top_test.go
index cfcf2a959..067358468 100644
--- a/test/e2e/top_test.go
+++ b/test/e2e/top_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/trust_test.go b/test/e2e/trust_test.go
index bbf09eca4..0d36266f6 100644
--- a/test/e2e/trust_test.go
+++ b/test/e2e/trust_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go
index 68a462bdb..8ae2eb9ca 100644
--- a/test/e2e/version_test.go
+++ b/test/e2e/version_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/volume_create_test.go b/test/e2e/volume_create_test.go
index 50ee63f2a..9e525786e 100644
--- a/test/e2e/volume_create_test.go
+++ b/test/e2e/volume_create_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/volume_inspect_test.go b/test/e2e/volume_inspect_test.go
index d0d5a601e..aacdbe8be 100644
--- a/test/e2e/volume_inspect_test.go
+++ b/test/e2e/volume_inspect_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/volume_ls_test.go b/test/e2e/volume_ls_test.go
index 119d29d9b..d2ee558c1 100644
--- a/test/e2e/volume_ls_test.go
+++ b/test/e2e/volume_ls_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/volume_prune_test.go b/test/e2e/volume_prune_test.go
index 8c0a10e77..008acc2a2 100644
--- a/test/e2e/volume_prune_test.go
+++ b/test/e2e/volume_prune_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/volume_rm_test.go b/test/e2e/volume_rm_test.go
index cebb09467..295b290e4 100644
--- a/test/e2e/volume_rm_test.go
+++ b/test/e2e/volume_rm_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/e2e/wait_test.go b/test/e2e/wait_test.go
index a7e9b4c06..08da97aa0 100644
--- a/test/e2e/wait_test.go
+++ b/test/e2e/wait_test.go
@@ -1,3 +1,5 @@
+// +build !remoteclient
+
package integration
import (
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 288c768d4..23dcb95e3 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -33,10 +33,13 @@ type PodmanTestCommon interface {
// PodmanTest struct for command line options
type PodmanTest struct {
- PodmanMakeOptions func(args []string) []string
- PodmanBinary string
- ArtifactPath string
- TempDir string
+ PodmanMakeOptions func(args []string) []string
+ PodmanBinary string
+ ArtifactPath string
+ TempDir string
+ RemoteTest bool
+ RemotePodmanBinary string
+ VarlinkSession *os.Process
}
// PodmanSession wraps the gexec.session so we can extend it
@@ -61,17 +64,20 @@ func (p *PodmanTest) MakeOptions(args []string) []string {
func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, env []string) *PodmanSession {
var command *exec.Cmd
podmanOptions := p.MakeOptions(args)
-
+ podmanBinary := p.PodmanBinary
+ if p.RemoteTest {
+ podmanBinary = p.RemotePodmanBinary
+ }
if env == nil {
- fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
+ fmt.Printf("Running: %s %s\n", podmanBinary, strings.Join(podmanOptions, " "))
} else {
- fmt.Printf("Running: (env: %v) %s %s\n", env, p.PodmanBinary, strings.Join(podmanOptions, " "))
+ fmt.Printf("Running: (env: %v) %s %s\n", env, podmanBinary, strings.Join(podmanOptions, " "))
}
if uid != 0 || gid != 0 {
- nsEnterOpts := append([]string{"--userspec", fmt.Sprintf("%d:%d", uid, gid), "/", p.PodmanBinary}, podmanOptions...)
+ nsEnterOpts := append([]string{"--userspec", fmt.Sprintf("%d:%d", uid, gid), "/", podmanBinary}, podmanOptions...)
command = exec.Command("chroot", nsEnterOpts...)
} else {
- command = exec.Command(p.PodmanBinary, podmanOptions...)
+ command = exec.Command(podmanBinary, podmanOptions...)
}
if env != nil {
command.Env = env
diff --git a/vendor.conf b/vendor.conf
index b6c58165c..9c9d41a0d 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -16,7 +16,7 @@ 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/storage v1.4
+github.com/containers/storage v1.7
github.com/containers/psgo v1.1
github.com/coreos/go-systemd v14
github.com/cri-o/ocicni 2d2983e40c242322a56c22a903785e7f83eb378c
@@ -90,7 +90,7 @@ k8s.io/api kubernetes-1.10.13-beta.0 https://github.com/kubernetes/api
k8s.io/apimachinery kubernetes-1.10.13-beta.0 https://github.com/kubernetes/apimachinery
k8s.io/client-go kubernetes-1.10.13-beta.0 https://github.com/kubernetes/client-go
github.com/mrunalp/fileutils 7d4729fb36185a7c1719923406c9d40e54fb93c7
-github.com/varlink/go e9fdc57f40123518ac513eb3443e50625ad6b434
+github.com/varlink/go 92687ab4eb68d99e43b1f5b93477ad76bb54f811
github.com/containers/buildah e7ca330f923701dba8859f5c014d0a9a3f7f0a49
# TODO: Gotty has not been updated since 2012. Can we find replacement?
github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512
diff --git a/vendor/github.com/containers/storage/containers_ffjson.go b/vendor/github.com/containers/storage/containers_ffjson.go
index aef6becfe..40b912bb3 100644
--- a/vendor/github.com/containers/storage/containers_ffjson.go
+++ b/vendor/github.com/containers/storage/containers_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: containers.go
+// source: ./containers.go
package storage
diff --git a/vendor/github.com/containers/storage/drivers/aufs/aufs.go b/vendor/github.com/containers/storage/drivers/aufs/aufs.go
index ca69816be..e821bc0c5 100644
--- a/vendor/github.com/containers/storage/drivers/aufs/aufs.go
+++ b/vendor/github.com/containers/storage/drivers/aufs/aufs.go
@@ -253,6 +253,11 @@ func (a *Driver) AdditionalImageStores() []string {
return nil
}
+// CreateFromTemplate creates a layer with the same contents and parent as another layer.
+func (a *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error {
+ return graphdriver.NaiveCreateFromTemplate(a, id, template, templateIDMappings, parent, parentIDMappings, opts, readWrite)
+}
+
// CreateReadWrite creates a layer that is writable for use as a container
// file system.
func (a *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
diff --git a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
index 567cda9d3..30254d9fb 100644
--- a/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
+++ b/vendor/github.com/containers/storage/drivers/btrfs/btrfs.go
@@ -490,6 +490,11 @@ func (d *Driver) quotasDirID(id string) string {
return path.Join(d.quotasDir(), id)
}
+// CreateFromTemplate creates a layer with the same contents and parent as another layer.
+func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error {
+ return d.Create(id, template, opts)
+}
+
// CreateReadWrite creates a layer that is writable for use as a container
// file system.
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
diff --git a/vendor/github.com/containers/storage/drivers/devmapper/driver.go b/vendor/github.com/containers/storage/drivers/devmapper/driver.go
index 39a4fbe2c..13677c93a 100644
--- a/vendor/github.com/containers/storage/drivers/devmapper/driver.go
+++ b/vendor/github.com/containers/storage/drivers/devmapper/driver.go
@@ -123,6 +123,11 @@ func (d *Driver) Cleanup() error {
return err
}
+// CreateFromTemplate creates a layer with the same contents and parent as another layer.
+func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error {
+ return d.Create(id, template, opts)
+}
+
// CreateReadWrite creates a layer that is writable for use as a container
// file system.
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
diff --git a/vendor/github.com/containers/storage/drivers/driver.go b/vendor/github.com/containers/storage/drivers/driver.go
index 476b55160..dda172574 100644
--- a/vendor/github.com/containers/storage/drivers/driver.go
+++ b/vendor/github.com/containers/storage/drivers/driver.go
@@ -72,6 +72,9 @@ type ProtoDriver interface {
// specified id and parent and options passed in opts. Parent
// may be "" and opts may be nil.
Create(id, parent string, opts *CreateOpts) error
+ // CreateFromTemplate creates a new filesystem layer with the specified id
+ // and parent, with contents identical to the specified template layer.
+ CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *CreateOpts, readWrite bool) error
// Remove attempts to remove the filesystem layer with this id.
Remove(id string) error
// Get returns the mountpoint for the layered filesystem referred
diff --git a/vendor/github.com/containers/storage/drivers/overlay/check.go b/vendor/github.com/containers/storage/drivers/overlay/check.go
index 590d517fa..a566e4afd 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/check.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/check.go
@@ -10,6 +10,8 @@ import (
"path/filepath"
"syscall"
+ "github.com/containers/storage/pkg/ioutils"
+ "github.com/containers/storage/pkg/mount"
"github.com/containers/storage/pkg/system"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -57,10 +59,11 @@ func doesSupportNativeDiff(d, mountOpts string) error {
}
opts := fmt.Sprintf("lowerdir=%s:%s,upperdir=%s,workdir=%s", path.Join(td, "l2"), path.Join(td, "l1"), path.Join(td, "l3"), path.Join(td, "work"))
- if mountOpts != "" {
- opts = fmt.Sprintf("%s,%s", opts, mountOpts)
+ flags, data := mount.ParseOptions(mountOpts)
+ if data != "" {
+ opts = fmt.Sprintf("%s,%s", opts, data)
}
- if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", 0, opts); err != nil {
+ if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", uintptr(flags), opts); err != nil {
return errors.Wrap(err, "failed to mount overlay")
}
defer func() {
@@ -103,3 +106,60 @@ func doesSupportNativeDiff(d, mountOpts string) error {
return nil
}
+
+// doesMetacopy checks if the filesystem is going to optimize changes to
+// metadata by using nodes marked with an "overlay.metacopy" attribute to avoid
+// copying up a file from a lower layer unless/until its contents are being
+// modified
+func doesMetacopy(d, mountOpts string) (bool, error) {
+ td, err := ioutil.TempDir(d, "metacopy-check")
+ if err != nil {
+ return false, err
+ }
+ defer func() {
+ if err := os.RemoveAll(td); err != nil {
+ logrus.Warnf("Failed to remove check directory %v: %v", td, err)
+ }
+ }()
+
+ // Make directories l1, l2, work, merged
+ if err := os.MkdirAll(filepath.Join(td, "l1"), 0755); err != nil {
+ return false, err
+ }
+ if err := ioutils.AtomicWriteFile(filepath.Join(td, "l1", "f"), []byte{0xff}, 0700); err != nil {
+ return false, err
+ }
+ if err := os.MkdirAll(filepath.Join(td, "l2"), 0755); err != nil {
+ return false, err
+ }
+ if err := os.Mkdir(filepath.Join(td, "work"), 0755); err != nil {
+ return false, err
+ }
+ if err := os.Mkdir(filepath.Join(td, "merged"), 0755); err != nil {
+ return false, err
+ }
+ // Mount using the mandatory options and configured options
+ opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", path.Join(td, "l1"), path.Join(td, "l2"), path.Join(td, "work"))
+ flags, data := mount.ParseOptions(mountOpts)
+ if data != "" {
+ opts = fmt.Sprintf("%s,%s", opts, data)
+ }
+ if err := unix.Mount("overlay", filepath.Join(td, "merged"), "overlay", uintptr(flags), opts); err != nil {
+ return false, errors.Wrap(err, "failed to mount overlay for metacopy check")
+ }
+ defer func() {
+ if err := unix.Unmount(filepath.Join(td, "merged"), 0); err != nil {
+ logrus.Warnf("Failed to unmount check directory %v: %v", filepath.Join(td, "merged"), err)
+ }
+ }()
+ // Make a change that only impacts the inode, and check if the pulled-up copy is marked
+ // as a metadata-only copy
+ if err := os.Chmod(filepath.Join(td, "merged", "f"), 0600); err != nil {
+ return false, errors.Wrap(err, "error changing permissions on file for metacopy check")
+ }
+ metacopy, err := system.Lgetxattr(filepath.Join(td, "l2", "f"), "trusted.overlay.metacopy")
+ if err != nil {
+ return false, errors.Wrap(err, "metacopy flag was not set on file in upper layer")
+ }
+ return metacopy != nil, nil
+}
diff --git a/vendor/github.com/containers/storage/drivers/overlay/overlay.go b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
index 2455b6736..3e8daf23c 100644
--- a/vendor/github.com/containers/storage/drivers/overlay/overlay.go
+++ b/vendor/github.com/containers/storage/drivers/overlay/overlay.go
@@ -85,13 +85,12 @@ const (
)
type overlayOptions struct {
- overrideKernelCheck bool
- imageStores []string
- quota quota.Quota
- mountProgram string
- ostreeRepo string
- skipMountHome bool
- mountOptions string
+ imageStores []string
+ quota quota.Quota
+ mountProgram string
+ ostreeRepo string
+ skipMountHome bool
+ mountOptions string
}
// Driver contains information about the home directory and the list of active mounts that are created using this driver.
@@ -105,6 +104,7 @@ type Driver struct {
options overlayOptions
naiveDiff graphdriver.DiffDriver
supportsDType bool
+ usingMetacopy bool
locker *locker.Locker
convert map[string]bool
}
@@ -174,6 +174,18 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
}
}
+ usingMetacopy, err := doesMetacopy(home, opts.mountOptions)
+ if err == nil {
+ if usingMetacopy {
+ logrus.Debugf("overlay test mount indicated that metacopy is being used")
+ } else {
+ logrus.Debugf("overlay test mount indicated that metacopy is not being used")
+ }
+ } else {
+ logrus.Warnf("overlay test mount did not indicate whether or not metacopy is being used: %v", err)
+ return nil, err
+ }
+
if !opts.skipMountHome {
if err := mount.MakePrivate(home); err != nil {
return nil, err
@@ -193,6 +205,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
gidMaps: gidMaps,
ctr: graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicOverlay)),
supportsDType: supportsDType,
+ usingMetacopy: usingMetacopy,
locker: locker.New(),
options: *opts,
convert: make(map[string]bool),
@@ -212,7 +225,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, fmt.Errorf("Storage option overlay.size only supported for backingFS XFS. Found %v", backingFs)
}
- logrus.Debugf("backingFs=%s, projectQuotaSupported=%v, useNativeDiff=%v", backingFs, projectQuotaSupported, !d.useNaiveDiff())
+ logrus.Debugf("backingFs=%s, projectQuotaSupported=%v, useNativeDiff=%v, usingMetacopy=%v", backingFs, projectQuotaSupported, !d.useNaiveDiff(), d.usingMetacopy)
return d, nil
}
@@ -226,12 +239,6 @@ func parseOptions(options []string) (*overlayOptions, error) {
}
key = strings.ToLower(key)
switch key {
- case ".override_kernel_check", "overlay.override_kernel_check", "overlay2.override_kernel_check":
- logrus.Debugf("overlay: override_kernelcheck=%s", val)
- o.overrideKernelCheck, err = strconv.ParseBool(val)
- if err != nil {
- return nil, err
- }
case ".mountopt", "overlay.mountopt", "overlay2.mountopt":
o.mountOptions = val
case ".size", "overlay.size", "overlay2.size":
@@ -375,6 +382,7 @@ func (d *Driver) Status() [][2]string {
{"Backing Filesystem", backingFs},
{"Supports d_type", strconv.FormatBool(d.supportsDType)},
{"Native Overlay Diff", strconv.FormatBool(!d.useNaiveDiff())},
+ {"Using metacopy", strconv.FormatBool(d.usingMetacopy)},
}
}
@@ -410,6 +418,14 @@ func (d *Driver) Cleanup() error {
return mount.Unmount(d.home)
}
+// CreateFromTemplate creates a layer with the same contents and parent as another layer.
+func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error {
+ if readWrite {
+ return d.CreateReadWrite(id, template, opts)
+ }
+ return d.Create(id, template, opts)
+}
+
// CreateReadWrite creates a layer that is writable for use as a container
// file system.
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
@@ -793,6 +809,7 @@ func (d *Driver) get(id string, disableShifting bool, options graphdriver.MountO
mountTarget = path.Join(id, "merged")
}
flags, data := mount.ParseOptions(mountData)
+ logrus.Debugf("overlay: mount_data=%s", mountData)
if err := mountFunc("overlay", mountTarget, "overlay", uintptr(flags), data); err != nil {
return "", fmt.Errorf("error creating overlay mount to %s: %v", mountTarget, err)
}
@@ -986,6 +1003,7 @@ func (d *Driver) UpdateLayerIDMap(id string, toContainer, toHost *idtools.IDMapp
// Mount the new layer and handle ownership changes and possible copy_ups in it.
options := graphdriver.MountOpts{
MountLabel: mountLabel,
+ Options: strings.Split(d.options.mountOptions, ","),
}
layerFs, err := d.get(id, true, options)
if err != nil {
diff --git a/vendor/github.com/containers/storage/drivers/template.go b/vendor/github.com/containers/storage/drivers/template.go
new file mode 100644
index 000000000..dfcbffb83
--- /dev/null
+++ b/vendor/github.com/containers/storage/drivers/template.go
@@ -0,0 +1,45 @@
+package graphdriver
+
+import (
+ "github.com/sirupsen/logrus"
+
+ "github.com/containers/storage/pkg/idtools"
+)
+
+// TemplateDriver is just barely enough of a driver that we can implement a
+// naive version of CreateFromTemplate on top of it.
+type TemplateDriver interface {
+ DiffDriver
+ CreateReadWrite(id, parent string, opts *CreateOpts) error
+ Create(id, parent string, opts *CreateOpts) error
+ Remove(id string) error
+}
+
+// CreateFromTemplate creates a layer with the same contents and parent as
+// another layer. Internally, it may even depend on that other layer
+// continuing to exist, as if it were actually a child of the child layer.
+func NaiveCreateFromTemplate(d TemplateDriver, id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *CreateOpts, readWrite bool) error {
+ var err error
+ if readWrite {
+ err = d.CreateReadWrite(id, parent, opts)
+ } else {
+ err = d.Create(id, parent, opts)
+ }
+ if err != nil {
+ return err
+ }
+ diff, err := d.Diff(template, templateIDMappings, parent, parentIDMappings, opts.MountLabel)
+ if err != nil {
+ if err2 := d.Remove(id); err2 != nil {
+ logrus.Errorf("error removing layer %q: %v", id, err2)
+ }
+ return err
+ }
+ if _, err = d.ApplyDiff(id, templateIDMappings, parent, opts.MountLabel, diff); err != nil {
+ if err2 := d.Remove(id); err2 != nil {
+ logrus.Errorf("error removing layer %q: %v", id, err2)
+ }
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/containers/storage/drivers/vfs/driver.go b/vendor/github.com/containers/storage/drivers/vfs/driver.go
index f7f3c75ba..5941ccc17 100644
--- a/vendor/github.com/containers/storage/drivers/vfs/driver.go
+++ b/vendor/github.com/containers/storage/drivers/vfs/driver.go
@@ -99,6 +99,14 @@ func (d *Driver) Cleanup() error {
return nil
}
+// CreateFromTemplate creates a layer with the same contents and parent as another layer.
+func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error {
+ if readWrite {
+ return d.CreateReadWrite(id, template, opts)
+ }
+ return d.Create(id, template, opts)
+}
+
// CreateReadWrite creates a layer that is writable for use as a container
// file system.
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
diff --git a/vendor/github.com/containers/storage/drivers/windows/windows.go b/vendor/github.com/containers/storage/drivers/windows/windows.go
index c6d86a4ab..c7df1c1fe 100644
--- a/vendor/github.com/containers/storage/drivers/windows/windows.go
+++ b/vendor/github.com/containers/storage/drivers/windows/windows.go
@@ -185,6 +185,11 @@ func (d *Driver) Exists(id string) bool {
return result
}
+// CreateFromTemplate creates a layer with the same contents and parent as another layer.
+func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error {
+ return graphdriver.NaiveCreateFromTemplate(d, id, template, templateIDMappings, parent, parentIDMappings, opts, readWrite)
+}
+
// CreateReadWrite creates a layer that is writable for use as a container
// file system.
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs.go b/vendor/github.com/containers/storage/drivers/zfs/zfs.go
index c3ce6e869..eaa9e8bc5 100644
--- a/vendor/github.com/containers/storage/drivers/zfs/zfs.go
+++ b/vendor/github.com/containers/storage/drivers/zfs/zfs.go
@@ -1,4 +1,4 @@
-// +build linux freebsd solaris
+// +build linux freebsd
package zfs
@@ -16,7 +16,7 @@ import (
"github.com/containers/storage/pkg/idtools"
"github.com/containers/storage/pkg/mount"
"github.com/containers/storage/pkg/parsers"
- zfs "github.com/mistifyio/go-zfs"
+ "github.com/mistifyio/go-zfs"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -38,7 +38,7 @@ type Logger struct{}
// Log wraps log message from ZFS driver with a prefix '[zfs]'.
func (*Logger) Log(cmd []string) {
- logrus.Debugf("[zfs] %s", strings.Join(cmd, " "))
+ logrus.WithField("storage-driver", "zfs").Debugf("%s", strings.Join(cmd, " "))
}
// Init returns a new ZFS driver.
@@ -47,14 +47,16 @@ func (*Logger) Log(cmd []string) {
func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) {
var err error
+ logger := logrus.WithField("storage-driver", "zfs")
+
if _, err := exec.LookPath("zfs"); err != nil {
- logrus.Debugf("[zfs] zfs command is not available: %v", err)
+ logger.Debugf("zfs command is not available: %v", err)
return nil, errors.Wrap(graphdriver.ErrPrerequisites, "the 'zfs' command is not available")
}
file, err := os.OpenFile("/dev/zfs", os.O_RDWR, 0600)
if err != nil {
- logrus.Debugf("[zfs] cannot open /dev/zfs: %v", err)
+ logger.Debugf("cannot open /dev/zfs: %v", err)
return nil, errors.Wrapf(graphdriver.ErrPrerequisites, "could not open /dev/zfs: %v", err)
}
defer file.Close()
@@ -109,9 +111,6 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri
return nil, fmt.Errorf("Failed to create '%s': %v", base, err)
}
- if err := mount.MakePrivate(base); err != nil {
- return nil, err
- }
d := &Driver{
dataset: rootDataset,
options: options,
@@ -157,7 +156,7 @@ func lookupZfsDataset(rootdir string) (string, error) {
}
for _, m := range mounts {
if err := unix.Stat(m.Mountpoint, &stat); err != nil {
- logrus.Debugf("[zfs] failed to stat '%s' while scanning for zfs mount: %v", m.Mountpoint, err)
+ logrus.WithField("storage-driver", "zfs").Debugf("failed to stat '%s' while scanning for zfs mount: %v", m.Mountpoint, err)
continue // may fail on fuse file systems
}
@@ -184,7 +183,7 @@ func (d *Driver) String() string {
return "zfs"
}
-// Cleanup is used to implement graphdriver.ProtoDriver. There is no cleanup required for this driver.
+// Cleanup is called on when program exits, it is a no-op for ZFS.
func (d *Driver) Cleanup() error {
return nil
}
@@ -260,6 +259,11 @@ func (d *Driver) mountPath(id string) string {
return path.Join(d.options.mountPath, "graph", getMountpoint(id))
}
+// CreateFromTemplate creates a layer with the same contents and parent as another layer.
+func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error {
+ return d.Create(id, template, opts)
+}
+
// CreateReadWrite creates a layer that is writable for use as a container
// file system.
func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
@@ -360,11 +364,25 @@ func (d *Driver) Remove(id string) error {
}
// Get returns the mountpoint for the given id after creating the target directories if necessary.
-func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
+func (d *Driver) Get(id string, options graphdriver.MountOpts) (_ string, retErr error) {
+
mountpoint := d.mountPath(id)
if count := d.ctr.Increment(mountpoint); count > 1 {
return mountpoint, nil
}
+ defer func() {
+ if retErr != nil {
+ if c := d.ctr.Decrement(mountpoint); c <= 0 {
+ if mntErr := unix.Unmount(mountpoint, 0); mntErr != nil {
+ logrus.WithField("storage-driver", "zfs").Errorf("Error unmounting %v: %v", mountpoint, mntErr)
+ }
+ if rmErr := unix.Rmdir(mountpoint); rmErr != nil && !os.IsNotExist(rmErr) {
+ logrus.WithField("storage-driver", "zfs").Debugf("Failed to remove %s: %v", id, rmErr)
+ }
+
+ }
+ }
+ }()
mountOptions := d.options.mountOptions
if len(options.Options) > 0 {
@@ -373,29 +391,24 @@ func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) {
filesystem := d.zfsPath(id)
opts := label.FormatMountLabel(mountOptions, options.MountLabel)
- logrus.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, opts)
+ logrus.WithField("storage-driver", "zfs").Debugf(`mount("%s", "%s", "%s")`, filesystem, mountpoint, opts)
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
if err != nil {
- d.ctr.Decrement(mountpoint)
return "", err
}
// Create the target directories if they don't exist
if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil {
- d.ctr.Decrement(mountpoint)
return "", err
}
if err := mount.Mount(filesystem, mountpoint, "zfs", opts); err != nil {
- d.ctr.Decrement(mountpoint)
- return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err)
+ return "", errors.Wrap(err, "error creating zfs mount")
}
// this could be our first mount after creation of the filesystem, and the root dir may still have root
// permissions instead of the remapped root uid:gid (if user namespaces are enabled):
if err := os.Chown(mountpoint, rootUID, rootGID); err != nil {
- mount.Unmount(mountpoint)
- d.ctr.Decrement(mountpoint)
return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
}
@@ -408,16 +421,18 @@ func (d *Driver) Put(id string) error {
if count := d.ctr.Decrement(mountpoint); count > 0 {
return nil
}
- mounted, err := graphdriver.Mounted(graphdriver.FsMagicZfs, mountpoint)
- if err != nil || !mounted {
- return err
- }
- logrus.Debugf(`[zfs] unmount("%s")`, mountpoint)
+ logger := logrus.WithField("storage-driver", "zfs")
- if err := mount.Unmount(mountpoint); err != nil {
- return fmt.Errorf("error unmounting to %s: %v", mountpoint, err)
+ logger.Debugf(`unmount("%s")`, mountpoint)
+
+ if err := unix.Unmount(mountpoint, unix.MNT_DETACH); err != nil {
+ logger.Warnf("Failed to unmount %s mount %s: %v", id, mountpoint, err)
+ }
+ if err := unix.Rmdir(mountpoint); err != nil && !os.IsNotExist(err) {
+ logger.Debugf("Failed to remove %s mount point %s: %v", id, mountpoint, err)
}
+
return nil
}
diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go b/vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go
index 69c0448d3..bf6905159 100644
--- a/vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go
+++ b/vendor/github.com/containers/storage/drivers/zfs/zfs_freebsd.go
@@ -18,7 +18,7 @@ func checkRootdirFs(rootdir string) error {
// on FreeBSD buf.Fstypename contains ['z', 'f', 's', 0 ... ]
if (buf.Fstypename[0] != 122) || (buf.Fstypename[1] != 102) || (buf.Fstypename[2] != 115) || (buf.Fstypename[3] != 0) {
- logrus.Debugf("[zfs] no zfs dataset found for rootdir '%s'", rootdir)
+ logrus.WithField("storage-driver", "zfs").Debugf("no zfs dataset found for rootdir '%s'", rootdir)
return errors.Wrapf(graphdriver.ErrPrerequisites, "no zfs dataset found for rootdir '%s'", rootdir)
}
diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go b/vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go
index da298047d..fb1ef3a3d 100644
--- a/vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go
+++ b/vendor/github.com/containers/storage/drivers/zfs/zfs_linux.go
@@ -1,23 +1,24 @@
package zfs
import (
- "fmt"
-
"github.com/containers/storage/drivers"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
- "golang.org/x/sys/unix"
)
-func checkRootdirFs(rootdir string) error {
- var buf unix.Statfs_t
- if err := unix.Statfs(rootdir, &buf); err != nil {
- return fmt.Errorf("Failed to access '%s': %s", rootdir, err)
+func checkRootdirFs(rootDir string) error {
+ fsMagic, err := graphdriver.GetFSMagic(rootDir)
+ if err != nil {
+ return err
+ }
+ backingFS := "unknown"
+ if fsName, ok := graphdriver.FsNames[fsMagic]; ok {
+ backingFS = fsName
}
- if graphdriver.FsMagic(buf.Type) != graphdriver.FsMagicZfs {
- logrus.Debugf("[zfs] no zfs dataset found for rootdir '%s'", rootdir)
- return errors.Wrapf(graphdriver.ErrPrerequisites, "no zfs dataset found for rootdir '%s'", rootdir)
+ if fsMagic != graphdriver.FsMagicZfs {
+ logrus.WithField("root", rootDir).WithField("backingFS", backingFS).WithField("storage-driver", "zfs").Error("No zfs dataset found for root")
+ return errors.Wrapf(graphdriver.ErrPrerequisites, "no zfs dataset found for rootdir '%s'", rootDir)
}
return nil
diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs_solaris.go b/vendor/github.com/containers/storage/drivers/zfs/zfs_solaris.go
deleted file mode 100644
index 2383bf3bf..000000000
--- a/vendor/github.com/containers/storage/drivers/zfs/zfs_solaris.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// +build solaris,cgo
-
-package zfs
-
-/*
-#include <sys/statvfs.h>
-#include <stdlib.h>
-
-static inline struct statvfs *getstatfs(char *s) {
- struct statvfs *buf;
- int err;
- buf = (struct statvfs *)malloc(sizeof(struct statvfs));
- err = statvfs(s, buf);
- return buf;
-}
-*/
-import "C"
-import (
- "path/filepath"
- "strings"
- "unsafe"
-
- "github.com/containers/storage/drivers"
- "github.com/pkg/errors"
- "github.com/sirupsen/logrus"
-)
-
-func checkRootdirFs(rootdir string) error {
-
- cs := C.CString(filepath.Dir(rootdir))
- defer C.free(unsafe.Pointer(cs))
- buf := C.getstatfs(cs)
- defer C.free(unsafe.Pointer(buf))
-
- // on Solaris buf.f_basetype contains ['z', 'f', 's', 0 ... ]
- if (buf.f_basetype[0] != 122) || (buf.f_basetype[1] != 102) || (buf.f_basetype[2] != 115) ||
- (buf.f_basetype[3] != 0) {
- logrus.Debugf("[zfs] no zfs dataset found for rootdir '%s'", rootdir)
- return errors.Wrapf(graphdriver.ErrPrerequisites, "no zfs dataset found for rootdir '%s'", rootdir)
- }
-
- return nil
-}
-
-/* rootfs is introduced to comply with the OCI spec
-which states that root filesystem must be mounted at <CID>/rootfs/ instead of <CID>/
-*/
-func getMountpoint(id string) string {
- maxlen := 12
-
- // we need to preserve filesystem suffix
- suffix := strings.SplitN(id, "-", 2)
-
- if len(suffix) > 1 {
- return filepath.Join(id[:maxlen]+"-"+suffix[1], "rootfs", "root")
- }
-
- return filepath.Join(id[:maxlen], "rootfs", "root")
-}
diff --git a/vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go b/vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go
index ce8daadaf..643b169bc 100644
--- a/vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go
+++ b/vendor/github.com/containers/storage/drivers/zfs/zfs_unsupported.go
@@ -1,4 +1,4 @@
-// +build !linux,!freebsd,!solaris
+// +build !linux,!freebsd
package zfs
diff --git a/vendor/github.com/containers/storage/images.go b/vendor/github.com/containers/storage/images.go
index b10501b08..d99842534 100644
--- a/vendor/github.com/containers/storage/images.go
+++ b/vendor/github.com/containers/storage/images.go
@@ -42,7 +42,9 @@ type Image struct {
// MappedTopLayers are the IDs of alternate versions of the top layer
// which have the same contents and parent, and which differ from
- // TopLayer only in which ID mappings they use.
+ // TopLayer only in which ID mappings they use. When the image is
+ // to be removed, they should be removed before the TopLayer, as the
+ // graph driver may depend on that.
MappedTopLayers []string `json:"mapped-layers,omitempty"`
// Metadata is data we keep for the convenience of the caller. It is not
diff --git a/vendor/github.com/containers/storage/images_ffjson.go b/vendor/github.com/containers/storage/images_ffjson.go
index 6b40ebd59..539acfe93 100644
--- a/vendor/github.com/containers/storage/images_ffjson.go
+++ b/vendor/github.com/containers/storage/images_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: images.go
+// source: ./images.go
package storage
diff --git a/vendor/github.com/containers/storage/layers.go b/vendor/github.com/containers/storage/layers.go
index 299d2f818..cdc3cbba9 100644
--- a/vendor/github.com/containers/storage/layers.go
+++ b/vendor/github.com/containers/storage/layers.go
@@ -551,9 +551,20 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab
}
}
parent := ""
- var parentMappings *idtools.IDMappings
if parentLayer != nil {
parent = parentLayer.ID
+ }
+ var parentMappings, templateIDMappings, oldMappings *idtools.IDMappings
+ if moreOptions.TemplateLayer != "" {
+ templateLayer, ok := r.lookup(moreOptions.TemplateLayer)
+ if !ok {
+ return nil, -1, ErrLayerUnknown
+ }
+ templateIDMappings = idtools.NewIDMappingsFromMaps(templateLayer.UIDMap, templateLayer.GIDMap)
+ } else {
+ templateIDMappings = &idtools.IDMappings{}
+ }
+ if parentLayer != nil {
parentMappings = idtools.NewIDMappingsFromMaps(parentLayer.UIDMap, parentLayer.GIDMap)
} else {
parentMappings = &idtools.IDMappings{}
@@ -566,23 +577,34 @@ func (r *layerStore) Put(id string, parentLayer *Layer, names []string, mountLab
MountLabel: mountLabel,
StorageOpt: options,
}
- if writeable {
- if err = r.driver.CreateReadWrite(id, parent, &opts); err != nil {
+ if moreOptions.TemplateLayer != "" {
+ if err = r.driver.CreateFromTemplate(id, moreOptions.TemplateLayer, templateIDMappings, parent, parentMappings, &opts, writeable); err != nil {
if id != "" {
- return nil, -1, errors.Wrapf(err, "error creating read-write layer with ID %q", id)
+ return nil, -1, errors.Wrapf(err, "error creating copy of template layer %q with ID %q", moreOptions.TemplateLayer, id)
}
- return nil, -1, errors.Wrapf(err, "error creating read-write layer")
+ return nil, -1, errors.Wrapf(err, "error creating copy of template layer %q", moreOptions.TemplateLayer)
}
+ oldMappings = templateIDMappings
} else {
- if err = r.driver.Create(id, parent, &opts); err != nil {
- if id != "" {
- return nil, -1, errors.Wrapf(err, "error creating layer with ID %q", id)
+ if writeable {
+ if err = r.driver.CreateReadWrite(id, parent, &opts); err != nil {
+ if id != "" {
+ return nil, -1, errors.Wrapf(err, "error creating read-write layer with ID %q", id)
+ }
+ return nil, -1, errors.Wrapf(err, "error creating read-write layer")
+ }
+ } else {
+ if err = r.driver.Create(id, parent, &opts); err != nil {
+ if id != "" {
+ return nil, -1, errors.Wrapf(err, "error creating layer with ID %q", id)
+ }
+ return nil, -1, errors.Wrapf(err, "error creating layer")
}
- return nil, -1, errors.Wrapf(err, "error creating layer")
}
+ oldMappings = parentMappings
}
- if !reflect.DeepEqual(parentMappings.UIDs(), idMappings.UIDs()) || !reflect.DeepEqual(parentMappings.GIDs(), idMappings.GIDs()) {
- if err = r.driver.UpdateLayerIDMap(id, parentMappings, idMappings, mountLabel); err != nil {
+ if !reflect.DeepEqual(oldMappings.UIDs(), idMappings.UIDs()) || !reflect.DeepEqual(oldMappings.GIDs(), idMappings.GIDs()) {
+ if err = r.driver.UpdateLayerIDMap(id, oldMappings, idMappings, mountLabel); err != nil {
// We don't have a record of this layer, but at least
// try to clean it up underneath us.
r.driver.Remove(id)
diff --git a/vendor/github.com/containers/storage/layers_ffjson.go b/vendor/github.com/containers/storage/layers_ffjson.go
index 125b5d8c9..09b5d0f33 100644
--- a/vendor/github.com/containers/storage/layers_ffjson.go
+++ b/vendor/github.com/containers/storage/layers_ffjson.go
@@ -1,5 +1,5 @@
// Code generated by ffjson <https://github.com/pquerna/ffjson>. DO NOT EDIT.
-// source: layers.go
+// source: ./layers.go
package storage
diff --git a/vendor/github.com/containers/storage/pkg/archive/example_changes.go b/vendor/github.com/containers/storage/pkg/archive/example_changes.go
new file mode 100644
index 000000000..70f9c5564
--- /dev/null
+++ b/vendor/github.com/containers/storage/pkg/archive/example_changes.go
@@ -0,0 +1,97 @@
+// +build ignore
+
+// Simple tool to create an archive stream from an old and new directory
+//
+// By default it will stream the comparison of two temporary directories with junk files
+package main
+
+import (
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+
+ "github.com/containers/storage/pkg/archive"
+ "github.com/sirupsen/logrus"
+)
+
+var (
+ flDebug = flag.Bool("D", false, "debugging output")
+ flNewDir = flag.String("newdir", "", "")
+ flOldDir = flag.String("olddir", "", "")
+ log = logrus.New()
+)
+
+func main() {
+ flag.Usage = func() {
+ fmt.Println("Produce a tar from comparing two directory paths. By default a demo tar is created of around 200 files (including hardlinks)")
+ fmt.Printf("%s [OPTIONS]\n", os.Args[0])
+ flag.PrintDefaults()
+ }
+ flag.Parse()
+ log.Out = os.Stderr
+ if (len(os.Getenv("DEBUG")) > 0) || *flDebug {
+ logrus.SetLevel(logrus.DebugLevel)
+ }
+ var newDir, oldDir string
+
+ if len(*flNewDir) == 0 {
+ var err error
+ newDir, err = ioutil.TempDir("", "storage-test-newDir")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(newDir)
+ if _, err := prepareUntarSourceDirectory(100, newDir, true); err != nil {
+ log.Fatal(err)
+ }
+ } else {
+ newDir = *flNewDir
+ }
+
+ if len(*flOldDir) == 0 {
+ oldDir, err := ioutil.TempDir("", "storage-test-oldDir")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(oldDir)
+ } else {
+ oldDir = *flOldDir
+ }
+
+ changes, err := archive.ChangesDirs(newDir, oldDir)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ a, err := archive.ExportChanges(newDir, changes)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer a.Close()
+
+ i, err := io.Copy(os.Stdout, a)
+ if err != nil && err != io.EOF {
+ log.Fatal(err)
+ }
+ fmt.Fprintf(os.Stderr, "wrote archive of %d bytes", i)
+}
+
+func prepareUntarSourceDirectory(numberOfFiles int, targetPath string, makeLinks bool) (int, error) {
+ fileData := []byte("fooo")
+ for n := 0; n < numberOfFiles; n++ {
+ fileName := fmt.Sprintf("file-%d", n)
+ if err := ioutil.WriteFile(path.Join(targetPath, fileName), fileData, 0700); err != nil {
+ return 0, err
+ }
+ if makeLinks {
+ if err := os.Link(path.Join(targetPath, fileName), path.Join(targetPath, fileName+"-link")); err != nil {
+ return 0, err
+ }
+ }
+ }
+ totalSize := numberOfFiles * len(fileData)
+ return totalSize, nil
+}
diff --git a/vendor/github.com/containers/storage/store.go b/vendor/github.com/containers/storage/store.go
index 5877c3b06..3fe305cc1 100644
--- a/vendor/github.com/containers/storage/store.go
+++ b/vendor/github.com/containers/storage/store.go
@@ -482,6 +482,10 @@ type LayerOptions struct {
// inherit settings from its parent layer or, if it has no parent
// layer, the Store object.
IDMappingOptions
+ // TemplateLayer is the ID of a layer whose contents will be used to
+ // initialize this layer. If set, it should be a child of the layer
+ // which we want to use as the parent of the new layer.
+ TemplateLayer string
}
// ImageOptions is used for passing options to a Store's CreateImage() method.
@@ -973,7 +977,7 @@ func (s *store) CreateImage(id string, names []string, layer, metadata string, o
return ristore.Create(id, names, layer, metadata, creationDate, options.Digest)
}
-func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, readWrite bool, rlstore LayerStore, lstores []ROLayerStore, options IDMappingOptions) (*Layer, error) {
+func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, createMappedLayer bool, rlstore LayerStore, lstores []ROLayerStore, options IDMappingOptions) (*Layer, error) {
layerMatchesMappingOptions := func(layer *Layer, options IDMappingOptions) bool {
// If the driver supports shifting and the layer has no mappings, we can use it.
if s.graphDriver.SupportsShifting() && len(layer.UIDMap) == 0 && len(layer.GIDMap) == 0 {
@@ -994,7 +998,6 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, read
return reflect.DeepEqual(layer.UIDMap, options.UIDMap) && reflect.DeepEqual(layer.GIDMap, options.GIDMap)
}
var layer, parentLayer *Layer
- var layerHomeStore ROLayerStore
// Locate the image's top layer and its parent, if it has one.
for _, store := range append([]ROLayerStore{rlstore}, lstores...) {
if store != rlstore {
@@ -1027,7 +1030,6 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, read
if layer == nil {
layer = cLayer
parentLayer = cParentLayer
- layerHomeStore = store
}
}
}
@@ -1037,27 +1039,25 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, read
}
// The top layer's mappings don't match the ones we want, but it's in a read-only
// image store, so we can't create and add a mapped copy of the layer to the image.
- if !readWrite {
+ // We'll have to do the mapping for the container itself, elsewhere.
+ if !createMappedLayer {
return layer, nil
}
// The top layer's mappings don't match the ones we want, and it's in an image store
// that lets us edit image metadata...
if istore, ok := ristore.(*imageStore); ok {
- // ... so extract the layer's contents, create a new copy of it with the
- // desired mappings, and register it as an alternate top layer in the image.
- noCompression := archive.Uncompressed
- diffOptions := DiffOptions{
- Compression: &noCompression,
- }
- rc, err := layerHomeStore.Diff("", layer.ID, &diffOptions)
- if err != nil {
- return nil, errors.Wrapf(err, "error reading layer %q to create an ID-mapped version of it", layer.ID)
- }
- defer rc.Close()
-
+ // ... so create a duplicate of the layer with the desired mappings, and
+ // register it as an alternate top layer in the image.
var layerOptions LayerOptions
if s.graphDriver.SupportsShifting() {
- layerOptions = LayerOptions{IDMappingOptions: IDMappingOptions{HostUIDMapping: true, HostGIDMapping: true, UIDMap: nil, GIDMap: nil}}
+ layerOptions = LayerOptions{
+ IDMappingOptions: IDMappingOptions{
+ HostUIDMapping: true,
+ HostGIDMapping: true,
+ UIDMap: nil,
+ GIDMap: nil,
+ },
+ }
} else {
layerOptions = LayerOptions{
IDMappingOptions: IDMappingOptions{
@@ -1068,9 +1068,10 @@ func (s *store) imageTopLayerForMapping(image *Image, ristore ROImageStore, read
},
}
}
- mappedLayer, _, err := rlstore.Put("", parentLayer, nil, layer.MountLabel, nil, &layerOptions, false, nil, rc)
+ layerOptions.TemplateLayer = layer.ID
+ mappedLayer, _, err := rlstore.Put("", parentLayer, nil, layer.MountLabel, nil, &layerOptions, false, nil, nil)
if err != nil {
- return nil, errors.Wrapf(err, "error creating ID-mapped copy of layer %q", layer.ID)
+ return nil, errors.Wrapf(err, "error creating an ID-mapped copy of layer %q", layer.ID)
}
if err = istore.addMappedTopLayer(image.ID, mappedLayer.ID); err != nil {
if err2 := rlstore.Delete(mappedLayer.ID); err2 != nil {
@@ -1144,7 +1145,9 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
}
imageID = cimage.ID
- ilayer, err := s.imageTopLayerForMapping(cimage, imageHomeStore, imageHomeStore == istore, rlstore, lstores, idMappingsOptions)
+ createMappedLayer := imageHomeStore == istore
+
+ ilayer, err := s.imageTopLayerForMapping(cimage, imageHomeStore, createMappedLayer, rlstore, lstores, idMappingsOptions)
if err != nil {
return nil, err
}
@@ -1170,7 +1173,14 @@ func (s *store) CreateContainer(id string, names []string, image, layer, metadat
}
var layerOptions *LayerOptions
if s.graphDriver.SupportsShifting() {
- layerOptions = &LayerOptions{IDMappingOptions: IDMappingOptions{HostUIDMapping: true, HostGIDMapping: true, UIDMap: nil, GIDMap: nil}}
+ layerOptions = &LayerOptions{
+ IDMappingOptions: IDMappingOptions{
+ HostUIDMapping: true,
+ HostGIDMapping: true,
+ UIDMap: nil,
+ GIDMap: nil,
+ },
+ }
} else {
layerOptions = &LayerOptions{
IDMappingOptions: IDMappingOptions{
@@ -2091,10 +2101,10 @@ func (s *store) DeleteImage(id string, commit bool) (layers []string, err error)
break
}
lastRemoved = layer
- layersToRemove = append(layersToRemove, lastRemoved)
if layer == image.TopLayer {
layersToRemove = append(layersToRemove, image.MappedTopLayers...)
}
+ layersToRemove = append(layersToRemove, lastRemoved)
layer = parent
}
} else {
@@ -3064,9 +3074,6 @@ type OptionsConfig struct {
// Size
Size string `toml:"size"`
- // OverrideKernelCheck
- OverrideKernelCheck string `toml:"override_kernel_check"`
-
// RemapUIDs is a list of default UID mappings to use for layers.
RemapUIDs string `toml:"remap-uids"`
// RemapGIDs is a list of default GID mappings to use for layers.
@@ -3191,9 +3198,6 @@ func ReloadConfigurationFile(configFile string, storeOptions *StoreOptions) {
if config.Storage.Options.MountOpt != "" {
storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.mountopt=%s", config.Storage.Driver, config.Storage.Options.MountOpt))
}
- if config.Storage.Options.OverrideKernelCheck != "" {
- storeOptions.GraphDriverOptions = append(storeOptions.GraphDriverOptions, fmt.Sprintf("%s.override_kernel_check=%s", config.Storage.Driver, config.Storage.Options.OverrideKernelCheck))
- }
if config.Storage.Options.RemapUser != "" && config.Storage.Options.RemapGroup == "" {
config.Storage.Options.RemapGroup = config.Storage.Options.RemapUser
}
diff --git a/vendor/github.com/varlink/go/.gitignore b/vendor/github.com/varlink/go/.gitignore
index 69e30cff1..a43b0e2d3 100644
--- a/vendor/github.com/varlink/go/.gitignore
+++ b/vendor/github.com/varlink/go/.gitignore
@@ -1 +1,2 @@
/cmd/varlink-go-certification/orgvarlinkcertification/orgvarlinkcertification.go
+/.idea
diff --git a/vendor/github.com/varlink/go/.travis.yml b/vendor/github.com/varlink/go/.travis.yml
index c090a924f..fa9963500 100644
--- a/vendor/github.com/varlink/go/.travis.yml
+++ b/vendor/github.com/varlink/go/.travis.yml
@@ -1,11 +1,13 @@
language: go
sudo: false
go:
-- '1.9'
-- 1.10.x
+- '1.10'
+- 1.11.x
install:
- go get golang.org/x/tools/cmd/cover
- go get github.com/mattn/goveralls
+- go get github.com/TylerBrock/colorjson
+- go get github.com/fatih/color
script:
- go generate ./...
- '"$HOME/gopath/bin/goveralls" -v -show -service=travis-ci -repotoken "$COVERALLS_TOKEN"'
diff --git a/vendor/github.com/varlink/go/cmd/varlink/main.go b/vendor/github.com/varlink/go/cmd/varlink/main.go
new file mode 100644
index 000000000..1de4e1a45
--- /dev/null
+++ b/vendor/github.com/varlink/go/cmd/varlink/main.go
@@ -0,0 +1,295 @@
+package main
+
+import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "github.com/TylerBrock/colorjson"
+ "github.com/fatih/color"
+ "github.com/varlink/go/varlink"
+ "os"
+ "strings"
+)
+
+var bold = color.New(color.Bold)
+var errorBoldRed = bold.Sprint(color.New(color.FgRed).Sprint("Error:"))
+var bridge string
+
+func ErrPrintf(format string, a ...interface{}) {
+ fmt.Fprintf(os.Stderr, "%s ", errorBoldRed)
+ fmt.Fprintf(os.Stderr, format, a...)
+}
+
+func print_usage(set *flag.FlagSet, arg_help string) {
+ if set == nil {
+ fmt.Fprintf(os.Stderr, "Usage: %s [GLOBAL OPTIONS] COMMAND ...\n", os.Args[0])
+ } else {
+ fmt.Fprintf(os.Stderr, "Usage: %s [GLOBAL OPTIONS] %s [OPTIONS] %s\n", os.Args[0], set.Name(), arg_help)
+ }
+
+ fmt.Fprintln(os.Stderr, "\nGlobal Options:")
+ flag.PrintDefaults()
+
+ if set == nil {
+ fmt.Fprintln(os.Stderr, "\nCommands:")
+ fmt.Fprintln(os.Stderr, " info\tPrint information about a service")
+ fmt.Fprintln(os.Stderr, " help\tPrint interface description or service information")
+ fmt.Fprintln(os.Stderr, " call\tCall a method")
+ } else {
+ fmt.Fprintln(os.Stderr, "\nOptions:")
+ set.PrintDefaults()
+ }
+ os.Exit(1)
+}
+
+func varlink_call(args []string) {
+ var err error
+ var oneway bool
+
+ callFlags := flag.NewFlagSet("help", flag.ExitOnError)
+ callFlags.BoolVar(&oneway, "-oneway", false, "Use bridge for connection")
+ var help bool
+ callFlags.BoolVar(&help, "help", false, "Prints help information")
+ var usage = func() { print_usage(callFlags, "<[ADDRESS/]INTERFACE.METHOD> [ARGUMENTS]") }
+ callFlags.Usage = usage
+
+ _ = callFlags.Parse(args)
+
+ if help {
+ usage()
+ }
+
+ var con *varlink.Connection
+ var address string
+ var methodName string
+
+ if len(bridge) != 0 {
+ con, err = varlink.NewBridge(bridge)
+
+ if err != nil {
+ ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err)
+ os.Exit(2)
+ }
+ address = "bridge:" + bridge
+ methodName = callFlags.Arg(0)
+ } else {
+ uri := callFlags.Arg(0)
+ if uri == "" {
+ usage()
+ }
+
+ li := strings.LastIndex(uri, "/")
+
+ if li == -1 {
+ ErrPrintf("Invalid address '%s'\n", uri)
+ os.Exit(2)
+ }
+
+ address = uri[:li]
+ methodName = uri[li+1:]
+
+ con, err = varlink.NewConnection(address)
+
+ if err != nil {
+ ErrPrintf("Cannot connect to '%s': %v\n", address, err)
+ os.Exit(2)
+ }
+ }
+ var parameters string
+ var params json.RawMessage
+
+ parameters = callFlags.Arg(1)
+ if parameters == "" {
+ params = nil
+ } else {
+ json.Unmarshal([]byte(parameters), &params)
+ }
+
+ var flags uint64
+ flags = 0
+ if oneway {
+ flags |= varlink.Oneway
+ }
+ recv, err := con.Send(methodName, params, flags)
+
+ var retval map[string]interface{}
+
+ // FIXME: Use cont
+ _, err = recv(&retval)
+
+ f := colorjson.NewFormatter()
+ f.Indent = 2
+ f.KeyColor = color.New(color.FgCyan)
+ f.StringColor = color.New(color.FgMagenta)
+ f.NumberColor = color.New(color.FgMagenta)
+ f.BoolColor = color.New(color.FgMagenta)
+ f.NullColor = color.New(color.FgMagenta)
+
+ if err != nil {
+ ErrPrintf("Error calling '%s': %v\n", methodName, err)
+ switch e := err.(type) {
+ case *varlink.Error:
+ println(e.Name)
+ errorRawParameters := e.Parameters.(*json.RawMessage)
+
+ if errorRawParameters == nil {
+ break
+ }
+ var param map[string]interface{}
+ _ = json.Unmarshal(*errorRawParameters, &param)
+ c, _ := f.Marshal(param)
+ ErrPrintf("%v\n", string(c))
+ }
+ os.Exit(2)
+ }
+ c, _ := f.Marshal(retval)
+ fmt.Println(string(c))
+}
+
+func varlink_help(args []string) {
+ var err error
+
+ helpFlags := flag.NewFlagSet("help", flag.ExitOnError)
+ var help bool
+ helpFlags.BoolVar(&help, "help", false, "Prints help information")
+ var usage = func() { print_usage(helpFlags, "<[ADDRESS/]INTERFACE>") }
+ helpFlags.Usage = usage
+
+ _ = helpFlags.Parse(args)
+
+ if help {
+ usage()
+ }
+
+ var con *varlink.Connection
+ var address string
+ var interfaceName string
+
+ if len(bridge) != 0 {
+ con, err = varlink.NewBridge(bridge)
+
+ if err != nil {
+ ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err)
+ os.Exit(2)
+ }
+ address = "bridge:" + bridge
+ interfaceName = helpFlags.Arg(0)
+ } else {
+ uri := helpFlags.Arg(0)
+ if uri == "" && bridge == "" {
+ ErrPrintf("No ADDRESS or activation or bridge\n\n")
+ usage()
+ }
+
+ li := strings.LastIndex(uri, "/")
+
+ if li == -1 {
+ ErrPrintf("Invalid address '%s'\n", uri)
+ os.Exit(2)
+ }
+
+ address = uri[:li]
+
+ con, err = varlink.NewConnection(address)
+
+ if err != nil {
+ ErrPrintf("Cannot connect to '%s': %v\n", address, err)
+ os.Exit(2)
+ }
+
+ interfaceName = uri[li+1:]
+ }
+ description, err := con.GetInterfaceDescription(interfaceName)
+
+ if err != nil {
+ ErrPrintf("Cannot get interface description for '%s': %v\n", interfaceName, err)
+ os.Exit(2)
+ }
+
+ fmt.Println(description)
+}
+
+func varlink_info(args []string) {
+ var err error
+ infoFlags := flag.NewFlagSet("info", flag.ExitOnError)
+ var help bool
+ infoFlags.BoolVar(&help, "help", false, "Prints help information")
+ var usage = func() { print_usage(infoFlags, "[ADDRESS]") }
+ infoFlags.Usage = usage
+
+ _ = infoFlags.Parse(args)
+
+ if help {
+ usage()
+ }
+
+ var con *varlink.Connection
+ var address string
+
+ if len(bridge) != 0 {
+ con, err = varlink.NewBridge(bridge)
+
+ if err != nil {
+ ErrPrintf("Cannot connect with bridge '%s': %v\n", bridge, err)
+ os.Exit(2)
+ }
+ address = "bridge:" + bridge
+ } else {
+ address = infoFlags.Arg(0)
+
+ if address == "" && bridge == "" {
+ ErrPrintf("No ADDRESS or activation or bridge\n\n")
+ usage()
+ }
+
+ con, err = varlink.NewConnection(address)
+
+ if err != nil {
+ ErrPrintf("Cannot connect to '%s': %v\n", address, err)
+ os.Exit(2)
+ }
+ }
+
+ var vendor, product, version, url string
+ var interfaces []string
+
+ err = con.GetInfo(&vendor, &product, &version, &url, &interfaces)
+
+ if err != nil {
+ ErrPrintf("Cannot get info for '%s': %v\n", address, err)
+ os.Exit(2)
+ }
+
+ fmt.Printf("%s %s\n", bold.Sprint("Vendor:"), vendor)
+ fmt.Printf("%s %s\n", bold.Sprint("Product:"), product)
+ fmt.Printf("%s %s\n", bold.Sprint("Version:"), version)
+ fmt.Printf("%s %s\n", bold.Sprint("URL:"), url)
+ fmt.Printf("%s\n %s\n\n", bold.Sprint("Interfaces:"), strings.Join(interfaces[:], "\n "))
+}
+
+func main() {
+ var debug bool
+ var colorMode string
+
+ flag.CommandLine.Usage = func() { print_usage(nil, "") }
+ flag.BoolVar(&debug, "debug", false, "Enable debug output")
+ flag.StringVar(&bridge, "bridge", "", "Use bridge for connection")
+ flag.StringVar(&colorMode, "color", "auto", "colorize output [default: auto] [possible values: on, off, auto]")
+
+ flag.Parse()
+
+ if colorMode != "on" && (os.Getenv("TERM") == "" || colorMode == "off") {
+ color.NoColor = true // disables colorized output
+ }
+
+ switch flag.Arg(0) {
+ case "info":
+ varlink_info(flag.Args()[1:])
+ case "help":
+ varlink_help(flag.Args()[1:])
+ case "call":
+ varlink_call(flag.Args()[1:])
+ default:
+ print_usage(nil, "")
+ }
+}
diff --git a/vendor/github.com/varlink/go/varlink/bridge.go b/vendor/github.com/varlink/go/varlink/bridge.go
new file mode 100644
index 000000000..b20c0925a
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/bridge.go
@@ -0,0 +1,59 @@
+// +build !windows
+
+package varlink
+
+import (
+ "bufio"
+ "io"
+ "log"
+ "net"
+ "os/exec"
+)
+
+type PipeCon struct {
+ net.Conn
+ reader *io.ReadCloser
+ writer *io.WriteCloser
+}
+
+func (p PipeCon) Close() error {
+ err1 := (*p.reader).Close()
+ err2 := (*p.writer).Close()
+ if err1 != nil {
+ return err1
+ }
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+// NewConnection returns a new connection to the given address.
+func NewBridge(bridge string) (*Connection, error) {
+ //var err error
+
+ c := Connection{}
+ cmd := exec.Command("sh", "-c", bridge)
+ r, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, err
+ }
+ w, err := cmd.StdinPipe()
+ if err != nil {
+ return nil, err
+ }
+ c.conn = PipeCon{nil, &r, &w}
+ c.address = ""
+ c.reader = bufio.NewReader(r)
+ c.writer = bufio.NewWriter(w)
+
+ go func() {
+ err := cmd.Run()
+ if err != nil {
+ log.Fatal(err)
+ }
+ }()
+
+ return &c, nil
+}
+
diff --git a/vendor/github.com/varlink/go/varlink/bridge_windows.go b/vendor/github.com/varlink/go/varlink/bridge_windows.go
new file mode 100644
index 000000000..692367a1a
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/bridge_windows.go
@@ -0,0 +1,57 @@
+package varlink
+
+import (
+ "bufio"
+ "io"
+ "log"
+ "net"
+ "os/exec"
+)
+
+type PipeCon struct {
+ net.Conn
+ reader *io.ReadCloser
+ writer *io.WriteCloser
+}
+
+func (p PipeCon) Close() error {
+ err1 := (*p.reader).Close()
+ err2 := (*p.writer).Close()
+ if err1 != nil {
+ return err1
+ }
+ if err2 != nil {
+ return err2
+ }
+ return nil
+}
+
+// NewConnection returns a new connection to the given address.
+func NewBridge(bridge string) (*Connection, error) {
+ //var err error
+
+ c := Connection{}
+ cmd := exec.Command("cmd", "/C", bridge)
+ r, err := cmd.StdoutPipe()
+ if err != nil {
+ return nil, err
+ }
+ w, err := cmd.StdinPipe()
+ if err != nil {
+ return nil, err
+ }
+ c.conn = PipeCon{nil, &r, &w}
+ c.address = ""
+ c.reader = bufio.NewReader(r)
+ c.writer = bufio.NewWriter(w)
+
+ go func() {
+ err := cmd.Run()
+ if err != nil {
+ log.Fatal(err)
+ }
+ }()
+
+ return &c, nil
+}
+
diff --git a/vendor/github.com/varlink/go/varlink/connection.go b/vendor/github.com/varlink/go/varlink/connection.go
index 43bec6393..ac9542408 100644
--- a/vendor/github.com/varlink/go/varlink/connection.go
+++ b/vendor/github.com/varlink/go/varlink/connection.go
@@ -3,6 +3,7 @@ package varlink
import (
"bufio"
"encoding/json"
+ "fmt"
"net"
"strings"
)
@@ -18,6 +19,7 @@ const (
// Error is a varlink error returned from a method call.
type Error struct {
+ error
Name string
Parameters interface{}
}
@@ -189,6 +191,11 @@ func NewConnection(address string) (*Connection, error) {
var err error
words := strings.SplitN(address, ":", 2)
+
+ if len(words) != 2 {
+ return nil, fmt.Errorf("Protocol missing")
+ }
+
protocol := words[0]
addr := words[1]
diff --git a/vendor/github.com/varlink/go/varlink/service.go b/vendor/github.com/varlink/go/varlink/service.go
index 551ba4e53..cb461f917 100644
--- a/vendor/github.com/varlink/go/varlink/service.go
+++ b/vendor/github.com/varlink/go/varlink/service.go
@@ -6,10 +6,8 @@ import (
"fmt"
"net"
"os"
- "strconv"
"strings"
"sync"
- "syscall"
"time"
)
@@ -110,58 +108,6 @@ func (s *Service) handleMessage(writer *bufio.Writer, request []byte) error {
return iface.VarlinkDispatch(c, methodname)
}
-func activationListener() net.Listener {
- pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
- if err != nil || pid != os.Getpid() {
- return nil
- }
-
- nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
- if err != nil || nfds < 1 {
- return nil
- }
-
- fd := -1
-
- // If more than one file descriptor is passed, find the
- // "varlink" tag. The first file descriptor is always 3.
- if nfds > 1 {
- fdnames, set := os.LookupEnv("LISTEN_FDNAMES")
- if !set {
- return nil
- }
-
- names := strings.Split(fdnames, ":")
- if len(names) != nfds {
- return nil
- }
-
- for i, name := range names {
- if name == "varlink" {
- fd = 3 + i
- break
- }
- }
-
- if fd < 0 {
- return nil
- }
-
- } else {
- fd = 3
- }
-
- syscall.CloseOnExec(fd)
-
- file := os.NewFile(uintptr(fd), "varlink")
- listener, err := net.FileListener(file)
- if err != nil {
- return nil
- }
-
- return listener
-}
-
// Shutdown shuts down the listener of a running service.
func (s *Service) Shutdown() {
s.running = false
@@ -253,18 +199,17 @@ func getListener(protocol string, address string) (net.Listener, error) {
}
func (s *Service) refreshTimeout(timeout time.Duration) error {
- switch s.protocol {
- case "unix":
- if err := s.listener.(*net.UnixListener).SetDeadline(time.Now().Add(timeout)); err != nil {
+ switch l := s.listener.(type) {
+ case *net.UnixListener:
+ if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil {
return err
}
-
- case "tcp":
- if err := s.listener.(*net.TCPListener).SetDeadline(time.Now().Add(timeout)); err != nil {
+ case *net.TCPListener:
+ if err:= l.SetDeadline(time.Now().Add(timeout)); err != nil {
return err
}
- }
+ }
return nil
}
diff --git a/vendor/github.com/varlink/go/varlink/socketactivation.go b/vendor/github.com/varlink/go/varlink/socketactivation.go
new file mode 100644
index 000000000..a64c0dc8e
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/socketactivation.go
@@ -0,0 +1,63 @@
+// +build !windows
+
+package varlink
+
+import (
+ "net"
+ "os"
+ "strconv"
+ "strings"
+ "syscall"
+)
+
+func activationListener() net.Listener {
+ pid, err := strconv.Atoi(os.Getenv("LISTEN_PID"))
+ if err != nil || pid != os.Getpid() {
+ return nil
+ }
+
+ nfds, err := strconv.Atoi(os.Getenv("LISTEN_FDS"))
+ if err != nil || nfds < 1 {
+ return nil
+ }
+
+ fd := -1
+
+ // If more than one file descriptor is passed, find the
+ // "varlink" tag. The first file descriptor is always 3.
+ if nfds > 1 {
+ fdnames, set := os.LookupEnv("LISTEN_FDNAMES")
+ if !set {
+ return nil
+ }
+
+ names := strings.Split(fdnames, ":")
+ if len(names) != nfds {
+ return nil
+ }
+
+ for i, name := range names {
+ if name == "varlink" {
+ fd = 3 + i
+ break
+ }
+ }
+
+ if fd < 0 {
+ return nil
+ }
+
+ } else {
+ fd = 3
+ }
+
+ syscall.CloseOnExec(fd)
+
+ file := os.NewFile(uintptr(fd), "varlink")
+ listener, err := net.FileListener(file)
+ if err != nil {
+ return nil
+ }
+
+ return listener
+}
diff --git a/vendor/github.com/varlink/go/varlink/socketactivation_windows.go b/vendor/github.com/varlink/go/varlink/socketactivation_windows.go
new file mode 100644
index 000000000..fb0894531
--- /dev/null
+++ b/vendor/github.com/varlink/go/varlink/socketactivation_windows.go
@@ -0,0 +1,7 @@
+package varlink
+
+import "net"
+
+func activationListener() net.Listener {
+ return nil
+}
diff --git a/version/version.go b/version/version.go
index 45dc93d91..ea5a92286 100644
--- a/version/version.go
+++ b/version/version.go
@@ -4,4 +4,4 @@ package version
// NOTE: remember to bump the version at the top
// of the top-level README.md file when this is
// bumped.
-const Version = "0.12.2-dev"
+const Version = "1.0.1-dev"