summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml36
-rwxr-xr-xAPI.md71
-rw-r--r--Makefile2
-rw-r--r--RELEASE_NOTES.md54
-rw-r--r--changelog.txt202
-rw-r--r--cmd/podman/cliconfig/config.go4
-rw-r--r--cmd/podman/commands.go2
-rw-r--r--cmd/podman/container.go2
-rw-r--r--cmd/podman/cp.go80
-rw-r--r--cmd/podman/main_remote.go20
-rw-r--r--cmd/podman/ps.go2
-rw-r--r--cmd/podman/shared/intermediate_varlink.go3
-rw-r--r--cmd/podman/varlink.go34
-rw-r--r--cmd/podman/varlink/io.podman.varlink5
-rw-r--r--cmd/podman/version.go50
-rwxr-xr-xcontrib/cirrus/rootless_test.sh2
-rw-r--r--contrib/spec/podman.spec.in2
-rw-r--r--docs/podman-cp.1.md3
-rw-r--r--docs/podman-create.1.md69
-rw-r--r--docs/podman-run.1.md69
-rw-r--r--docs/podman-varlink.1.md19
-rw-r--r--docs/tutorials/podman_tutorial.md111
-rwxr-xr-xhack/tree_status.sh4
-rw-r--r--install.md198
-rw-r--r--libpod/container_internal.go24
-rw-r--r--libpod/lock/in_memory_locks.go16
-rw-r--r--libpod/lock/lock.go7
-rw-r--r--libpod/lock/shm/shm_lock.c55
-rw-r--r--libpod/lock/shm/shm_lock.go17
-rw-r--r--libpod/lock/shm/shm_lock.h1
-rw-r--r--libpod/lock/shm_lock_manager_linux.go19
-rw-r--r--libpod/pod_internal.go2
-rw-r--r--libpod/runtime.go2
-rw-r--r--libpod/runtime_ctr.go86
-rw-r--r--libpod/runtime_img.go2
-rw-r--r--libpod/runtime_pod_linux.go187
-rw-r--r--libpod/runtime_volume_linux.go2
-rw-r--r--pkg/adapter/client.go35
-rw-r--r--pkg/adapter/client_config.go4
-rw-r--r--pkg/adapter/containers.go12
-rw-r--r--pkg/adapter/containers_remote.go35
-rw-r--r--pkg/adapter/errors.go31
-rw-r--r--pkg/adapter/info_remote.go7
-rw-r--r--pkg/adapter/pods_remote.go6
-rw-r--r--pkg/adapter/runtime.go8
-rw-r--r--pkg/adapter/runtime_remote.go50
-rw-r--r--pkg/systemdgen/systemdgen_test.go120
-rw-r--r--pkg/varlinkapi/attach.go1
-rw-r--r--pkg/varlinkapi/containers.go17
-rw-r--r--pkg/varlinkapi/pods.go6
-rw-r--r--pkg/varlinkapi/system.go17
-rw-r--r--test/e2e/common_test.go7
-rw-r--r--test/e2e/cp_test.go75
-rw-r--r--test/e2e/create_test.go2
-rw-r--r--test/e2e/diff_test.go3
-rw-r--r--test/e2e/images_test.go3
-rw-r--r--test/e2e/info_test.go1
-rw-r--r--test/e2e/kill_test.go2
-rw-r--r--test/e2e/libpod_suite_remoteclient_test.go74
-rw-r--r--test/e2e/libpod_suite_test.go3
-rw-r--r--test/e2e/logs_test.go2
-rw-r--r--test/e2e/negative_test.go38
-rw-r--r--test/e2e/pod_create_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_prune_test.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_stop_test.go2
-rw-r--r--test/e2e/ps_test.go2
-rw-r--r--test/e2e/refresh_test.go74
-rw-r--r--test/e2e/rm_test.go2
-rw-r--r--test/e2e/run_test.go1
-rw-r--r--test/e2e/save_test.go10
-rw-r--r--test/e2e/stop_test.go2
-rw-r--r--test/e2e/tag_test.go2
-rw-r--r--test/e2e/version_test.go4
-rw-r--r--test/e2e/wait_test.go2
-rw-r--r--test/utils/utils.go6
-rw-r--r--vendor.conf2
-rw-r--r--vendor/github.com/varlink/go/varlink/bridge.go11
-rw-r--r--vendor/github.com/varlink/go/varlink/bridge_windows.go11
-rw-r--r--version/version.go2
86 files changed, 1540 insertions, 634 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index 0745b1e7b..514889969 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -176,10 +176,40 @@ vendor_task:
failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh |& ${TIMESTAMP}'
+# This task runs `make varlink_api_generate` followed by ./hack/tree_status.sh to check
+# whether the git tree is clean.
+varlink_api_task:
+
+ depends_on:
+ - "gating"
+
+ env:
+ CIRRUS_WORKING_DIR: "/usr/src/libpod"
+ # Used by tree_status.sh
+ SUGGESTION: 'remove API.md, then "make varlink_api_generate" and commit changes.'
+
+ # Runs within Cirrus's "community cluster"
+ container:
+ image: "quay.io/libpod/gate:latest"
+ cpu: 4
+ memory: 12
+
+ timeout_in: 10m
+
+ vendor_script:
+ - '/usr/local/bin/entrypoint.sh varlink_api_generate'
+ - 'cd /go/src/github.com/containers/libpod && ./hack/tree_status.sh'
+
+ on_failure:
+ failed_master_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_master_failure.sh'
+
+
build_each_commit_task:
depends_on:
- "gating"
+ - "vendor"
+ - "varlink_api"
# $CIRRUS_BASE_BRANCH is only set when testing a PR
only_if: $CIRRUS_BRANCH != 'master'
@@ -232,6 +262,8 @@ testing_task:
depends_on:
- "gating"
+ - "varlink_api"
+ - "vendor"
- "build_each_commit"
gce_instance:
@@ -275,6 +307,8 @@ special_testing_task:
depends_on:
- "gating"
+ - "varlink_api"
+ - "vendor"
- "build_each_commit"
gce_instance:
@@ -388,6 +422,8 @@ success_task:
depends_on: # ignores any dependent task conditions
- "gating"
+ - "varlink_api"
+ - "vendor"
- "build_each_commit_task"
- "testing"
- "rootless_testing_task"
diff --git a/API.md b/API.md
index 738449f43..db84f695c 100755
--- a/API.md
+++ b/API.md
@@ -45,6 +45,10 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func ExportImage(name: string, destination: string, compress: bool, tags: []string) string](#ExportImage)
+[func GenerateKube(name: string, service: bool) KubePodService](#GenerateKube)
+
+[func GenerateSystemd(name: string, restart: string, timeout: int, useName: bool) string](#GenerateSystemd)
+
[func GetAttachSockets(name: string) Sockets](#GetAttachSockets)
[func GetContainer(id: string) Container](#GetContainer)
@@ -57,6 +61,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func GetContainersByContext(all: bool, latest: bool, args: []string) []string](#GetContainersByContext)
+[func GetContainersByStatus(status: []string) Container](#GetContainersByStatus)
+
[func GetContainersLogs(names: []string, follow: bool, latest: bool, since: string, tail: int, timestamps: bool) LogLine](#GetContainersLogs)
[func GetEvents(filter: []string, since: string, until: string) Event](#GetEvents)
@@ -73,6 +79,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func GetPodsByContext(all: bool, latest: bool, args: []string) []string](#GetPodsByContext)
+[func GetPodsByStatus(statuses: []string) []string](#GetPodsByStatus)
+
[func GetVersion() string, string, string, string, string, int](#GetVersion)
[func GetVolumes(args: []string, all: bool) Volume](#GetVolumes)
@@ -87,6 +95,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func ImportImage(source: string, reference: string, message: string, changes: []string, delete: bool) string](#ImportImage)
+[func InitContainer(name: string) string](#InitContainer)
+
[func InspectContainer(name: string) string](#InspectContainer)
[func InspectImage(name: string) string](#InspectImage)
@@ -153,6 +163,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[func TagImage(name: string, tagged: string) string](#TagImage)
+[func Top(nameOrID: string, descriptors: []string) []string](#Top)
+
[func TopPod(pod: string, latest: bool, descriptors: []string) []string](#TopPod)
[func UnmountContainer(name: string, force: bool) ](#UnmountContainer)
@@ -211,6 +223,8 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[type InfoStore](#InfoStore)
+[type KubePodService](#KubePodService)
+
[type ListPodContainerInfo](#ListPodContainerInfo)
[type ListPodData](#ListPodData)
@@ -245,10 +259,14 @@ in the [API.md](https://github.com/containers/libpod/blob/master/API.md) file in
[error ContainerNotFound](#ContainerNotFound)
+[error ErrCtrStopped](#ErrCtrStopped)
+
[error ErrorOccurred](#ErrorOccurred)
[error ImageNotFound](#ImageNotFound)
+[error InvalidState](#InvalidState)
+
[error NoContainerRunning](#NoContainerRunning)
[error NoContainersInPod](#NoContainersInPod)
@@ -445,6 +463,17 @@ a booleon option to force compression. It also takes in a string array of tags
tags of the same image to a tarball (each tag should be of the form <image>:<tag>). Upon completion, the ID
of the image is returned. If the image cannot be found in local storage, an [ImageNotFound](#ImageNotFound)
error will be returned. See also [ImportImage](ImportImage).
+### <a name="GenerateKube"></a>func GenerateKube
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method GenerateKube(name: [string](https://godoc.org/builtin#string), service: [bool](https://godoc.org/builtin#bool)) [KubePodService](#KubePodService)</div>
+GenerateKube generates a Kubernetes v1 Pod description of a Podman container or pod
+and its containers. The description is in YAML. See also [ReplayKube](ReplayKube).
+### <a name="GenerateSystemd"></a>func GenerateSystemd
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method GenerateSystemd(name: [string](https://godoc.org/builtin#string), restart: [string](https://godoc.org/builtin#string), timeout: [int](https://godoc.org/builtin#int), useName: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div>
+
### <a name="GetAttachSockets"></a>func GetAttachSockets
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -522,6 +551,11 @@ method GetContainersByContext(all: [bool](https://godoc.org/builtin#bool), lates
GetContainersByContext allows you to get a list of container ids depending on all, latest, or a list of
container names. The definition of latest container means the latest by creation date. In a multi-
user environment, results might differ from what you expect.
+### <a name="GetContainersByStatus"></a>func GetContainersByStatus
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method GetContainersByStatus(status: [[]string](#[]string)) [Container](#Container)</div>
+
### <a name="GetContainersLogs"></a>func GetContainersLogs
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -621,6 +655,11 @@ method GetPodsByContext(all: [bool](https://godoc.org/builtin#bool), latest: [bo
GetPodsByContext allows you to get a list pod ids depending on all, latest, or a list of
pod names. The definition of latest pod means the latest by creation date. In a multi-
user environment, results might differ from what you expect.
+### <a name="GetPodsByStatus"></a>func GetPodsByStatus
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method GetPodsByStatus(statuses: [[]string](#[]string)) [[]string](#[]string)</div>
+GetPodsByStatus searches for pods whose status is included in statuses
### <a name="GetVersion"></a>func GetVersion
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -669,6 +708,16 @@ the IDs of the removed images are returned.
method ImportImage(source: [string](https://godoc.org/builtin#string), reference: [string](https://godoc.org/builtin#string), message: [string](https://godoc.org/builtin#string), changes: [[]string](#[]string), delete: [bool](https://godoc.org/builtin#bool)) [string](https://godoc.org/builtin#string)</div>
ImportImage imports an image from a source (like tarball) into local storage. The image can have additional
descriptions added to it using the message and changes options. See also [ExportImage](ExportImage).
+### <a name="InitContainer"></a>func InitContainer
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method InitContainer(name: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
+InitContainer initializes the given container. It accepts a container name or
+ID, and will initialize the container matching that ID if possible, and error
+if not. Containers can only be initialized when they are in the Created or
+Exited states. Initialization prepares a container to be started, but does not
+start the container. It is intended to be used to debug a container's state
+prior to starting it.
### <a name="InspectContainer"></a>func InspectContainer
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -1039,6 +1088,11 @@ $ varlink call -m unix:/run/podman/io.podman/io.podman.StopPod '{"name": "135d71
method TagImage(name: [string](https://godoc.org/builtin#string), tagged: [string](https://godoc.org/builtin#string)) [string](https://godoc.org/builtin#string)</div>
TagImage takes the name or ID of an image in local storage as well as the desired tag name. If the image cannot
be found, an [ImageNotFound](#ImageNotFound) error will be returned; otherwise, the ID of the image is returned on success.
+### <a name="Top"></a>func Top
+<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
+
+method Top(nameOrID: [string](https://godoc.org/builtin#string), descriptors: [[]string](#[]string)) [[]string](#[]string)</div>
+
### <a name="TopPod"></a>func TopPod
<div style="background-color: #E8E8E8; padding: 15px; margin: 10px; border-radius: 10px;">
@@ -1445,6 +1499,8 @@ quiet [](#)
readonly [](#)
+readonlytmpfs [](#)
+
restart [](#)
rm [](#)
@@ -1666,6 +1722,13 @@ graph_root [string](https://godoc.org/builtin#string)
graph_status [InfoGraphStatus](#InfoGraphStatus)
run_root [string](https://godoc.org/builtin#string)
+### <a name="KubePodService"></a>type KubePodService
+
+
+
+pod [string](https://godoc.org/builtin#string)
+
+service [string](https://godoc.org/builtin#string)
### <a name="ListPodContainerInfo"></a>type ListPodContainerInfo
ListPodContainerInfo is a returned struct for describing containers
@@ -1917,6 +1980,9 @@ force [bool](https://godoc.org/builtin#bool)
### <a name="ContainerNotFound"></a>type ContainerNotFound
ContainerNotFound means the container could not be found by the provided name or ID in local storage.
+### <a name="ErrCtrStopped"></a>type ErrCtrStopped
+
+Container is already stopped
### <a name="ErrorOccurred"></a>type ErrorOccurred
ErrorOccurred is a generic error for an error that occurs during the execution. The actual error message
@@ -1924,6 +1990,9 @@ is includes as part of the error's text.
### <a name="ImageNotFound"></a>type ImageNotFound
ImageNotFound means the image could not be found by the provided name or ID in local storage.
+### <a name="InvalidState"></a>type InvalidState
+
+InvalidState indicates that a container or pod was in an improper state for the requested operation
### <a name="NoContainerRunning"></a>type NoContainerRunning
NoContainerRunning means none of the containers requested are running in a command that requires a running container.
@@ -1933,7 +2002,7 @@ NoContainersInPod means a pod has no containers on which to perform the operatio
the pod ID.
### <a name="PodContainerError"></a>type PodContainerError
-PodContainerError means a container associated with a pod failed to preform an operation. It contains
+PodContainerError means a container associated with a pod failed to perform an operation. It contains
a container ID of the container that failed.
### <a name="PodNotFound"></a>type PodNotFound
diff --git a/Makefile b/Makefile
index 0085537d0..86d0d99d2 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
GO ?= go
DESTDIR ?= /
-EPOCH_TEST_COMMIT ?= 7b7397481960c85379d8eb1ed21e76da2ce8a4fc
+EPOCH_TEST_COMMIT ?= a9fc570dd844bf1ebd1f106f1b8091882b4a2b29
HEAD ?= HEAD
CHANGELOG_BASE ?= HEAD~
CHANGELOG_TARGET ?= HEAD
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 45e844cb8..499f46317 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,59 @@
# Release Notes
+## 1.3.0
+### Features
+- Podman now supports container restart policies! The `--restart-policy` flag on `podman create` and `podman run` allows containers to be restarted after they exit. Please note that Podman cannot restart containers after a system reboot - for that, see our next feature
+- Podman `podman generate systemd` command was added to generate systemd unit files for managing Podman containers
+- The `podman runlabel` command now allows a `$GLOBAL_OPTS` variable, which will be populated by global options passed to the `podman runlabel` command, allowing custom storage configurations to be passed into containers run with `runlabel` ([#2399](https://github.com/containers/libpod/issues/2399))
+- The `podman play kube` command now allows `File` and `FileOrCreate` volumes
+- The `podman pod prune` command was added to prune unused pods
+- Added the `podman system migrate` command to migrate containers using older configurations to allow their use by newer Libpod versions ([#2935](https://github.com/containers/libpod/issues/2935))
+- Podman containers now forward proxy-related environment variables from the host into the container with the `--http-proxy` flag (enabled by default)
+- Read-only Podman containers can now create tmpfs filesystems on `/tmp`, `/var/tmp`, and `/run` with the `--read-only-tmpfs` flag (enabled by default)
+- The `podman init` command was added, performing all container pre-start tasks without starting the container to allow pre-run debugging
+
+### Bugfixes
+- Fixed a bug where `podman cp` would not copy folders ([#2836](https://github.com/containers/libpod/issues/2836))
+- Fixed a bug where Podman would panic when the Varlink API attempted too pull a non-existent image ([#2860](https://github.com/containers/libpod/issues/2860))
+- Fixed a bug where `podman rmi` sometimes did not produce an event when images were deleted
+- Fixed a bug where Podman would panic when the Varlink API passed improperly-formatted options when attempting to build ([#2869](https://github.com/containers/libpod/issues/2869))
+- Fixed a bug where `podman images` would not print a header if no images were present ([#2877](https://github.com/containers/libpod/pull/2877))
+- Fixed a bug where the `podman images` command with `--filter dangling=false` would incorrectly print dangling images instead of images which are not dangling ([#2884](https://github.com/containers/libpod/issues/2884))
+- Fixed a bug where rootless Podman would panic when any command was run after the system was rebooted ([#2894](https://github.com/containers/libpod/issues/2894))
+- Fixed a bug where Podman containers in user namespaces would include undesired directories from the host in `/sys/kernel`
+- Fixed a bug where `podman create` would panic when trying to create a container whose name already existed
+- Fixed a bug where `podman pull` would exit 0 on failing to pull an image ([#2785](https://github.com/containers/libpod/issues/2785))
+- Fixed a bug where `podman pull` would not properly print the cause of errors that occurred ([#2710](https://github.com/containers/libpod/issues/2710))
+- Fixed a bug where rootless Podman commands were not properly suspended via `ctrl-z` in a shell ([#2775](https://github.com/containers/libpod/issues/2775))
+- Fixed a bug where Podman would error when cleaning up containers when some container mountpoints in `/sys/` were cleaned up already by the closing of the mount namespace
+- Fixed a bug where `podman play kube` was not including environment variables from the image run ([#2930](https://github.com/containers/libpod/issues/2930))
+- Fixed a bug where `podman play kube` would not properly clean up partially-created pods when encountering an error
+- Fixed a bug where `podman commit` with the `--change` flag improperly set `CMD` when a multipart value was provided ([#2951](https://github.com/containers/libpod/issues/2951))
+- Fixed a bug where the `--mount` flag to `podman create` and `podman run` did not properly validate its arguments, causing Podman to panic
+- Fixed a bug where conflicts between mounts created by the `--mount`, `--volume`, and `--tmpfs` flags were not properly reported
+- Fixed a bug where the `--mount` flag could not be used with named volumes
+- Fixed a bug where the `--mount` flag did not properly set options for created tmpfs filesystems
+- Fixed a bug where rootless Podman could close too many file descriptors, causing Podman to panic ([#2964](https://github.com/containers/libpod/issues/2964))
+- Fixed a bug where `podman logout` would not print an error when the login was established by `docker login` ([#2735](https://github.com/containers/libpod/issues/2735))
+- Fixed a bug where `podman stop` would error when not all containers were running ([#2993](https://github.com/containers/libpod/issues/2993))
+- Fixed a bug where `podman pull` would fail to pull images by shortname if they were not present in the `docker.io` registry
+- Fixed a bug where `podman login` would error when credentials were not present if a credential helper was configured ([#1675](https://github.com/containers/libpod/issues/1675))
+- Fixed a bug where the `podman system renumber` command and Podman post-reboot state refreshes would not create events
+- Fixed a bug where the `podman top` command was not compatible with `docker top` syntax
+
+### Misc
+- Updated vendored Buildah to v1.8.2
+- Updated vendored containers/storage to v1.12.6
+- Updated vendored containers/psgo to v1.2.1
+- Updated to sysregistriesv2, including slight changes to the `registries.conf` config file
+- Rootless Podman now places all containers within a single user namespace. This change will not take effect for existing containers until containers are restarted, and containers that are not restarted may not be fully usable
+- The `podman run`, `podman create`, `podman start`, `podman restart`, `podman attach`, `podman stop`, `podman port`, `podman rm`, `podman top`, `podman image tree`, `podman generate kube`, `podman umount`, `podman container checkpoint`, and `podman container restore` commands are now available in the remote client
+- The Podman remote client now builds on Windows
+- A major refactor of volumes created using the `podman volume` command was performed. There should be no major user-facing changes, but downgrading from Podman 1.3 to previous versions may render some volumes unable to be removed.
+- The `podman events` command now logs events to journald by default. The old behavior (log to file) can be configured in podman.conf via the `events_logger` option
+- The `podman commit` command, in versions 1.2 and earlier, included all volumes mounted into the container as image volumes in the committed image. This behavior was incorrect and has been disabled by default; it can be reenabled with the `--include-volumes` flag
+
+
## 1.2.0
### Features
- Podman now supports image healthchecks! The `podman healthcheck run` command was added to manually run healthchecks, and the status of a running healthcheck can be viewed via `podman inspect`
diff --git a/changelog.txt b/changelog.txt
index 92a17f8d0..c72117d7f 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,205 @@
+- Changelog for v1.3.0 (2019-05-06)
+ * Update release notes for 1.3.0 release
+ * Bump to Buildah v1.8.2
+ * Document events logger options in libpod.conf manpage
+ * Try and fix restart-policy tests
+ * fix logout message if login only with docker
+ * Fix manpage typos
+ * Small code fix
+ * Fix 'restart' event in journald
+ * change from sysregistries to sysregistriesv2
+ * Address review comments on restart policy
+ * Add a test for restart policy
+ * Add a restart event, and make one during restart policy
+ * Restart policy should not run if a container is running
+ * Restart policy conflicts with the --rm flag
+ * Move to using constants for valid restart policy types
+ * Add manpage information for restart policy
+ * Add support for retry count with --restart flag
+ * Sending signals to containers prevents restart policy
+ * Add container restart policy to Libpod & Podman
+ * Add a StoppedByUser field to the DB
+ * top: fallback to execing ps(1)
+ * clean up shared/parse/parse.go
+ * Generate systemd unit files for containers
+ * Fix podman-in-podman volume test
+ * Cirrus: Add pipefail confirmation check
+ * Cirrus: timestamp all output script output
+ * Update c/storage to v1.12.6
+ * Fix typo in init manpage
+ * Add an InvalidState varlink error for Init
+ * Bump Buildah to v1.8.1, ImageBuilder to v1.1.0
+ * Add variable for global flags to runlabel
+ * docs: Fix typo "healthcheck" pt2
+ * cirrus lib.sh: refactor req_env_var()
+ * Remove two bits of dead code
+ * http-proxy: improve docs
+ * Small fixes for #2950
+ * container: drop rootless check
+ * Add basic structure of podman init command
+ * Move handling of ReadOnlyTmpfs into new mounts code
+ * Begin adding volume tests
+ * Ensure that named volumes have their options parsed
+ * Add options parsing for tmpfs mounts
+ * Use EqualValues instead of reflect equality
+ * Hit a number of to-do comments in unified volumes code
+ * Fix options for non-bind and non-tmpfs volumes
+ * Migrate unit tests from cmd/podman into pkg/spec
+ * Migrate to unified volume handling code
+ * Always pass pod into MakeContainerConfig
+ * Remove non-config fields from CreateConfig
+ * Add a new function for converting a CreateConfig
+ * podman-remote port
+ * install.md contains hints for rootless setup on arch linux
+ * auto pass http_proxy into container
+ * enable podman-remote on windows
+ * Use 'sudo tee' in tutorial so install works as non-root
+ * Refactor container cleanup to use latest functions
+ * Move --mount in run man page
+ * Add details on rootless Podman to the readme
+ * podman-remote stop
+ * correct upstream vndr issues
+ * runtime: pass down the context
+ * system: add new subcommand "migrate"
+ * Vendor in latest buildah code
+ * remove manual install of libsystemd-dev
+ * Vendor in latest containers/storage
+ * Add --read-only-tmpfs options
+ * Fix remote-client testing reports
+ * podman-remote prune containers
+ * Do not hard fail on non-decodable events
+ * update psgo to v1.2.1
+ * Add System event type and renumber, refresh events
+ * enable podman remote top
+ * fix login supports credHelpers config
+ * Cirrus: Collect audit log on success and failure
+ * Add a debug message indicating that a refresh occurred
+ * image: rework parent/child/history matching
+ * images: add context to GetParent/IsParent/Remove/Prune...
+ * build podman-remote with Dockerfile.
+ * point to 3rd party tools for `docker-compose` format
+ * Update vendor of container/storage
+ * journald event logging
+ * podman remote-client restart containers
+ * Cirrus: Use freshly built images
+ * Cirrus: Bump up runc commit
+ * Cirrus: fix obsolete Ubuntu package
+ * Cirrus: Install libsystemd-dev on Ubuntu
+ * pull: special case all-tags semantics
+ * Fix test compile
+ * Trim whitespace from ps -q before comparing
+ * Enhance tests for stop to check results
+ * Add extra CI tests for stopping all containers
+ * Fix podman stop --all attempting to stop created ctrs
+ * Cirrus: Temp. override container-selinux on F29
+ * Refactor of 'podman prune' to better support remote
+ * bats - various small updates
+ * podman-remote pause|unpause
+ * Internal names do not match external names
+ * Add header to play kube output
+ * Clean up after play kube failure
+ * rootless: not close more FDs than needed
+ * Fix COPR builds to start working again
+ * Fix podman command --change CMD
+ * podman-remote start
+ * Vendor in latest Buildah
+ * Added remote pod prune
+ * Add podman pod prune
+ * podman-remote container commands
+ * Fix segfaults attribute to missing options
+ * Call the runtime with WithRenumber() when asked
+ * Add File mounts to play kube
+ * cmd, pkg: drop commented code
+ * pod: drop dead code
+ * rootless, mount: not create namespace
+ * Incorporate image and default environment variables in play kube
+ * Validate ENV/LABEL Change options in varlink
+ * oci: fix umount of /sys/kernel
+ * Revert "rootless: set controlling terminal for podman in the userns"
+ * Remove old crio reference from man pages
+ * create: fix segfault if container name already exists
+ * adding uidmap to install steps for ubuntu
+ * podman-remote generate kube
+ * rootless: do not block SIGTSTP
+ * rootless: set controlling terminal for podman in the userns
+ * Use GetContainer instead of LookupContainer for full ID
+ * pull: exit with error if the image is not found
+ * Use the same SELinux label for CRIU log files
+ * pull: remove cryptic error message
+ * new uidmap BATS test: fix
+ * adding additional update, needed for install
+ * Fix README.md -> rootless.md link
+ * Fixes for podman-remote run and attach
+ * remote-client checkpoint/restore
+ * Expand debugging for container cleanup errors
+ * spec: mask /sys/kernel when bind mounting /sys
+ * Add --include-volumes flag to 'podman commit'
+ * oci: add /sys/kernel to the masked paths
+ * userns: prevent /sys/kernel/* paths in the container
+ * imagefilter dangling handling corrected
+ * rootless: fix segfault on refresh if there are containers
+ * Add demo script and cast to images
+ * Initial remote flag clean up
+ * (minor): fix misspelled 'Healthcheck'
+ * BATS tests: start supporting podman-remote
+ * Add the ability to attach remotely to a container
+ * Print header for 'podman images' even with no images
+ * podman-remote ps
+ * Re-run (make vendor) to drop the now unnecessary collation code and tables
+ * Potentially breaking: Make hooks sort order locale-independent
+ * Implement podman-remote rm
+ * ps: now works with --size and nonroot
+ * Update invalid name errors to report the correct regex
+ * cirrus: enable remote tests for rootless
+ * test: fix remote tests for rootless
+ * test: enable userns e2e tests for rootless
+ * CI check for --help vs man pages: usability fix
+ * podman-remote create|run
+ * Correct varlink pull panic
+ * add image rmi event
+ * Revert "Switch to golangci-lint"
+ * Document shortcomings with rootless podman
+ * podman: enable kube for rootless
+ * kube: correctly set the default for MemorySwappiness
+ * rootless: enable healthcheck tests
+ * Respect image entrypoint in play kube
+ * Increase CI resources to help avoid hitting timeouts
+ * podman-remote image tree
+ * Added port forwarding and IP address hint.
+ * fix bug podman cp directory
+ * Fix E2E tests
+ * Drop LocalVolumes from our the database
+ * Major rework of --volumes-from flag
+ * Volume force-remove now removed dependent containers
+ * Add handling for new named volumes code in pkg/spec
+ * Create non-existing named volumes at container create
+ * Switch Libpod over to new explicit named volumes
+ * Add named volumes for each container to database
+ * Add varcheck linter
+ * Add deadcode linter
+ * Update lint to use golangci-lint
+ * Update registrar unit tests to match them of cri-o
+ * Update run tests to be skipped when not supported
+ * Fix Dockerfile dependencies for packer tests
+ * Update Dockerfile to use golang:1.12 image
+ * Fix a potential segfault in podman search
+ * Improve podman pod rm -a test
+ * Cirrus: Update F28 -> F29 container image
+ * --size does not work with rootless at present
+ * add remote-client diff
+ * Cirrus: Support special-case modes of testing
+ * rootless: use a single user namespace
+ * rootless: remove SkipStorageSetup()
+ * Update cri-o annotations
+ * Update README with current version
+ * docs/podman*.md: fix numerous option typos and spacing errors
+ * docs/podman-rm.1.md: delete "Not yet implemented" msg for volume removal
+ * docs/podman-inspect.1.md: add missing option hyphen for "-t"
+ * Bump gitvalidation epoch
+ * Bump to v1.3.0-dev
+ * Fix location of libpod.conf
+ * Capitalize global options help information
+
- Changelog for v1.2.0 (2019-03-30)
* Update release notes for v1.2.0
* Remove wait event
diff --git a/cmd/podman/cliconfig/config.go b/cmd/podman/cliconfig/config.go
index b770aaca0..aaa4513d8 100644
--- a/cmd/podman/cliconfig/config.go
+++ b/cmd/podman/cliconfig/config.go
@@ -32,6 +32,10 @@ type MainFlags struct {
CpuProfile string
LogLevel string
TmpDir string
+
+ RemoteUserName string
+ RemoteHost string
+ VarlinkAddress string
}
type AttachValues struct {
diff --git a/cmd/podman/commands.go b/cmd/podman/commands.go
index 14451d944..3a409f503 100644
--- a/cmd/podman/commands.go
+++ b/cmd/podman/commands.go
@@ -39,13 +39,11 @@ func getImageSubCommands() []*cobra.Command {
func getContainerSubCommands() []*cobra.Command {
return []*cobra.Command{
- _checkpointCommand,
_cleanupCommand,
_commitCommand,
_execCommand,
_mountCommand,
_refreshCommand,
- _restoreCommand,
_runlabelCommand,
_statsCommand,
_umountCommand,
diff --git a/cmd/podman/container.go b/cmd/podman/container.go
index bbf01d1f8..530175a55 100644
--- a/cmd/podman/container.go
+++ b/cmd/podman/container.go
@@ -51,6 +51,7 @@ var (
// Commands that are universally implemented.
containerCommands = []*cobra.Command{
_attachCommand,
+ _checkpointCommand,
_containerExistsCommand,
_contInspectSubCommand,
_diffCommand,
@@ -64,6 +65,7 @@ var (
_portCommand,
_pruneContainersCommand,
_restartCommand,
+ _restoreCommand,
_runCommand,
_rmCommand,
_startCommand,
diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go
index 82f2d3f20..4cb8a8c54 100644
--- a/cmd/podman/cp.go
+++ b/cmd/podman/cp.go
@@ -1,7 +1,9 @@
package main
import (
+ "archive/tar"
"fmt"
+ "io"
"os"
"path/filepath"
"strings"
@@ -142,7 +144,11 @@ func copyBetweenHostAndContainer(runtime *libpod.Runtime, src string, dest strin
var lastError error
for _, src := range glob {
- err := copy(src, destPath, dest, idMappingOpts, &containerOwner, extract)
+ if src == "-" {
+ src = os.Stdin.Name()
+ extract = true
+ }
+ err := copy(src, destPath, dest, idMappingOpts, &containerOwner, extract, isFromHostToCtr)
if lastError != nil {
logrus.Error(lastError)
}
@@ -195,7 +201,7 @@ func getPathInfo(path string) (string, os.FileInfo, error) {
return path, srcfi, nil
}
-func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, chownOpts *idtools.IDPair, extract bool) error {
+func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, chownOpts *idtools.IDPair, extract, isFromHostToCtr bool) error {
srcPath, err := filepath.EvalSymlinks(src)
if err != nil {
return errors.Wrapf(err, "error evaluating symlinks %q", srcPath)
@@ -205,6 +211,16 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
if err != nil {
return err
}
+
+ filename := filepath.Base(destPath)
+ if filename == "-" && !isFromHostToCtr {
+ err := streamFileToStdout(srcPath, srcfi)
+ if err != nil {
+ return errors.Wrapf(err, "error streaming source file %s to Stdout", srcPath)
+ }
+ return nil
+ }
+
destdir := destPath
if !srcfi.IsDir() && !strings.HasSuffix(dest, string(os.PathSeparator)) {
destdir = filepath.Dir(destPath)
@@ -224,7 +240,6 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch
untarPath := chrootarchive.UntarPathAndChown(chownOpts, digest.Canonical.Digester().Hash(), idMappingOpts.UIDMap, idMappingOpts.GIDMap)
if srcfi.IsDir() {
-
logrus.Debugf("copying %q to %q", srcPath+string(os.PathSeparator)+"*", dest+string(os.PathSeparator)+"*")
if destDirIsExist && !strings.HasSuffix(src, fmt.Sprintf("%s.", string(os.PathSeparator))) {
destPath = filepath.Join(destPath, filepath.Base(srcPath))
@@ -276,3 +291,62 @@ func convertIDMap(idMaps []idtools.IDMap) (convertedIDMap []specs.LinuxIDMapping
}
return convertedIDMap
}
+
+func streamFileToStdout(srcPath string, srcfi os.FileInfo) error {
+ if srcfi.IsDir() {
+ tw := tar.NewWriter(os.Stdout)
+ err := filepath.Walk(srcPath, func(path string, info os.FileInfo, err error) error {
+ if err != nil || !info.Mode().IsRegular() || path == srcPath {
+ return err
+ }
+ hdr, err := tar.FileInfoHeader(info, "")
+ if err != nil {
+ return err
+ }
+
+ if err = tw.WriteHeader(hdr); err != nil {
+ return err
+ }
+ fh, err := os.Open(path)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+
+ _, err = io.Copy(tw, fh)
+ return err
+ })
+ if err != nil {
+ return errors.Wrapf(err, "error streaming directory %s to Stdout", srcPath)
+ }
+ return nil
+ }
+
+ file, err := os.Open(srcPath)
+ if err != nil {
+ return errors.Wrapf(err, "error opening file %s", srcPath)
+ }
+ defer file.Close()
+ if !archive.IsArchivePath(srcPath) {
+ tw := tar.NewWriter(os.Stdout)
+ hdr, err := tar.FileInfoHeader(srcfi, "")
+ if err != nil {
+ return err
+ }
+ err = tw.WriteHeader(hdr)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(tw, file)
+ if err != nil {
+ return errors.Wrapf(err, "error streaming archive %s to Stdout", srcPath)
+ }
+ return nil
+ }
+
+ _, err = io.Copy(os.Stdout, file)
+ if err != nil {
+ return errors.Wrapf(err, "error streaming file to Stdout")
+ }
+ return nil
+}
diff --git a/cmd/podman/main_remote.go b/cmd/podman/main_remote.go
index a3335050a..c8bb3ad3e 100644
--- a/cmd/podman/main_remote.go
+++ b/cmd/podman/main_remote.go
@@ -3,17 +3,17 @@
package main
import (
- "os"
-
- "github.com/containers/libpod/pkg/rootless"
- "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
const remote = true
func init() {
- // remote client specific flags can go here.
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteUserName, "username", "", "username on the remote host")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.RemoteHost, "remote-host", "", "remote host")
+ // TODO maybe we allow the altering of this for bridge connections?
+ //rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.VarlinkAddress, "varlink-address", adapter.DefaultAddress, "address of the varlink socket")
+ rootCmd.PersistentFlags().StringVar(&MainGlobalOpts.LogLevel, "log-level", "error", "Log messages above specified level: debug, info, warn, error, fatal or panic")
}
func setSyslog() error {
@@ -29,16 +29,6 @@ func profileOff(cmd *cobra.Command) error {
}
func setupRootless(cmd *cobra.Command, args []string) error {
- if rootless.IsRootless() {
- became, ret, err := rootless.BecomeRootInUserNS()
- if err != nil {
- logrus.Errorf(err.Error())
- os.Exit(1)
- }
- if became {
- os.Exit(ret)
- }
- }
return nil
}
diff --git a/cmd/podman/ps.go b/cmd/podman/ps.go
index 623f17050..eb5181126 100644
--- a/cmd/podman/ps.go
+++ b/cmd/podman/ps.go
@@ -497,7 +497,7 @@ func psDisplay(c *cliconfig.PsValues, runtime *adapter.LocalRuntime) error {
} else {
// Print namespace information
- ns := shared.GetNamespaces(container.Pid)
+ ns := runtime.GetNamespaces(container)
fmt.Fprintf(w, "\n%s\t%s\t%d\t%s\t%s\t%s\t%s\t%s\t%s\t%s", container.ID, container.Names, container.Pid, ns.Cgroup, ns.IPC, ns.MNT, ns.NET, ns.PIDNS, ns.User, ns.UTS)
}
diff --git a/cmd/podman/shared/intermediate_varlink.go b/cmd/podman/shared/intermediate_varlink.go
index 5e21245e3..4742d4909 100644
--- a/cmd/podman/shared/intermediate_varlink.go
+++ b/cmd/podman/shared/intermediate_varlink.go
@@ -3,8 +3,6 @@
package shared
import (
- "fmt"
-
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/varlink"
"github.com/containers/libpod/pkg/rootless"
@@ -209,7 +207,6 @@ func boolFromVarlink(v *bool, flagName string, defaultValue bool) CRBool {
cr.Val = defaultValue
cr.Changed = false
} else {
- fmt.Println(flagName, cr.Val)
cr.Val = *v
cr.Changed = true
}
diff --git a/cmd/podman/varlink.go b/cmd/podman/varlink.go
index 978678a84..215542d2c 100644
--- a/cmd/podman/varlink.go
+++ b/cmd/podman/varlink.go
@@ -3,11 +3,17 @@
package main
import (
+ "fmt"
+ "os"
+ "path/filepath"
"time"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/cmd/podman/libpodruntime"
iopodman "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/pkg/adapter"
+ "github.com/containers/libpod/pkg/rootless"
+ "github.com/containers/libpod/pkg/util"
"github.com/containers/libpod/pkg/varlinkapi"
"github.com/containers/libpod/version"
"github.com/pkg/errors"
@@ -45,13 +51,31 @@ func init() {
}
func varlinkCmd(c *cliconfig.VarlinkValues) error {
- args := c.InputArgs
- if len(args) < 1 {
- return errors.Errorf("you must provide a varlink URI")
+ varlinkURI := adapter.DefaultAddress
+ if rootless.IsRootless() {
+ xdg, err := util.GetRootlessRuntimeDir()
+ if err != nil {
+ return err
+ }
+ socketDir := filepath.Join(xdg, "podman/io.podman")
+ if _, err := os.Stat(filepath.Dir(socketDir)); os.IsNotExist(err) {
+ if err := os.Mkdir(filepath.Dir(socketDir), 0755); err != nil {
+ return err
+ }
+ }
+ varlinkURI = fmt.Sprintf("unix:%s", socketDir)
}
+ args := c.InputArgs
+
if len(args) > 1 {
- return errors.Errorf("too many arguments. Requires exactly 1")
+ return errors.Errorf("too many arguments. you may optionally provide 1")
+ }
+
+ if len(args) > 0 {
+ varlinkURI = args[0]
}
+
+ logrus.Debugf("Using varlink socket: %s", varlinkURI)
timeout := time.Duration(c.Timeout) * time.Millisecond
// Create a single runtime for varlink
@@ -81,7 +105,7 @@ func varlinkCmd(c *cliconfig.VarlinkValues) error {
}
// Run the varlink server at the given address
- if err = service.Listen(args[0], timeout); err != nil {
+ if err = service.Listen(varlinkURI, timeout); err != nil {
switch err.(type) {
case varlink.ServiceTimeoutError:
logrus.Infof("varlink service expired (use --timeout to increase session time beyond %d ms, 0 means never timeout)", c.Int64("timeout"))
diff --git a/cmd/podman/varlink/io.podman.varlink b/cmd/podman/varlink/io.podman.varlink
index ace81646c..faaecdb6b 100644
--- a/cmd/podman/varlink/io.podman.varlink
+++ b/cmd/podman/varlink/io.podman.varlink
@@ -1254,4 +1254,7 @@ error ErrorOccurred (reason: string)
error RuntimeError (reason: string)
# The Podman endpoint requires that you use a streaming connection.
-error WantsMoreRequired (reason: string) \ No newline at end of file
+error WantsMoreRequired (reason: string)
+
+# Container is already stopped
+error ErrCtrStopped (id: string)
diff --git a/cmd/podman/version.go b/cmd/podman/version.go
index e964bdbb5..439a1cca6 100644
--- a/cmd/podman/version.go
+++ b/cmd/podman/version.go
@@ -2,6 +2,7 @@ package main
import (
"fmt"
+ "io"
"os"
"strings"
"text/tabwriter"
@@ -10,6 +11,7 @@ import (
"github.com/containers/buildah/pkg/formats"
"github.com/containers/libpod/cmd/podman/cliconfig"
"github.com/containers/libpod/libpod"
+ "github.com/containers/libpod/pkg/adapter"
"github.com/pkg/errors"
"github.com/spf13/cobra"
)
@@ -38,7 +40,7 @@ func init() {
// versionCmd gets and prints version info for version command
func versionCmd(c *cliconfig.VersionValues) error {
- output, err := libpod.GetVersion()
+ clientVersion, err := libpod.GetVersion()
if err != nil {
errors.Wrapf(err, "unable to determine version")
}
@@ -51,25 +53,49 @@ func versionCmd(c *cliconfig.VersionValues) error {
var out formats.Writer
switch versionOutputFormat {
case formats.JSONString:
- out = formats.JSONStruct{Output: output}
+ out = formats.JSONStruct{Output: clientVersion}
default:
- out = formats.StdoutTemplate{Output: output, Template: versionOutputFormat}
+ out = formats.StdoutTemplate{Output: clientVersion, Template: versionOutputFormat}
}
return formats.Writer(out).Out()
}
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
defer w.Flush()
- fmt.Fprintf(w, "Version:\t%s\n", output.Version)
- fmt.Fprintf(w, "RemoteAPI Version:\t%d\n", output.RemoteAPIVersion)
- fmt.Fprintf(w, "Go Version:\t%s\n", output.GoVersion)
- if output.GitCommit != "" {
- fmt.Fprintf(w, "Git Commit:\t%s\n", output.GitCommit)
+
+ if remote {
+ fmt.Fprintf(w, "Client:\n")
+ }
+ formatVersion(w, clientVersion)
+
+ if remote {
+ fmt.Fprintf(w, "\nService:\n")
+
+ runtime, err := adapter.GetRuntime(getContext(), nil)
+ if err != nil {
+ return errors.Wrapf(err, "could not get runtime")
+ }
+ defer runtime.Shutdown(false)
+
+ serviceVersion, err := runtime.GetVersion()
+ if err != nil {
+ return err
+ }
+ formatVersion(w, serviceVersion)
+ }
+ return nil
+}
+
+func formatVersion(writer io.Writer, version libpod.Version) {
+ fmt.Fprintf(writer, "Version:\t%s\n", version.Version)
+ fmt.Fprintf(writer, "RemoteAPI Version:\t%d\n", version.RemoteAPIVersion)
+ fmt.Fprintf(writer, "Go Version:\t%s\n", version.GoVersion)
+ if version.GitCommit != "" {
+ fmt.Fprintf(writer, "Git Commit:\t%s\n", version.GitCommit)
}
// Prints out the build time in readable format
- if output.Built != 0 {
- fmt.Fprintf(w, "Built:\t%s\n", time.Unix(output.Built, 0).Format(time.ANSIC))
+ if version.Built != 0 {
+ fmt.Fprintf(writer, "Built:\t%s\n", time.Unix(version.Built, 0).Format(time.ANSIC))
}
- fmt.Fprintf(w, "OS/Arch:\t%s\n", output.OsArch)
- return nil
+ fmt.Fprintf(writer, "OS/Arch:\t%s\n", version.OsArch)
}
diff --git a/contrib/cirrus/rootless_test.sh b/contrib/cirrus/rootless_test.sh
index 8351214f3..eab06bac0 100755
--- a/contrib/cirrus/rootless_test.sh
+++ b/contrib/cirrus/rootless_test.sh
@@ -14,8 +14,6 @@ then
exit 1
fi
-export PODMAN_VARLINK_ADDRESS=unix:/tmp/podman-$(id -u)
-
echo "."
echo "Hello, my name is $USER and I live in $PWD can I be your friend?"
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index f3ee01bca..d69b673e0 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: 1.3.0
+Version: 1.3.1
Release: #COMMITDATE#.git%{shortcommit0}%{?dist}
Summary: Manage Pods, Containers and Container Images
License: ASL 2.0
diff --git a/docs/podman-cp.1.md b/docs/podman-cp.1.md
index 44612003d..406dd51df 100644
--- a/docs/podman-cp.1.md
+++ b/docs/podman-cp.1.md
@@ -8,6 +8,7 @@ podman\-cp - Copy files/folders between a container and the local filesystem
## DESCRIPTION
Copies the contents of **src_path** to the **dest_path**. You can copy from the containers's filesystem to the local machine or the reverse, from the local filesystem to the container.
+If - is specified for either the SRC_PATH or DEST_PATH, you can also stream a tar archive from STDIN or to STDOUT.
The CONTAINER can be a running or stopped container. The **src_path** or **dest_path** can be a file or directory.
@@ -107,5 +108,7 @@ podman cp containerID:/home/myuser/. /home/myuser/
podman cp --extract /home/myuser/myfiles.tar.gz containerID:/myfiles
+podman cp - containerID:/myfiles.tar.gz < myfiles.tar.gz
+
## SEE ALSO
podman(1), podman-mount(1), podman-umount(1)
diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md
index 851f5cf3d..cf36106e8 100644
--- a/docs/podman-create.1.md
+++ b/docs/podman-create.1.md
@@ -244,26 +244,6 @@ inside of the container.
Read in a line delimited file of environment variables
-**--http-proxy**=*true*|*false*
-
-By default proxy environment variables are passed into the container if set
-for the podman process. This can be disabled by setting the `--http-proxy`
-option to `false`. The environment variables passed in include `http_proxy`,
-`https_proxy`, `ftp_proxy`, `no_proxy`, and also the upper case versions of
-those. This option is only needed when the host system must use a proxy but
-the container should not use any proxy. Proxy environment variables specified
-for the container in any other way will override the values that would have
-been passed thru from the host. (Other ways to specify the proxy for the
-container include passing the values with the `--env` flag, or hardcoding the
-proxy environment at container build time.)
-
-For example, to disable passing these environment variables from host to
-container:
-
-`--http-proxy=false`
-
-Defaults to `true`
-
**--expose**=[]
Expose a port, or a range of ports (e.g. --expose=3300-3310) to set up port redirection
@@ -281,20 +261,27 @@ Add additional groups to run as
**--healthcheck**=""
-Set or alter a healthcheck for a container. The value must be of the format of:
+Set or alter a healthcheck command for a container. The command is a command to be executed inside your
+container that determines your container health. The command is required for other healthcheck options
+to be applied. A value of `none` disables existing healthchecks.
+
+**--healthcheck-interval**=""
+
+Set an interval for the healthchecks (a value of `disable` results in no automatic timer setup) (default "30s")
- `[OPTIONS] CMD command`
+**--healthcheck-retries=**
- where options can be any of the follow:
- * --interval=DURATION (default: 30s)
- * --timeout=DURATION (default: 30s)
- * --start-period=DURATION (default: 0s)
- * --retries=N (default: 3)
+The number of retries allowed before a healthcheck is considered to be unhealthy. The default value is `3`.
-Note: options are *not* required.
+**--healthcheck-start-period**=""
-The command is a command to be executed inside your container that determines your container health. The
-command is required.
+The initialization time needed for a container to bootstrap. The value can be expressed in time format like
+`2m3s`. The default value is `0s`
+
+**--healthcheck-timeout**=""
+
+The maximum time allowed to complete the healthcheck before an interval is considered failed. Like start-period, the
+value can be expressed in a time format such as `1m22s`. The default value is `30s`.
**--hostname**=""
@@ -306,6 +293,26 @@ Sets the container host name that is available inside the container.
Print usage statement
+**--http-proxy**=*true*|*false*
+
+By default proxy environment variables are passed into the container if set
+for the podman process. This can be disabled by setting the `--http-proxy`
+option to `false`. The environment variables passed in include `http_proxy`,
+`https_proxy`, `ftp_proxy`, `no_proxy`, and also the upper case versions of
+those. This option is only needed when the host system must use a proxy but
+the container should not use any proxy. Proxy environment variables specified
+for the container in any other way will override the values that would have
+been passed thru from the host. (Other ways to specify the proxy for the
+container include passing the values with the `--env` flag, or hardcoding the
+proxy environment at container build time.)
+
+For example, to disable passing these environment variables from host to
+container:
+
+`--http-proxy=false`
+
+Defaults to `true`
+
**--image-volume**, **builtin-volume**=*bind*|*tmpfs*|*ignore*
Tells podman how to handle the builtin image volumes. The options are: 'bind', 'tmpfs', or 'ignore' (default 'bind').
@@ -585,7 +592,7 @@ Automatically remove the container when it exits. The default is *false*.
Note that the container will not be removed when it could not be created or
started successfully. This allows the user to inspect the container after
-failure. The `--rm` flag is incompatible with the `-d` flag.
+failure.
**--rootfs**
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index db90ce50e..1840e0f0b 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -251,26 +251,6 @@ inside of the container.
Read in a line delimited file of environment variables
-**--http-proxy**=*true*|*false*
-
-By default proxy environment variables are passed into the container if set
-for the podman process. This can be disabled by setting the `--http-proxy`
-option to `false`. The environment variables passed in include `http_proxy`,
-`https_proxy`, `ftp_proxy`, `no_proxy`, and also the upper case versions of
-those. This option is only needed when the host system must use a proxy but
-the container should not use any proxy. Proxy environment variables specified
-for the container in any other way will override the values that would have
-been passed thru from the host. (Other ways to specify the proxy for the
-container include passing the values with the `--env` flag, or hardcoding the
-proxy environment at container build time.)
-
-For example, to disable passing these environment variables from host to
-container:
-
-`--http-proxy=false`
-
-Defaults to `true`
-
**--expose**=[]
Expose a port, or a range of ports (e.g. --expose=3300-3310) to set up port redirection
@@ -289,20 +269,27 @@ Add additional groups to run as
**--healthcheck**=""
-Set or alter a healthcheck for a container. The value must be of the format of:
+Set or alter a healthcheck command for a container. The command is a command to be executed inside your
+container that determines your container health. The command is required for other healthcheck options
+to be applied. A value of `none` disables existing healthchecks.
+
+**--healthcheck-interval**=""
+
+Set an interval for the healthchecks (a value of `disable` results in no automatic timer setup) (default "30s")
- `[OPTIONS] CMD command`
+**--healthcheck-retries=**
- where options can be any of the follow:
- * --interval=DURATION (default: 30s)
- * --timeout=DURATION (default: 30s)
- * --start-period=DURATION (default: 0s)
- * --retries=N (default: 3)
+The number of retries allowed before a healthcheck is considered to be unhealthy. The default value is `3`.
-Note: options are *not* required.
+**--healthcheck-start-period**=""
-The command is a command to be executed inside your container that determines your container health. The
-command is required.
+The initialization time needed for a container to bootstrap. The value can be expressed in time format like
+`2m3s`. The default value is `0s`
+
+**--healthcheck-timeout**=""
+
+The maximum time allowed to complete the healthcheck before an interval is considered failed. Like start-period, the
+value can be expressed in a time format such as `1m22s`. The default value is `30s`.
**--hostname**=""
@@ -314,6 +301,26 @@ Sets the container host name that is available inside the container.
Print usage statement
+**--http-proxy**=*true*|*false*
+
+By default proxy environment variables are passed into the container if set
+for the podman process. This can be disabled by setting the `--http-proxy`
+option to `false`. The environment variables passed in include `http_proxy`,
+`https_proxy`, `ftp_proxy`, `no_proxy`, and also the upper case versions of
+those. This option is only needed when the host system must use a proxy but
+the container should not use any proxy. Proxy environment variables specified
+for the container in any other way will override the values that would have
+been passed thru from the host. (Other ways to specify the proxy for the
+container include passing the values with the `--env` flag, or hardcoding the
+proxy environment at container build time.)
+
+For example, to disable passing these environment variables from host to
+container:
+
+`--http-proxy=false`
+
+Defaults to `true`
+
**--image-volume**, **builtin-volume**=*bind*|*tmpfs*|*ignore*
Tells podman how to handle the builtin image volumes.
@@ -607,7 +614,7 @@ Automatically remove the container when it exits. The default is *false*.
Note that the container will not be removed when it could not be created or
started successfully. This allows the user to inspect the container after
-failure. The `--rm` flag is incompatible with the `-d` flag.
+failure.
**--rootfs**
diff --git a/docs/podman-varlink.1.md b/docs/podman-varlink.1.md
index 7eeb3dd66..0501d853f 100644
--- a/docs/podman-varlink.1.md
+++ b/docs/podman-varlink.1.md
@@ -7,8 +7,10 @@ podman\-varlink - Runs the varlink backend interface
**podman varlink** [*options*] *uri*
## DESCRIPTION
-Starts the varlink service listening on *uri* that allows varlink clients to interact with podman. This should generally be done
-with systemd. See _Configuration_ below.
+Starts the varlink service listening on *uri* that allows varlink clients to interact with podman. If no *uri* is provided, a default
+URI will be used depending on the user calling the varlink service. The default for the root user is `unix:/run/podman/io.podman`. Regular
+users will have a default *uri* of `$XDG_RUNTIME_DIR/podman/io.podman`. For example, `unix:/run/user/1000/podman/io.podman`
+The varlink service should generally be done with systemd. See _Configuration_ below.
## GLOBAL OPTIONS
@@ -23,16 +25,23 @@ second. A value of `0` means no timeout and the session will not expire.
## EXAMPLES
-Run the podman varlink service manually and accept the default timeout.
+Run the podman varlink service accepting all default options.
```
-$ podman varlink unix:/run/podman/io.podman
+$ podman varlink
+```
+
+
+Run the podman varlink service with an alternate URI and accept the default timeout.
+
+```
+$ podman varlink unix:/tmp/io.podman
```
Run the podman varlink service manually with a 5 second timeout.
```
-$ podman varlink --timeout 5000 unix:/run/podman/io.podman
+$ podman varlink --timeout 5000
```
## CONFIGURATION
diff --git a/docs/tutorials/podman_tutorial.md b/docs/tutorials/podman_tutorial.md
index f972853e6..032b7c851 100644
--- a/docs/tutorials/podman_tutorial.md
+++ b/docs/tutorials/podman_tutorial.md
@@ -8,114 +8,9 @@ commands with Podman.
**NOTE**: the code samples are intended to be run as a non-root user, and use `sudo` where
root escalation is required.
-## Install Podman on Fedora from RPM Repositories
-Fedora 27 and later provide Podman via the package manager.
-```console
-sudo dnf install -y podman
-```
-
-*Optional*: If you've already installed podman on Fedora and you're feeling
-adventerous, you can test the very latest podman in Fedora's `updates-testing`
-repository before it goes out to all Fedora users.
-```console
-sudo yum distro-sync --enablerepo=updates-testing podman
-```
-
-If you use a newer podman package from Fedora's `updates-testing`, we would
-appreciate your `+1` feedback in [Bodhi, Fedora's update management
-system](https://bodhi.fedoraproject.org/updates/?packages=podman).
-
-## Install Podman on Fedora from Source
-Many of the basic components to run Podman are readily available from the Fedora RPM repositories.
-In this section, we will help you install all the runtime and build dependencies for Podman,
-acquire the source, and build it.
-
-### Installing build and runtime dependencies
-```console
-sudo dnf install -y git runc libassuan-devel golang golang-github-cpuguy83-go-md2man glibc-static \
- gpgme-devel glib2-devel device-mapper-devel libseccomp-devel \
- atomic-registries iptables containers-common containernetworking-cni \
- conmon ostree-devel
-```
-### Building and installing podman
-
-First, configure a `GOPATH` (if you are using go1.8 or later, this defaults to `~/go`), then clone
-and make libpod.
-
-```console
-export GOPATH=~/go
-mkdir -p $GOPATH
-git clone https://github.com/containers/libpod/ $GOPATH/src/github.com/containers/libpod
-cd $GOPATH/src/github.com/containers/libpod
-make
-sudo make install PREFIX=/usr
-```
-
-You now have a working podman environment. Jump to [Familiarizing yourself with Podman](#familiarizing-yourself-with-podman)
-to begin using Podman.
-
-## Install podman on Ubuntu
-
-The default Ubuntu cloud image size will not allow for the following exercise to be done without increasing its
-capacity. Be sure to add at least 5GB to the image. Instructions to do this are outside the scope of this
-tutorial. For this tutorial, the Ubuntu **artful-server-cloudimg** image was used.
+## Installing Podman
-### Installing build and runtime dependencies
-
-#### Installing base packages
-```console
-sudo apt-get update
-sudo apt-get install libdevmapper-dev libglib2.0-dev libgpgme11-dev golang libseccomp-dev libostree-dev \
- go-md2man libprotobuf-dev libprotobuf-c0-dev libseccomp-dev python3-setuptools
-```
-#### Building and installing conmon
-First, configure a `GOPATH` (if you are using go1.8 or later, this defaults to `~/go`), then clone
-and make libpod.
-
-```console
-export GOPATH=~/go
-mkdir -p $GOPATH
-git clone https://github.com/kubernetes-sigs/cri-o $GOPATH/src/github.com/kubernetes-sigs/cri-o
-cd $GOPATH/src/github.com/kubernetes-sigs/cri-o
-mkdir bin
-make bin/conmon
-sudo install -D -m 755 bin/conmon /usr/libexec/podman/conmon
-```
-#### Adding required configuration files
-```console
-sudo mkdir -p /etc/containers
-sudo curl https://raw.githubusercontent.com/projectatomic/registries/master/registries.fedora -o /etc/containers/registries.conf
-sudo curl https://raw.githubusercontent.com/containers/skopeo/master/default-policy.json -o /etc/containers/policy.json
-```
-#### Installing CNI plugins
-```console
-git clone https://github.com/containernetworking/plugins.git $GOPATH/src/github.com/containernetworking/plugins
-cd $GOPATH/src/github.com/containernetworking/plugins
-./build_linux.sh
-sudo mkdir -p /usr/libexec/cni
-sudo cp bin/* /usr/libexec/cni
-```
-#### Installing CNI config
-Add a most basic network config
-```console
-mkdir -p /etc/cni/net.d
-curl -qsSL https://raw.githubusercontent.com/containers/libpod/master/cni/87-podman-bridge.conflist | sudo tee /etc/cni/net.d/99-loopback.conf
-```
-#### Installing runc
-```console
-git clone https://github.com/opencontainers/runc.git $GOPATH/src/github.com/opencontainers/runc
-cd $GOPATH/src/github.com/opencontainers/runc
-make BUILDTAGS="seccomp"
-sudo cp runc /usr/bin/runc
-```
-
-### Building and installing Podman
-```console
-git clone https://github.com/containers/libpod/ $GOPATH/src/github.com/containers/libpod
-cd $GOPATH/src/github.com/containers/libpod
-make
-sudo make install PREFIX=/usr
-```
+For installing or building Podman, please see the [installation instructions](install.md).
## Familiarizing yourself with Podman
@@ -128,7 +23,7 @@ podman run -dt -p 8080:8080/tcp -e HTTPD_VAR_RUN=/var/run/httpd -e HTTPD_MAIN_CO
-e HTTPD_CONTAINER_SCRIPTS_PATH=/usr/share/container-scripts/httpd/ \
registry.fedoraproject.org/f27/httpd /usr/bin/run-httpd
```
-Because the container is being run in detached mode, represented by the *-d* in the podman run command, podman
+Because the container is being run in detached mode, represented by the *-d* in the `podman run` command, Podman
will print the container ID after it has run. Note that we use port forwarding to be able to
access the HTTP server. For successful running at least slirp4netns v0.3.0 is needed.
diff --git a/hack/tree_status.sh b/hack/tree_status.sh
index 78fb4c6a3..ac874a347 100755
--- a/hack/tree_status.sh
+++ b/hack/tree_status.sh
@@ -1,12 +1,14 @@
#!/bin/bash
set -e
+SUGGESTION="${SUGGESTION:-sync the vendor.conf and commit all changes.}"
+
STATUS=$(git status --porcelain)
if [[ -z $STATUS ]]
then
echo "tree is clean"
else
- echo "tree is dirty, please commit all changes and sync the vendor.conf"
+ echo "tree is dirty, please $SUGGESTION"
echo ""
echo "$STATUS"
exit 1
diff --git a/install.md b/install.md
index bd7f326c3..82dd4c36a 100644
--- a/install.md
+++ b/install.md
@@ -8,7 +8,7 @@
sudo pacman -S podman
```
-If you have problems when running podman in [rootless](README.md#rootless) mode follow [these instructions](https://wiki.archlinux.org/index.php/Linux_Containers#Enable_support_to_run_unprivileged_containers_(optional))
+If you have problems when running Podman in [rootless](README.md#rootless) mode follow the instructions [here](https://wiki.archlinux.org/index.php/Linux_Containers#Enable_support_to_run_unprivileged_containers_(optional))
#### [Fedora](https://www.fedoraproject.org), [CentOS](https://www.centos.org)
@@ -16,7 +16,6 @@ If you have problems when running podman in [rootless](README.md#rootless) mode
sudo yum -y install podman
```
-
#### [Fedora-CoreOS](https://coreos.fedoraproject.org), [Fedora SilverBlue](https://silverblue.fedoraproject.org)
Built-in, no need to install
@@ -39,7 +38,7 @@ 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.
+Subscribe, then enable Extras channel and install Podman.
```bash
sudo subscription-manager repos --enable=rhel-7-server-extras-rpms
@@ -53,8 +52,12 @@ sudo yum module enable -y container-tools:1.0
sudo yum module install -y container-tools:1.0
```
+### Installing development versions of Podman
+
#### [Ubuntu](https://www.ubuntu.com)
+The latest builds are available in a PPA. Take note of the [Build and Run Dependencies](#build-and-run-dependencies) listed below if you run into any issues.
+
```bash
sudo apt-get update -qq
sudo apt-get install -qq -y software-properties-common uidmap
@@ -63,25 +66,20 @@ sudo apt-get update -qq
sudo apt-get -qq -y install podman
```
-Take note of the [Build and Run Dependencies](#build-and-run-dependencies) listed below if you run into any issues.
-
-## Building from scratch
+#### Fedora
-### Prerequisites
+You can test the very latest Podman in Fedora's `updates-testing`
+repository before it goes out to all Fedora users.
-#### runc installed
-
-The latest version of `runc` is expected to be installed on the system. It is picked up as the default runtime by podman.
-
-#### conmon installed
-
-The latest version of `conmon` is expected to be installed on the system. Conmon is used to monitor OCI Runtimes.
+```console
+sudo yum distro-sync --enablerepo=updates-testing podman
+```
-#### Setup CNI networking
+If you use a newer Podman package from Fedora's `updates-testing`, we would
+appreciate your `+1` feedback in [Bodhi, Fedora's update management
+system](https://bodhi.fedoraproject.org/updates/?packages=podman).
-A proper description of setting up CNI networking is given in the [`cni` README](cni/README.md).
-But the gist is that you need to have some basic network configurations enabled and
-CNI plugins installed on your system.
+## Building from scratch
### Build and Run Dependencies
@@ -90,7 +88,7 @@ CNI plugins installed on your system.
Fedora, CentOS, RHEL, and related distributions:
```bash
-yum install -y \
+sudo yum install -y \
atomic-registries \
btrfs-progs-devel \
conmon \
@@ -118,42 +116,133 @@ yum install -y \
Debian, Ubuntu, and related distributions:
```bash
-apt-get install -y \
+sudo apt-get install \
btrfs-tools \
git \
golang-go \
go-md2man \
iptables \
libassuan-dev \
+ libc6-dev \
libdevmapper-dev \
libglib2.0-dev \
- libc6-dev \
- libgpgme11-dev \
+ libgpgme-dev \
libgpg-error-dev \
+ libostree-dev \
libprotobuf-dev \
libprotobuf-c0-dev \
libseccomp-dev \
libselinux1-dev \
+ libsystemd-dev \
pkg-config \
+ runc \
uidmap
```
-Debian, Ubuntu, and related distributions will also need to do the following setup:
+### Building missing dependencies
- * A copy of the development libraries for `ostree`, either in the form of the `libostree-dev` package from the [flatpak](https://launchpad.net/~alexlarsson/+archive/ubuntu/flatpak) PPA, or built [from source](https://github.com/ostreedev/ostree) (more on that [here](https://ostree.readthedocs.io/en/latest/#building)). As of Ubuntu 18.04, `libostree-dev` is available in the main repositories, and the PPA is no longer required.
- * [Add required configuration files](https://github.com/containers/libpod/blob/master/docs/tutorials/podman_tutorial.md#adding-required-configuration-files)
- * Install conmon, CNI plugins and runc
- * [Install conmon](https://github.com/containers/libpod/blob/master/docs/tutorials/podman_tutorial.md#building-and-installing-conmon)
- * [Install CNI plugins](https://github.com/containers/libpod/blob/master/docs/tutorials/podman_tutorial.md#installing-cni-plugins)
- * [runc Installation](https://github.com/containers/libpod/blob/master/docs/tutorials/podman_tutorial.md#installing-runc) - Although installable, the latest runc is not available in the Ubuntu repos. Version 1.0.0-rc4 is the minimal requirement.
+If any dependencies cannot be installed or are not sufficiently current, they have to be built from source.
+This will mainly affect Debian, Ubuntu, and related distributions, or RHEL where no subscription is active (e.g. Cloud VMs).
-**NOTE**
+#### ostree
-If using an older release or a long-term support release, be careful to double-check that the version of `runc` is new enough (running `runc --version` should produce `spec: 1.0.0`), or else [build](https://github.com/containers/libpod/blob/master/docs/tutorials/podman_tutorial.md#installing-runc) your own.
+A copy of the development libraries for `ostree` is necessary, either in the form of the `libostree-dev` package
+from the [flatpak](https://launchpad.net/~alexlarsson/+archive/ubuntu/flatpak) PPA,
+or built [from source](https://github.com/ostreedev/ostree/blob/master/docs/contributing-tutorial.md)
+(see also [here](https://ostree.readthedocs.io/en/latest/#building)). As of Ubuntu 18.04, `libostree-dev` is available in the main repositories,
+and the PPA is no longer required.
-Be careful to double-check that the version of golang is new enough, version 1.10.x or higher is required. If needed, golang kits are available at https://golang.org/dl/
+To build, use the following (running `make` can take a while):
+```bash
+git clone https://github.com/ostreedev/ostree ~/ostree
+cd ~/ostree
+git submodule update --init
+# for Fedora, CentOS, RHEL
+sudo yum install -y automake bison e2fsprogs-devel fuse-devel libtool xz-devel zlib-devel
+# for Debian, Ubuntu etc.
+sudo apt-get install -y automake bison e2fsprogs fuse liblzma-dev libtool zlib1g
+
+./autogen.sh --prefix=/usr --libdir=/usr/lib64 --sysconfdir=/etc
+# remove --nonet option due to https:/github.com/ostreedev/ostree/issues/1374
+sed -i '/.*--nonet.*/d' ./Makefile-man.am
+make
+sudo make install
+```
+
+#### golang
+
+Be careful to double-check that the version of golang is new enough (i.e. `go version`), version 1.10.x or higher is required.
+If needed, golang kits are available at https://golang.org/dl/. Alternatively, go can be built from source as follows
+(it's helpful to leave the system-go installed, to avoid having to [bootstrap go](https://golang.org/doc/install/source):
+
+```bash
+export GOPATH=~/go
+git clone https://go.googlesource.com/go $GOPATH
+cd $GOPATH
+git checkout tags/go1.10.8 # optional
+cd src
+./all.bash
+export PATH=$GOPATH/bin:$PATH
+```
-**Optional**
+#### conmon
+
+The latest version of `conmon` is expected to be installed on the system. Conmon is used to monitor OCI Runtimes.
+To build from source, use the following (if not already executed above, run `export GOPATH=~/go && mkdir -p $GOPATH`):
+
+```bash
+git clone https://github.com/cri-o/cri-o $GOPATH/src/github.com/cri-o/cri-o
+cd $GOPATH/src/github.com/cri-o/cri-o
+mkdir bin
+make bin/conmon
+sudo install -D -m 755 bin/conmon /usr/libexec/podman/conmon
+```
+
+#### runc
+
+The latest version of `runc` is expected to be installed on the system. It is picked up as the default runtime by Podman.
+Version 1.0.0-rc4 is the minimal requirement, which is available in Ubuntu 18.04 already.
+To double-check, `runc --version` should produce at least `spec: 1.0.1`, otherwise build your own:
+
+```bash
+git clone https://github.com/opencontainers/runc.git $GOPATH/src/github.com/opencontainers/runc
+cd $GOPATH/src/github.com/opencontainers/runc
+make BUILDTAGS="selinux seccomp"
+sudo cp runc /usr/bin/runc
+```
+
+#### CNI plugins
+
+```bash
+git clone https://github.com/containernetworking/plugins.git $GOPATH/src/github.com/containernetworking/plugins
+cd $GOPATH/src/github.com/containernetworking/plugins
+./build_linux.sh
+sudo mkdir -p /usr/libexec/cni
+sudo cp bin/* /usr/libexec/cni
+```
+
+#### Setup CNI networking
+
+A proper description of setting up CNI networking is given in the [`cni` README](cni/README.md).
+
+Using the CNI plugins from above, a more basic network config is achieved with:
+
+```bash
+mkdir -p /etc/cni/net.d
+curl -qsSL https://raw.githubusercontent.com/containers/libpod/master/cni/87-podman-bridge.conflist | sudo tee /etc/cni/net.d/99-loopback.conf
+```
+
+
+#### Add configuration
+
+```bash
+sudo mkdir -p /etc/containers
+sudo curl https://raw.githubusercontent.com/projectatomic/registries/master/registries.fedora -o /etc/containers/registries.conf
+sudo curl https://raw.githubusercontent.com/containers/skopeo/master/default-policy.json -o /etc/containers/policy.json
+```
+
+
+#### Optional packages
Fedora, CentOS, RHEL, and related distributions:
@@ -168,53 +257,38 @@ apt-get install -y \
### Get Source Code
-As with other Go projects, PODMAN must be cloned into a directory structure like:
+As with other Go projects, Podman must be cloned into a directory structure like:
```
GOPATH
└── src
└── github.com
- └── containers
- └── libpod
-```
-
-First, configure a `GOPATH` (if you are using go1.8 or later, this defaults to `~/go`)
-and then add $GOPATH/bin to your $PATH environment variable.
-
-```bash
-export GOPATH=~/go
-mkdir -p $GOPATH
-export PATH=$PATH:$GOPATH/bin
+ └── containers
+ └── libpod
```
-Next, clone the source code using:
+First, ensure that the go version that is found first on the $PATH (in case you built your own; see [above](#golang)) is sufficiently recent -
+`go version` must be higher than 1.10.x). Then we can finally build Podman (assuming we already have a `$GOPATH` and the corresponding folder,
+`export GOPATH=~/go && mkdir -p $GOPATH`):
```bash
-mkdir -p $GOPATH/src/github.com/containers
-cd $_ # or cd $GOPATH/src/github.com/containers
-git clone https://github.com/containers/libpod # or your fork
-cd libpod
+git clone https://github.com/containers/libpod/ $GOPATH/src/github.com/containers/libpod
+cd $GOPATH/src/github.com/containers/libpod
+make BUILDTAGS="selinux seccomp"
+sudo make install PREFIX=
```
-### Build
-
-```bash
-make install.tools
-make
-sudo make install
-```
+#### Build Tags
-Otherwise, if you do not want to build `podman` with seccomp support you can add `BUILDTAGS=""` when running make.
+Otherwise, if you do not want to build Podman with seccomp or selinux support you can add `BUILDTAGS=""` when running make.
```bash
make BUILDTAGS=""
sudo make install
```
-#### Build Tags
-
-`podman` supports optional build tags for compiling support of various features.
-To add build tags to the make option the `BUILDTAGS` variable must be set.
+Podman supports optional build tags for compiling support of various features.
+To add build tags to the make option the `BUILDTAGS` variable must be set, for example:
```bash
make BUILDTAGS='seccomp apparmor'
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index 0b4e5763e..fc33a1bbc 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -516,7 +516,7 @@ func (c *Container) refresh() error {
}
// We need to pick up a new lock
- lock, err := c.runtime.lockManager.RetrieveLock(c.config.LockID)
+ lock, err := c.runtime.lockManager.AllocateAndRetrieveLock(c.config.LockID)
if err != nil {
return errors.Wrapf(err, "error acquiring lock for container %s", c.ID())
}
@@ -1490,3 +1490,25 @@ func (c *Container) copyWithTarFromImage(src, dest string) error {
}
return a.CopyWithTar(source, dest)
}
+
+// checkReadyForRemoval checks whether the given container is ready to be
+// removed.
+// These checks are only used if force-remove is not specified.
+// If it is, we'll remove the container anyways.
+// Returns nil if safe to remove, or an error describing why it's unsafe if not.
+func (c *Container) checkReadyForRemoval() error {
+ if c.state.State == ContainerStateUnknown {
+ return errors.Wrapf(ErrCtrStateInvalid, "container %s is in invalid state", c.ID())
+ }
+
+ if c.state.State == ContainerStateRunning ||
+ c.state.State == ContainerStatePaused {
+ return errors.Wrapf(ErrCtrStateInvalid, "cannot remove container %s as it is %s - running or paused containers cannot be removed", c.ID(), c.state.State.String())
+ }
+
+ if len(c.state.ExecSessions) != 0 {
+ return errors.Wrapf(ErrCtrStateInvalid, "cannot remove container %s as it has active exec sessions", c.ID())
+ }
+
+ return nil
+}
diff --git a/libpod/lock/in_memory_locks.go b/libpod/lock/in_memory_locks.go
index 7c9605917..f3c842f89 100644
--- a/libpod/lock/in_memory_locks.go
+++ b/libpod/lock/in_memory_locks.go
@@ -90,6 +90,22 @@ func (m *InMemoryManager) RetrieveLock(id uint32) (Locker, error) {
return m.locks[id], nil
}
+// AllocateAndRetrieveLock allocates a lock with the given ID (if not already in
+// use) and returns it.
+func (m *InMemoryManager) AllocateAndRetrieveLock(id uint32) (Locker, error) {
+ if id >= m.numLocks {
+ return nil, errors.Errorf("given lock ID %d is too large - this manager only supports lock indexes up to %d", id, m.numLocks)
+ }
+
+ if m.locks[id].allocated {
+ return nil, errors.Errorf("given lock ID %d is already in use, cannot reallocate", id)
+ }
+
+ m.locks[id].allocated = true
+
+ return m.locks[id], nil
+}
+
// FreeAllLocks frees all locks.
// This function is DANGEROUS. Please read the full comment in locks.go before
// trying to use it.
diff --git a/libpod/lock/lock.go b/libpod/lock/lock.go
index d6841646b..4e1e2e215 100644
--- a/libpod/lock/lock.go
+++ b/libpod/lock/lock.go
@@ -24,6 +24,13 @@ type Manager interface {
// The underlying lock MUST be the same as another other lock with the
// same UUID.
RetrieveLock(id uint32) (Locker, error)
+ // AllocateAndRetrieveLock marks the lock with the given UUID as in use
+ // and retrieves it.
+ // RetrieveAndAllocateLock will error if the lock in question has
+ // already been allocated.
+ // This is mostly used after a system restart to repopulate the list of
+ // locks in use.
+ AllocateAndRetrieveLock(id uint32) (Locker, error)
// PLEASE READ FULL DESCRIPTION BEFORE USING.
// FreeAllLocks frees all allocated locks, in preparation for lock
// reallocation.
diff --git a/libpod/lock/shm/shm_lock.c b/libpod/lock/shm/shm_lock.c
index d11fce71a..047d3c417 100644
--- a/libpod/lock/shm/shm_lock.c
+++ b/libpod/lock/shm/shm_lock.c
@@ -354,6 +354,61 @@ int64_t allocate_semaphore(shm_struct_t *shm) {
return -1 * ENOSPC;
}
+// Allocate the semaphore with the given ID.
+// Returns an error if the semaphore with this ID does not exist, or has already
+// been allocated.
+// Returns 0 on success, or negative errno values on failure.
+int32_t allocate_given_semaphore(shm_struct_t *shm, uint32_t sem_index) {
+ int bitmap_index, index_in_bitmap, ret_code;
+ bitmap_t test_map;
+
+ if (shm == NULL) {
+ return -1 * EINVAL;
+ }
+
+ // Check if the lock index is valid
+ if (sem_index >= shm->num_locks) {
+ return -1 * EINVAL;
+ }
+
+ bitmap_index = sem_index / BITMAP_SIZE;
+ index_in_bitmap = sem_index % BITMAP_SIZE;
+
+ // This should never happen if the sem_index test above succeeded, but better
+ // safe than sorry
+ if (bitmap_index >= shm->num_bitmaps) {
+ return -1 * EFAULT;
+ }
+
+ test_map = 0x1 << index_in_bitmap;
+
+ // Lock the mutex controlling access to our shared memory
+ ret_code = take_mutex(&(shm->segment_lock));
+ if (ret_code != 0) {
+ return -1 * ret_code;
+ }
+
+ // Check if the semaphore is allocated
+ if ((test_map & shm->locks[bitmap_index].bitmap) != 0) {
+ ret_code = release_mutex(&(shm->segment_lock));
+ if (ret_code != 0) {
+ return -1 * ret_code;
+ }
+
+ return -1 * EEXIST;
+ }
+
+ // The semaphore is not allocated, allocate it
+ shm->locks[bitmap_index].bitmap = shm->locks[bitmap_index].bitmap | test_map;
+
+ ret_code = release_mutex(&(shm->segment_lock));
+ if (ret_code != 0) {
+ return -1 * ret_code;
+ }
+
+ return 0;
+}
+
// Deallocate a given semaphore
// Returns 0 on success, negative ERRNO values on failure
int32_t deallocate_semaphore(shm_struct_t *shm, uint32_t sem_index) {
diff --git a/libpod/lock/shm/shm_lock.go b/libpod/lock/shm/shm_lock.go
index e70ea8743..c21e9a221 100644
--- a/libpod/lock/shm/shm_lock.go
+++ b/libpod/lock/shm/shm_lock.go
@@ -134,6 +134,23 @@ func (locks *SHMLocks) AllocateSemaphore() (uint32, error) {
return uint32(retCode), nil
}
+// AllocateGivenSemaphore allocates the given semaphore from the shared-memory
+// segment for use by a container or pod.
+// If the semaphore is already in use or the index is invalid an error will be
+// returned.
+func (locks *SHMLocks) AllocateGivenSemaphore(sem uint32) error {
+ if !locks.valid {
+ return errors.Wrapf(syscall.EINVAL, "locks have already been closed")
+ }
+
+ retCode := C.allocate_given_semaphore(locks.lockStruct, C.uint32_t(sem))
+ if retCode < 0 {
+ return syscall.Errno(-1 * retCode)
+ }
+
+ return nil
+}
+
// DeallocateSemaphore frees a semaphore in a shared-memory segment so it can be
// reallocated to another container or pod.
// The given semaphore must be already allocated, or an error will be returned.
diff --git a/libpod/lock/shm/shm_lock.h b/libpod/lock/shm/shm_lock.h
index 58e4297e2..759f8178a 100644
--- a/libpod/lock/shm/shm_lock.h
+++ b/libpod/lock/shm/shm_lock.h
@@ -39,6 +39,7 @@ shm_struct_t *setup_lock_shm(char *path, uint32_t num_locks, int *error_code);
shm_struct_t *open_lock_shm(char *path, uint32_t num_locks, int *error_code);
int32_t close_lock_shm(shm_struct_t *shm);
int64_t allocate_semaphore(shm_struct_t *shm);
+int32_t allocate_given_semaphore(shm_struct_t *shm, uint32_t sem_index);
int32_t deallocate_semaphore(shm_struct_t *shm, uint32_t sem_index);
int32_t deallocate_all_semaphores(shm_struct_t *shm);
int32_t lock_semaphore(shm_struct_t *shm, uint32_t sem_index);
diff --git a/libpod/lock/shm_lock_manager_linux.go b/libpod/lock/shm_lock_manager_linux.go
index 8678958ee..5f31939f8 100644
--- a/libpod/lock/shm_lock_manager_linux.go
+++ b/libpod/lock/shm_lock_manager_linux.go
@@ -57,6 +57,25 @@ func (m *SHMLockManager) AllocateLock() (Locker, error) {
return lock, nil
}
+// AllocateAndRetrieveLock allocates the lock with the given ID and returns it.
+// If the lock is already allocated, error.
+func (m *SHMLockManager) AllocateAndRetrieveLock(id uint32) (Locker, error) {
+ lock := new(SHMLock)
+ lock.lockID = id
+ lock.manager = m
+
+ if id >= m.locks.GetMaxLocks() {
+ return nil, errors.Wrapf(syscall.EINVAL, "lock ID %d is too large - max lock size is %d",
+ id, m.locks.GetMaxLocks()-1)
+ }
+
+ if err := m.locks.AllocateGivenSemaphore(id); err != nil {
+ return nil, err
+ }
+
+ return lock, nil
+}
+
// RetrieveLock retrieves a lock from the manager given its ID.
func (m *SHMLockManager) RetrieveLock(id uint32) (Locker, error) {
lock := new(SHMLock)
diff --git a/libpod/pod_internal.go b/libpod/pod_internal.go
index 25e4e77d7..1fcb5b1a6 100644
--- a/libpod/pod_internal.go
+++ b/libpod/pod_internal.go
@@ -56,7 +56,7 @@ func (p *Pod) refresh() error {
}
// Retrieve the pod's lock
- lock, err := p.runtime.lockManager.RetrieveLock(p.config.LockID)
+ lock, err := p.runtime.lockManager.AllocateAndRetrieveLock(p.config.LockID)
if err != nil {
return errors.Wrapf(err, "error retrieving lock for pod %s", p.ID())
}
diff --git a/libpod/runtime.go b/libpod/runtime.go
index 34b6ac74f..e6b84014e 100644
--- a/libpod/runtime.go
+++ b/libpod/runtime.go
@@ -922,7 +922,7 @@ func makeRuntime(ctx context.Context, runtime *Runtime) (err error) {
if os.IsNotExist(errors.Cause(err)) {
manager, err = lock.NewSHMLockManager(lockPath, runtime.config.NumLocks)
if err != nil {
- return err
+ return errors.Wrapf(err, "failed to get new shm lock manager")
}
} else if errors.Cause(err) == syscall.ERANGE && runtime.doRenumber {
logrus.Debugf("Number of locks does not match - removing old locks")
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index 48c254c0f..c7758055f 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -238,12 +238,15 @@ func (r *Runtime) newContainer(ctx context.Context, rSpec *spec.Spec, options ..
func (r *Runtime) RemoveContainer(ctx context.Context, c *Container, force bool, removeVolume bool) error {
r.lock.Lock()
defer r.lock.Unlock()
- return r.removeContainer(ctx, c, force, removeVolume)
+ return r.removeContainer(ctx, c, force, removeVolume, false)
}
-// Internal function to remove a container
-// Locks the container, but does not lock the runtime
-func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, removeVolume bool) error {
+// Internal function to remove a container.
+// Locks the container, but does not lock the runtime.
+// removePod is used only when removing pods. It instructs Podman to ignore
+// infra container protections, and *not* remove from the database (as pod
+// remove will handle that).
+func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool, removeVolume bool, removePod bool) error {
span, _ := opentracing.StartSpanFromContext(ctx, "removeContainer")
span.SetTag("type", "runtime")
defer span.Finish()
@@ -256,12 +259,14 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
}
}
- // We need to lock the pod before we lock the container
- // To avoid races around removing a container and the pod it is in
+ // We need to lock the pod before we lock the container.
+ // To avoid races around removing a container and the pod it is in.
+ // Don't need to do this in pod removal case - we're evicting the entire
+ // pod.
var pod *Pod
var err error
runtime := c.runtime
- if c.config.Pod != "" {
+ if c.config.Pod != "" && !removePod {
pod, err = r.state.Pod(c.config.Pod)
if err != nil {
return errors.Wrapf(err, "container %s is in pod %s, but pod cannot be retrieved", c.ID(), pod.ID())
@@ -280,8 +285,11 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
}
}
- c.lock.Lock()
- defer c.lock.Unlock()
+ // For pod removal, the container is already locked by the caller
+ if !removePod {
+ c.lock.Lock()
+ defer c.lock.Unlock()
+ }
if !r.valid {
return ErrRuntimeStopped
@@ -292,10 +300,15 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
return err
}
- if c.state.State == ContainerStatePaused {
- if !force {
- return errors.Wrapf(ErrCtrStateInvalid, "container %s is paused, cannot remove until unpaused", c.ID())
+ // If we're not force-removing, we need to check if we're in a good
+ // state to remove.
+ if !force {
+ if err := c.checkReadyForRemoval(); err != nil {
+ return err
}
+ }
+
+ if c.state.State == ContainerStatePaused {
if err := c.runtime.ociRuntime.killContainer(c, 9); err != nil {
return err
}
@@ -309,7 +322,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
}
// Check that the container's in a good state to be removed
- if c.state.State == ContainerStateRunning && force {
+ if c.state.State == ContainerStateRunning {
if err := r.ociRuntime.stopContainer(c, c.StopTimeout()); err != nil {
return errors.Wrapf(err, "cannot remove container %s as it could not be stopped", c.ID())
}
@@ -318,42 +331,41 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool,
if err := c.waitForExitFileAndSync(); err != nil {
return err
}
- } else if !(c.state.State == ContainerStateConfigured ||
- c.state.State == ContainerStateCreated ||
- c.state.State == ContainerStateStopped ||
- c.state.State == ContainerStateExited) {
- return errors.Wrapf(ErrCtrStateInvalid, "cannot remove container %s as it is %s - running or paused containers cannot be removed", c.ID(), c.state.State.String())
}
// Check that all of our exec sessions have finished
if len(c.state.ExecSessions) != 0 {
- if force {
- if err := r.ociRuntime.execStopContainer(c, c.StopTimeout()); err != nil {
- return err
- }
- } else {
- return errors.Wrapf(ErrCtrStateInvalid, "cannot remove container %s as it has active exec sessions", c.ID())
+ if err := r.ociRuntime.execStopContainer(c, c.StopTimeout()); err != nil {
+ return err
}
}
- // Check that no other containers depend on the container
- deps, err := r.state.ContainerInUse(c)
- if err != nil {
- return err
- }
- if len(deps) != 0 {
- depsStr := strings.Join(deps, ", ")
- return errors.Wrapf(ErrCtrExists, "container %s has dependent containers which must be removed before it: %s", c.ID(), depsStr)
+ // Check that no other containers depend on the container.
+ // Only used if not removing a pod - pods guarantee that all
+ // deps will be evicted at the same time.
+ if !removePod {
+ deps, err := r.state.ContainerInUse(c)
+ if err != nil {
+ return err
+ }
+ if len(deps) != 0 {
+ depsStr := strings.Join(deps, ", ")
+ return errors.Wrapf(ErrCtrExists, "container %s has dependent containers which must be removed before it: %s", c.ID(), depsStr)
+ }
}
var cleanupErr error
// Remove the container from the state
if c.config.Pod != "" {
- if err := r.state.RemoveContainerFromPod(pod, c); err != nil {
- if cleanupErr == nil {
- cleanupErr = err
- } else {
- logrus.Errorf("removing container from pod: %v", err)
+ // If we're removing the pod, the container will be evicted
+ // from the state elsewhere
+ if !removePod {
+ if err := r.state.RemoveContainerFromPod(pod, c); err != nil {
+ if cleanupErr == nil {
+ cleanupErr = err
+ } else {
+ logrus.Errorf("removing container from pod: %v", err)
+ }
}
}
} else {
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index 5e9f65acc..7cc7de270 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -48,7 +48,7 @@ func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool)
if len(imageCtrs) > 0 && len(img.Names()) <= 1 {
if force {
for _, ctr := range imageCtrs {
- if err := r.removeContainer(ctx, ctr, true, false); err != nil {
+ if err := r.removeContainer(ctx, ctr, true, false, false); err != nil {
return "", errors.Wrapf(err, "error removing image %s: container %s using image could not be removed", img.ID(), ctr.ID())
}
}
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index 0011c771a..456ad365f 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -11,6 +11,7 @@ import (
"github.com/containerd/cgroups"
"github.com/containers/libpod/libpod/events"
+ spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
@@ -148,117 +149,88 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
return errors.Wrapf(ErrCtrExists, "pod %s contains containers and cannot be removed", p.ID())
}
- // Go through and lock all containers so we can operate on them all at once
- dependencies := make(map[string][]string)
+ // Go through and lock all containers so we can operate on them all at
+ // once.
+ // First loop also checks that we are ready to go ahead and remove.
for _, ctr := range ctrs {
- ctr.lock.Lock()
- defer ctr.lock.Unlock()
+ ctrLock := ctr.lock
+ ctrLock.Lock()
+ defer ctrLock.Unlock()
+
+ // If we're force-removing, no need to check status.
+ if force {
+ continue
+ }
// Sync all containers
if err := ctr.syncContainer(); err != nil {
return err
}
- // Check if the container is in a good state to be removed
- if ctr.state.State == ContainerStatePaused {
- return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains paused container %s, cannot remove", p.ID(), ctr.ID())
- }
-
- if ctr.state.State == ContainerStateUnknown {
- return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s with invalid state", p.ID(), ctr.ID())
- }
-
- // If the container is running and force is not set we can't do anything
- if ctr.state.State == ContainerStateRunning && !force {
- return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s which is running", p.ID(), ctr.ID())
- }
-
- // If the container has active exec sessions and force is not set we can't do anything
- if len(ctr.state.ExecSessions) != 0 && !force {
- return errors.Wrapf(ErrCtrStateInvalid, "pod %s contains container %s which has active exec sessions", p.ID(), ctr.ID())
- }
-
- deps, err := r.state.ContainerInUse(ctr)
- if err != nil {
- return err
+ // Ensure state appropriate for removal
+ if err := ctr.checkReadyForRemoval(); err != nil {
+ return errors.Wrapf(err, "pod %s has containers that are not ready to be removed", p.ID())
}
- dependencies[ctr.ID()] = deps
}
- // Check if containers have dependencies
- // If they do, and the dependencies are not in the pod, error
- for ctr, deps := range dependencies {
- for _, dep := range deps {
- if _, ok := dependencies[dep]; !ok {
- return errors.Wrapf(ErrCtrExists, "container %s depends on container %s not in pod %s", ctr, dep, p.ID())
+ var removalErr error
+
+ // We're going to be removing containers.
+ // If we are CGroupfs cgroup driver, to avoid races, we need to hit
+ // the pod and conmon CGroups with a PID limit to prevent them from
+ // spawning any further processes (particularly cleanup processes) which
+ // would prevent removing the CGroups.
+ if p.runtime.config.CgroupManager == CgroupfsCgroupsManager {
+ // Get the conmon CGroup
+ v1CGroups := GetV1CGroups(getExcludedCGroups())
+ conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon")
+ conmonCgroup, err := cgroups.Load(v1CGroups, cgroups.StaticPath(conmonCgroupPath))
+ if err != nil && err != cgroups.ErrCgroupDeleted {
+ if removalErr == nil {
+ removalErr = errors.Wrapf(err, "error retrieving pod %s conmon cgroup %s", p.ID(), conmonCgroupPath)
+ } else {
+ logrus.Errorf("Error retrieving pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err)
}
}
- }
- // First loop through all containers and stop them
- // Do not remove in this loop to ensure that we don't remove unless all
- // containers are in a good state
- if force {
- for _, ctr := range ctrs {
- // If force is set and the container is running, stop it now
- if ctr.state.State == ContainerStateRunning {
- if err := r.ociRuntime.stopContainer(ctr, ctr.StopTimeout()); err != nil {
- return errors.Wrapf(err, "error stopping container %s to remove pod %s", ctr.ID(), p.ID())
- }
-
- // Sync again to pick up stopped state
- if err := ctr.syncContainer(); err != nil {
- return err
- }
- }
- // If the container has active exec sessions, stop them now
- if len(ctr.state.ExecSessions) != 0 {
- if err := r.ociRuntime.execStopContainer(ctr, ctr.StopTimeout()); err != nil {
- return err
+ // New resource limits
+ resLimits := new(spec.LinuxResources)
+ resLimits.Pids = new(spec.LinuxPids)
+ resLimits.Pids.Limit = 1 // Inhibit forks with very low pids limit
+
+ // Don't try if we failed to retrieve the cgroup
+ if err == nil {
+ if err := conmonCgroup.Update(resLimits); err != nil {
+ if removalErr == nil {
+ removalErr = errors.Wrapf(err, "error updating pod %s conmon group", p.ID())
+ } else {
+ logrus.Errorf("Error updating pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err)
}
}
}
}
- // Start removing containers
- // We can remove containers even if they have dependencies now
- // As we have guaranteed their dependencies are in the pod
+ // Second loop - all containers are good, so we should be clear to
+ // remove.
for _, ctr := range ctrs {
- // Clean up network namespace, cgroups, mounts
- if err := ctr.cleanup(ctx); err != nil {
- return err
- }
-
- // Stop container's storage
- if err := ctr.teardownStorage(); err != nil {
- return err
- }
-
- // Delete the container from runtime (only if we are not
- // ContainerStateConfigured)
- if ctr.state.State != ContainerStateConfigured &&
- ctr.state.State != ContainerStateExited {
- if err := ctr.delete(ctx); err != nil {
- return err
+ // Remove the container
+ if err := r.removeContainer(ctx, ctr, force, true, true); err != nil {
+ if removalErr != nil {
+ removalErr = err
+ } else {
+ logrus.Errorf("Error removing container %s from pod %s: %v", ctr.ID(), p.ID(), err)
}
}
-
- // Free the container's lock
- if err := ctr.lock.Free(); err != nil {
- return err
- }
}
- // Remove containers from the state
+ // Remove all containers in the pod from the state.
if err := r.state.RemovePodContainers(p); err != nil {
+ // If this fails, there isn't much more we can do.
+ // The containers in the pod are unusable, but they still exist,
+ // so pod removal will fail.
return err
}
- // Mark containers invalid
- for _, ctr := range ctrs {
- ctr.valid = false
- }
-
// Remove pod cgroup, if present
if p.state.CgroupPath != "" {
logrus.Debugf("Removing pod cgroup %s", p.state.CgroupPath)
@@ -266,10 +238,11 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
switch p.runtime.config.CgroupManager {
case SystemdCgroupsManager:
if err := deleteSystemdCgroup(p.state.CgroupPath); err != nil {
- // The pod is already almost gone.
- // No point in hard-failing if we fail
- // this bit of cleanup.
- logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err)
+ if removalErr == nil {
+ removalErr = errors.Wrapf(err, "error removing pod %s cgroup", p.ID())
+ } else {
+ logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err)
+ }
}
case CgroupfsCgroupsManager:
// Delete the cgroupfs cgroup
@@ -280,34 +253,60 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon")
conmonCgroup, err := cgroups.Load(v1CGroups, cgroups.StaticPath(conmonCgroupPath))
if err != nil && err != cgroups.ErrCgroupDeleted {
- return err
+ if removalErr == nil {
+ removalErr = errors.Wrapf(err, "error retrieving pod %s conmon cgroup", p.ID())
+ } else {
+ logrus.Debugf("Error retrieving pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err)
+ }
}
if err == nil {
if err := conmonCgroup.Delete(); err != nil {
- logrus.Errorf("Error deleting pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err)
+ if removalErr == nil {
+ removalErr = errors.Wrapf(err, "error removing pod %s conmon cgroup", p.ID())
+ } else {
+ logrus.Errorf("Error deleting pod %s conmon cgroup %s: %v", p.ID(), conmonCgroupPath, err)
+ }
}
}
cgroup, err := cgroups.Load(v1CGroups, cgroups.StaticPath(p.state.CgroupPath))
if err != nil && err != cgroups.ErrCgroupDeleted {
- return err
+ if removalErr == nil {
+ removalErr = errors.Wrapf(err, "error retrieving pod %s cgroup", p.ID())
+ } else {
+ logrus.Errorf("Error retrieving pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err)
+ }
}
if err == nil {
if err := cgroup.Delete(); err != nil {
- logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err)
+ if removalErr == nil {
+ removalErr = errors.Wrapf(err, "error removing pod %s cgroup", p.ID())
+ } else {
+ logrus.Errorf("Error deleting pod %s cgroup %s: %v", p.ID(), p.state.CgroupPath, err)
+ }
}
}
default:
- return errors.Wrapf(ErrInvalidArg, "unknown cgroups manager %s specified", p.runtime.config.CgroupManager)
+ // This should be caught much earlier, but let's still
+ // keep going so we make sure to evict the pod before
+ // ending up with an inconsistent state.
+ if removalErr == nil {
+ removalErr = errors.Wrapf(ErrInternal, "unrecognized cgroup manager %s when removing pod %s cgroups", p.runtime.config.CgroupManager, p.ID())
+ } else {
+ logrus.Errorf("Unknown cgroups manager %s specified - cannot remove pod %s cgroup", p.runtime.config.CgroupManager, p.ID())
+ }
}
}
// Remove pod from state
if err := r.state.RemovePod(p); err != nil {
+ if removalErr != nil {
+ logrus.Errorf("%v", removalErr)
+ }
return err
}
// Mark pod invalid
p.valid = false
p.newPodEvent(events.Remove)
- return nil
+ return removalErr
}
diff --git a/libpod/runtime_volume_linux.go b/libpod/runtime_volume_linux.go
index 40040fc52..a326ed0e0 100644
--- a/libpod/runtime_volume_linux.go
+++ b/libpod/runtime_volume_linux.go
@@ -116,7 +116,7 @@ func (r *Runtime) removeVolume(ctx context.Context, v *Volume, force bool) error
// containers?
// I'm inclined to say no, in case someone accidentally
// wipes a container they're using...
- if err := r.removeContainer(ctx, ctr, false, false); err != nil {
+ if err := r.removeContainer(ctx, ctr, false, false, false); err != nil {
return errors.Wrapf(err, "error removing container %s that depends on volume %s", ctr.ID(), v.Name())
}
}
diff --git a/pkg/adapter/client.go b/pkg/adapter/client.go
index 6512a5952..f672a92a6 100644
--- a/pkg/adapter/client.go
+++ b/pkg/adapter/client.go
@@ -3,30 +3,45 @@
package adapter
import (
+ "fmt"
"os"
- "github.com/sirupsen/logrus"
+ "github.com/pkg/errors"
"github.com/varlink/go/varlink"
)
-// DefaultAddress is the default address of the varlink socket
-const DefaultAddress = "unix:/run/podman/io.podman"
+type VarlinkConnectionInfo struct {
+ RemoteUserName string
+ RemoteHost string
+ VarlinkAddress string
+}
// Connect provides a varlink connection
func (r RemoteRuntime) Connect() (*varlink.Connection, error) {
- 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)
+ var (
+ err error
+ connection *varlink.Connection
+ )
+
+ logLevel := r.cmd.LogLevel
+
+ // I'm leaving this here for now as a document of the birdge format. It can be removed later once the bridge
+ // function is more flushed out.
+ //bridge := `ssh -T root@192.168.122.1 "/usr/bin/varlink -A '/usr/bin/podman varlink \$VARLINK_ADDRESS' bridge"`
+ if len(r.cmd.RemoteHost) > 0 {
+ // The user has provided a remote host endpoint
+ if len(r.cmd.RemoteUserName) < 1 {
+ return nil, errors.New("you must provide a username when providing a remote host name")
+ }
+ bridge := fmt.Sprintf(`ssh -T %s@%s /usr/bin/varlink -A \'/usr/bin/podman --log-level=%s varlink \\\$VARLINK_ADDRESS\' bridge`, r.cmd.RemoteUserName, r.cmd.RemoteHost, logLevel)
+ connection, err = varlink.NewBridge(bridge)
+ } else if bridge := os.Getenv("PODMAN_VARLINK_BRIDGE"); 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 {
diff --git a/pkg/adapter/client_config.go b/pkg/adapter/client_config.go
new file mode 100644
index 000000000..d165ef1cc
--- /dev/null
+++ b/pkg/adapter/client_config.go
@@ -0,0 +1,4 @@
+package adapter
+
+// DefaultAddress is the default address of the varlink socket
+const DefaultAddress = "unix:/run/podman/io.podman"
diff --git a/pkg/adapter/containers.go b/pkg/adapter/containers.go
index 0721af773..ff7b6377a 100644
--- a/pkg/adapter/containers.go
+++ b/pkg/adapter/containers.go
@@ -413,7 +413,9 @@ func (r *LocalRuntime) Run(ctx context.Context, c *cliconfig.RunValues, exitCode
}
if c.IsSet("rm") {
- r.Runtime.RemoveContainer(ctx, ctr, false, true)
+ if err := r.Runtime.RemoveContainer(ctx, ctr, false, false); err != nil {
+ logrus.Errorf("Error removing container %s: %v", ctr.ID(), err)
+ }
}
return exitCode, nil
@@ -965,8 +967,9 @@ func (r *LocalRuntime) CleanupContainers(ctx context.Context, cli *cliconfig.Cle
return ok, failures, nil
}
+// Only used when cleaning up containers
func removeContainer(ctx context.Context, ctr *libpod.Container, runtime *LocalRuntime) error {
- if err := runtime.RemoveContainer(ctx, ctr, false, true); err != nil {
+ if err := runtime.RemoveContainer(ctx, ctr, false, false); err != nil {
return errors.Wrapf(err, "failed to cleanup and remove container %v", ctr.ID())
}
return nil
@@ -1022,3 +1025,8 @@ func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (stri
}
return systemdgen.CreateSystemdUnitAsString(name, ctr.ID(), c.RestartPolicy, ctr.Config().StaticDir, timeout)
}
+
+// GetNamespaces returns namespace information about a container for PS
+func (r *LocalRuntime) GetNamespaces(container shared.PsContainerOutput) *shared.Namespace {
+ return shared.GetNamespaces(container.Pid)
+}
diff --git a/pkg/adapter/containers_remote.go b/pkg/adapter/containers_remote.go
index 201249fc3..63b0f9d2f 100644
--- a/pkg/adapter/containers_remote.go
+++ b/pkg/adapter/containers_remote.go
@@ -234,15 +234,25 @@ func (r *LocalRuntime) StopContainers(ctx context.Context, cli *cliconfig.StopVa
ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
if err != nil {
- return ok, failures, err
+ return ok, failures, TranslateError(err)
}
for _, id := range ids {
- stopped, err := iopodman.StopContainer().Call(r.Conn, id, int64(cli.Timeout))
- if err != nil {
+ if _, err := iopodman.StopContainer().Call(r.Conn, id, int64(cli.Timeout)); err != nil {
+ transError := TranslateError(err)
+ if errors.Cause(transError) == libpod.ErrCtrStopped {
+ ok = append(ok, id)
+ continue
+ }
+ if errors.Cause(transError) == libpod.ErrCtrStateInvalid && cli.All {
+ ok = append(ok, id)
+ continue
+ }
failures[id] = err
} else {
- ok = append(ok, stopped)
+ // We should be using ID here because in varlink, only successful returns
+ // include the string id
+ ok = append(ok, id)
}
}
return ok, failures, nil
@@ -310,7 +320,7 @@ func (r *LocalRuntime) KillContainers(ctx context.Context, cli *cliconfig.KillVa
func (r *LocalRuntime) RemoveContainers(ctx context.Context, cli *cliconfig.RmValues) ([]string, map[string]error, error) {
ids, err := iopodman.GetContainersByContext().Call(r.Conn, cli.All, cli.Latest, cli.InputArgs)
if err != nil {
- return nil, nil, err
+ return nil, nil, TranslateError(err)
}
var (
@@ -961,3 +971,18 @@ func (r *LocalRuntime) Port(c *cliconfig.PortValues) ([]*Container, error) {
func (r *LocalRuntime) GenerateSystemd(c *cliconfig.GenerateSystemdValues) (string, error) {
return iopodman.GenerateSystemd().Call(r.Conn, c.InputArgs[0], c.RestartPolicy, int64(c.StopTimeout), c.Name)
}
+
+// GetNamespaces returns namespace information about a container for PS
+func (r *LocalRuntime) GetNamespaces(container shared.PsContainerOutput) *shared.Namespace {
+ ns := shared.Namespace{
+ PID: container.PID,
+ Cgroup: container.Cgroup,
+ IPC: container.IPC,
+ MNT: container.MNT,
+ NET: container.NET,
+ PIDNS: container.PIDNS,
+ User: container.User,
+ UTS: container.UTS,
+ }
+ return &ns
+}
diff --git a/pkg/adapter/errors.go b/pkg/adapter/errors.go
new file mode 100644
index 000000000..7fbbabd93
--- /dev/null
+++ b/pkg/adapter/errors.go
@@ -0,0 +1,31 @@
+// +build remoteclient
+
+package adapter
+
+import (
+ iopodman "github.com/containers/libpod/cmd/podman/varlink"
+ "github.com/containers/libpod/libpod"
+ "github.com/pkg/errors"
+)
+
+// TranslateMapErrors translates the errors a typical podman output struct
+// from varlink errors to libpod errors
+func TranslateMapErrors(failures map[string]error) map[string]error {
+ for k, v := range failures {
+ failures[k] = TranslateError(v)
+ }
+ return failures
+}
+
+// TranslateError converts a single varlink error to a libpod error
+func TranslateError(err error) error {
+ switch err.(type) {
+ case *iopodman.ContainerNotFound:
+ return errors.Wrap(libpod.ErrNoSuchCtr, err.Error())
+ case *iopodman.ErrCtrStopped:
+ return errors.Wrap(libpod.ErrCtrStopped, err.Error())
+ case *iopodman.InvalidState:
+ return errors.Wrap(libpod.ErrCtrStateInvalid, err.Error())
+ }
+ return err
+}
diff --git a/pkg/adapter/info_remote.go b/pkg/adapter/info_remote.go
index 3b691ed17..3b2d02a5a 100644
--- a/pkg/adapter/info_remote.go
+++ b/pkg/adapter/info_remote.go
@@ -20,12 +20,7 @@ func (r RemoteRuntime) Info() ([]libpod.InfoData, error) {
registries := make(map[string]interface{})
insecureRegistries := make(map[string]interface{})
- conn, err := r.Connect()
- if err != nil {
- return nil, err
- }
- defer conn.Close()
- info, err := iopodman.GetInfo().Call(conn)
+ info, err := iopodman.GetInfo().Call(r.Conn)
if err != nil {
return nil, err
}
diff --git a/pkg/adapter/pods_remote.go b/pkg/adapter/pods_remote.go
index 7cf38aac0..e2c97c36a 100644
--- a/pkg/adapter/pods_remote.go
+++ b/pkg/adapter/pods_remote.go
@@ -172,11 +172,15 @@ func (r *LocalRuntime) StartPods(ctx context.Context, cli *cliconfig.PodStartVal
// CreatePod creates a pod for the remote client over a varlink connection
func (r *LocalRuntime) CreatePod(ctx context.Context, cli *cliconfig.PodCreateValues, labels map[string]string) (string, error) {
+ var share []string
+ if cli.Share != "" {
+ share = strings.Split(cli.Share, ",")
+ }
pc := iopodman.PodCreate{
Name: cli.Name,
CgroupParent: cli.CgroupParent,
Labels: labels,
- Share: strings.Split(cli.Share, ","),
+ Share: share,
Infra: cli.Infra,
InfraCommand: cli.InfraCommand,
InfraImage: cli.InfraCommand,
diff --git a/pkg/adapter/runtime.go b/pkg/adapter/runtime.go
index 0d840d65b..21613c425 100644
--- a/pkg/adapter/runtime.go
+++ b/pkg/adapter/runtime.go
@@ -5,12 +5,13 @@ package adapter
import (
"bufio"
"context"
- "github.com/containers/libpod/cmd/podman/shared"
"io"
"io/ioutil"
"os"
"text/template"
+ "github.com/containers/libpod/cmd/podman/shared"
+
"github.com/containers/buildah"
"github.com/containers/buildah/imagebuildah"
"github.com/containers/buildah/pkg/parse"
@@ -392,3 +393,8 @@ func (r *LocalRuntime) GetPodsByStatus(statuses []string) ([]*libpod.Pod, error)
return pods, nil
}
+
+// GetVersion is an alias to satisfy interface{}
+func (r *LocalRuntime) GetVersion() (libpod.Version, error) {
+ return libpod.GetVersion()
+}
diff --git a/pkg/adapter/runtime_remote.go b/pkg/adapter/runtime_remote.go
index 4986d16f7..e86287462 100644
--- a/pkg/adapter/runtime_remote.go
+++ b/pkg/adapter/runtime_remote.go
@@ -9,12 +9,13 @@ import (
"fmt"
"io"
"io/ioutil"
- v1 "k8s.io/api/core/v1"
"os"
"strings"
"text/template"
"time"
+ v1 "k8s.io/api/core/v1"
+
"github.com/containers/buildah/imagebuildah"
"github.com/containers/image/docker/reference"
"github.com/containers/image/types"
@@ -38,6 +39,7 @@ type RemoteImageRuntime struct{}
type RemoteRuntime struct {
Conn *varlink.Connection
Remote bool
+ cmd cliconfig.MainFlags
}
// LocalRuntime describes a typical libpod runtime
@@ -47,17 +49,17 @@ type LocalRuntime struct {
// GetRuntime returns a LocalRuntime struct with the actual runtime embedded in it
func GetRuntime(ctx context.Context, c *cliconfig.PodmanCommand) (*LocalRuntime, error) {
- runtime := RemoteRuntime{}
+ runtime := RemoteRuntime{
+ Remote: true,
+ cmd: c.GlobalFlags,
+ }
conn, err := runtime.Connect()
if err != nil {
return nil, err
}
-
+ runtime.Conn = conn
return &LocalRuntime{
- &RemoteRuntime{
- Conn: conn,
- Remote: true,
- },
+ &runtime,
}, nil
}
@@ -414,19 +416,19 @@ func (r *LocalRuntime) Build(ctx context.Context, c *cliconfig.BuildValues, opti
Compression: string(options.Compression),
DefaultsMountFilePath: options.DefaultMountsFilePath,
Dockerfiles: dockerfiles,
- //Err: string(options.Err),
+ // Err: string(options.Err),
ForceRmIntermediateCtrs: options.ForceRmIntermediateCtrs,
Iidfile: options.IIDFile,
Label: options.Labels,
Layers: options.Layers,
Nocache: options.NoCache,
- //Out:
+ // Out:
Output: options.Output,
OutputFormat: options.OutputFormat,
PullPolicy: options.PullPolicy.String(),
Quiet: options.Quiet,
RemoteIntermediateCtrs: options.RemoveIntermediateCtrs,
- //ReportWriter:
+ // ReportWriter:
RuntimeArgs: options.RuntimeArgs,
SignaturePolicyPath: options.SignaturePolicyPath,
Squash: options.Squash,
@@ -610,7 +612,7 @@ func (r *LocalRuntime) InspectVolumes(ctx context.Context, c *cliconfig.VolumeIn
return varlinkVolumeToVolume(r, reply), nil
}
-//Volumes returns a slice of adapter.volumes based on information about libpod
+// Volumes returns a slice of adapter.volumes based on information about libpod
// volumes over a varlink connection
func (r *LocalRuntime) Volumes(ctx context.Context) ([]*Volume, error) {
reply, err := iopodman.GetVolumes().Call(r.Conn, []string{}, true)
@@ -906,3 +908,29 @@ func (r *LocalRuntime) GetContainersByContext(all bool, latest bool, namesOrIDs
}
return containers, nil
}
+
+// GetVersion returns version information from service
+func (r *LocalRuntime) GetVersion() (libpod.Version, error) {
+ version, goVersion, gitCommit, built, osArch, apiVersion, err := iopodman.GetVersion().Call(r.Conn)
+ if err != nil {
+ return libpod.Version{}, errors.Wrapf(err, "Unable to obtain server version information")
+ }
+
+ var buildTime int64
+ if built != "" {
+ t, err := time.Parse(time.RFC3339, built)
+ if err != nil {
+ return libpod.Version{}, nil
+ }
+ buildTime = t.Unix()
+ }
+
+ return libpod.Version{
+ RemoteAPIVersion: apiVersion,
+ Version: version,
+ GoVersion: goVersion,
+ GitCommit: gitCommit,
+ Built: buildTime,
+ OsArch: osArch,
+ }, nil
+}
diff --git a/pkg/systemdgen/systemdgen_test.go b/pkg/systemdgen/systemdgen_test.go
new file mode 100644
index 000000000..f2f49e750
--- /dev/null
+++ b/pkg/systemdgen/systemdgen_test.go
@@ -0,0 +1,120 @@
+package systemdgen
+
+import (
+ "testing"
+)
+
+func TestValidateRestartPolicy(t *testing.T) {
+ type args struct {
+ restart string
+ }
+ tests := []struct {
+ name string
+ args args
+ wantErr bool
+ }{
+ {"good-on", args{restart: "no"}, false},
+ {"good-on-success", args{restart: "on-success"}, false},
+ {"good-on-failure", args{restart: "on-failure"}, false},
+ {"good-on-abnormal", args{restart: "on-abnormal"}, false},
+ {"good-on-watchdog", args{restart: "on-watchdog"}, false},
+ {"good-on-abort", args{restart: "on-abort"}, false},
+ {"good-always", args{restart: "always"}, false},
+ {"fail", args{restart: "foobar"}, true},
+ {"failblank", args{restart: ""}, true},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if err := ValidateRestartPolicy(tt.args.restart); (err != nil) != tt.wantErr {
+ t.Errorf("ValidateRestartPolicy() error = %v, wantErr %v", err, tt.wantErr)
+ }
+ })
+ }
+}
+
+func TestCreateSystemdUnitAsString(t *testing.T) {
+ goodID := `[Unit]
+Description=639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401 Podman Container
+[Service]
+Restart=always
+ExecStart=/usr/bin/podman start 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+ExecStop=/usr/bin/podman stop -t 10 639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401
+KillMode=none
+Type=forking
+PIDFile=/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid
+[Install]
+WantedBy=multi-user.target`
+
+ goodName := `[Unit]
+Description=foobar Podman Container
+[Service]
+Restart=always
+ExecStart=/usr/bin/podman start foobar
+ExecStop=/usr/bin/podman stop -t 10 foobar
+KillMode=none
+Type=forking
+PIDFile=/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401.pid
+[Install]
+WantedBy=multi-user.target`
+
+ type args struct {
+ name string
+ cid string
+ restart string
+ pidPath string
+ stopTimeout int
+ }
+ tests := []struct {
+ name string
+ args args
+ want string
+ wantErr bool
+ }{
+
+ {"good with id",
+ args{
+ "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ "always",
+ "/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/",
+ 10,
+ },
+ goodID,
+ false,
+ },
+ {"good with name",
+ args{
+ "foobar",
+ "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ "always",
+ "/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/",
+ 10,
+ },
+ goodName,
+ false,
+ },
+ {"bad restart policy",
+ args{
+ "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ "639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401",
+ "never",
+ "/var/lib/containers/storage/overlay-containers/639c53578af4d84b8800b4635fa4e680ee80fd67e0e6a2d4eea48d1e3230f401/userdata/",
+ 10,
+ },
+ "",
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ got, err := CreateSystemdUnitAsString(tt.args.name, tt.args.cid, tt.args.restart, tt.args.pidPath, tt.args.stopTimeout)
+ if (err != nil) != tt.wantErr {
+ t.Errorf("CreateSystemdUnitAsString() error = %v, wantErr %v", err, tt.wantErr)
+ return
+ }
+ if got != tt.want {
+ t.Errorf("CreateSystemdUnitAsString() = %v, want %v", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/pkg/varlinkapi/attach.go b/pkg/varlinkapi/attach.go
index 6c62d3514..2234899a5 100644
--- a/pkg/varlinkapi/attach.go
+++ b/pkg/varlinkapi/attach.go
@@ -60,6 +60,7 @@ func (i *LibpodAPI) Attach(call iopodman.VarlinkCall, name string, detachKeys st
if !start && state != libpod.ContainerStateRunning {
return call.ReplyErrorOccurred("container must be running to attach")
}
+ call.Reply(nil)
reader, writer, _, pw, streams := setupStreams(call)
go func() {
diff --git a/pkg/varlinkapi/containers.go b/pkg/varlinkapi/containers.go
index c8be41636..8611a1a7d 100644
--- a/pkg/varlinkapi/containers.go
+++ b/pkg/varlinkapi/containers.go
@@ -119,6 +119,9 @@ func (i *LibpodAPI) GetContainersByContext(call iopodman.VarlinkCall, all, lates
ctrs, err := shortcuts.GetContainersByContext(all, latest, input, i.Runtime)
if err != nil {
+ if errors.Cause(err) == libpod.ErrNoSuchCtr {
+ return call.ReplyContainerNotFound("", err.Error())
+ }
return call.ReplyErrorOccurred(err.Error())
}
@@ -359,7 +362,11 @@ func (i *LibpodAPI) StartContainer(call iopodman.VarlinkCall, name string) error
if state == libpod.ContainerStateRunning || state == libpod.ContainerStatePaused {
return call.ReplyErrorOccurred("container is already running or paused")
}
- if err := ctr.Start(getContext(), false); err != nil {
+ recursive := false
+ if ctr.PodID() != "" {
+ recursive = true
+ }
+ if err := ctr.Start(getContext(), recursive); err != nil {
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyStartContainer(ctr.ID())
@@ -386,7 +393,13 @@ func (i *LibpodAPI) StopContainer(call iopodman.VarlinkCall, name string, timeou
if err != nil {
return call.ReplyContainerNotFound(name, err.Error())
}
- if err := ctr.StopWithTimeout(uint(timeout)); err != nil && err != libpod.ErrCtrStopped {
+ if err := ctr.StopWithTimeout(uint(timeout)); err != nil {
+ if errors.Cause(err) == libpod.ErrCtrStopped {
+ return call.ReplyErrCtrStopped(ctr.ID())
+ }
+ if errors.Cause(err) == libpod.ErrCtrStateInvalid {
+ return call.ReplyInvalidState(ctr.ID(), err.Error())
+ }
return call.ReplyErrorOccurred(err.Error())
}
return call.ReplyStopContainer(ctr.ID())
diff --git a/pkg/varlinkapi/pods.go b/pkg/varlinkapi/pods.go
index f34375bf5..c0fd8b1f7 100644
--- a/pkg/varlinkapi/pods.go
+++ b/pkg/varlinkapi/pods.go
@@ -6,7 +6,6 @@ import (
"encoding/json"
"fmt"
"github.com/containers/libpod/pkg/adapter/shortcuts"
- "github.com/containers/libpod/pkg/rootless"
"syscall"
"github.com/containers/libpod/cmd/podman/shared"
@@ -37,12 +36,9 @@ func (i *LibpodAPI) CreatePod(call iopodman.VarlinkCall, create iopodman.PodCrea
if !create.Infra {
return call.ReplyErrorOccurred("you must have an infra container to publish port bindings to the host")
}
- if rootless.IsRootless() {
- return call.ReplyErrorOccurred("rootless networking does not allow port binding to the host")
- }
portBindings, err := shared.CreatePortBindings(create.Publish)
if err != nil {
- return err
+ return call.ReplyErrorOccurred(err.Error())
}
options = append(options, libpod.WithInfraContainerPorts(portBindings))
diff --git a/pkg/varlinkapi/system.go b/pkg/varlinkapi/system.go
index 7f436a954..59bfec75b 100644
--- a/pkg/varlinkapi/system.go
+++ b/pkg/varlinkapi/system.go
@@ -86,15 +86,18 @@ func (i *LibpodAPI) GetInfo(call iopodman.VarlinkCall) error {
Graph_status: graphStatus,
}
- registriesInterface := info[2].Data["registries"]
- insecureRegistriesInterface := info[3].Data["registries"]
- if registriesInterface != nil {
- registries = registriesInterface.([]string)
+ if len(info) > 2 {
+ registriesInterface := info[2].Data["registries"]
+ if registriesInterface != nil {
+ registries = registriesInterface.([]string)
+ }
}
- if insecureRegistriesInterface != nil {
- insecureRegistries = insecureRegistriesInterface.([]string)
+ if len(info) > 3 {
+ insecureRegistriesInterface := info[3].Data["registries"]
+ if insecureRegistriesInterface != nil {
+ insecureRegistries = insecureRegistriesInterface.([]string)
+ }
}
-
podmanInfo.Store = infoStore
podmanInfo.Podman = pmaninfo
podmanInfo.Registries = registries
diff --git a/test/e2e/common_test.go b/test/e2e/common_test.go
index a6fc211f6..3c7675b35 100644
--- a/test/e2e/common_test.go
+++ b/test/e2e/common_test.go
@@ -264,9 +264,14 @@ func PodmanTestCreateUtil(tempDir string, remote bool) *PodmanTestIntegration {
}
if remote {
p.PodmanTest.RemotePodmanBinary = podmanRemoteBinary
+ uuid := stringid.GenerateNonCryptoID()
if !rootless.IsRootless() {
- uuid := stringid.GenerateNonCryptoID()
p.VarlinkEndpoint = fmt.Sprintf("unix:/run/podman/io.podman-%s", uuid)
+ } else {
+ runtimeDir := os.Getenv("XDG_RUNTIME_DIR")
+ socket := fmt.Sprintf("io.podman-%s", uuid)
+ fqpath := filepath.Join(runtimeDir, socket)
+ p.VarlinkEndpoint = fmt.Sprintf("unix:%s", fqpath)
}
}
diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go
index 591f533d6..273668f35 100644
--- a/test/e2e/cp_test.go
+++ b/test/e2e/cp_test.go
@@ -7,6 +7,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "strings"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
@@ -58,21 +59,12 @@ var _ = Describe("Podman cp", func() {
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"start", "-a", name})
- session.WaitWithDefaultTimeout()
-
- Expect(session.ExitCode()).To(Equal(0))
- Expect(session.OutputToString()).To(Equal("copy from host to container"))
-
session = podmanTest.Podman([]string{"cp", name + ":foo", filepath.Join(path, "cp_from_container")})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- c := exec.Command("cat", filepath.Join(path, "cp_from_container"))
- output, err := c.Output()
- if err != nil {
- os.Exit(1)
- }
- Expect(string(output)).To(Equal("copy from host to container"))
+
+ os.Remove("cp_from_container")
+ os.Remove("cp_test.txt")
})
It("podman cp file to dir", func() {
@@ -89,28 +81,18 @@ var _ = Describe("Podman cp", func() {
session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foodir/"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"ps", "-a", "-q"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
name := session.OutputToString()
session = podmanTest.Podman([]string{"cp", filepath.Join(path, "cp_test.txt"), name + ":foodir/"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"start", "-a", name})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- Expect(session.OutputToString()).To(Equal("cp_test.txt"))
session = podmanTest.Podman([]string{"cp", name + ":foodir/cp_test.txt", path + "/receive/"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- c := exec.Command("cat", filepath.Join(path, "receive", "cp_test.txt"))
- output, err := c.Output()
- if err != nil {
- os.Exit(1)
- }
- Expect(string(output)).To(Equal("copy from host to container directory"))
+
+ os.Remove("cp_test.txt")
+ os.RemoveAll("receive")
})
It("podman cp dir to dir", func() {
@@ -132,17 +114,50 @@ var _ = Describe("Podman cp", func() {
session = podmanTest.Podman([]string{"cp", testDirPath, name + ":/foodir"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"start", "-a", name})
+
+ session = podmanTest.Podman([]string{"cp", testDirPath, name + ":/foodir"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- Expect(len(session.OutputToStringArray())).To(Equal(0))
- session = podmanTest.Podman([]string{"cp", testDirPath, name + ":/foodir"})
+ os.RemoveAll(testDirPath)
+ })
+
+ It("podman cp stdin/stdout", func() {
+ path, err := os.Getwd()
+ if err != nil {
+ os.Exit(1)
+ }
+ testDirPath := filepath.Join(path, "TestDir")
+ err = os.Mkdir(testDirPath, 0777)
+ if err != nil {
+ os.Exit(1)
+ }
+ cmd := exec.Command("tar", "-zcvf", "file.tar.gz", testDirPath)
+ _, err = cmd.Output()
+ if err != nil {
+ os.Exit(1)
+ }
+
+ session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foo"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ name := session.OutputToString()
+
+ data, err := ioutil.ReadFile("foo.tar.gz")
+ reader := strings.NewReader(string(data))
+ cmd.Stdin = reader
+ session = podmanTest.Podman([]string{"cp", "-", name + ":/foo"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- session = podmanTest.Podman([]string{"start", "-a", name})
+
+ session = podmanTest.Podman([]string{"cp", "file.tar.gz", name + ":/foo.tar.gz"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
- Expect(session.OutputToString()).To(Equal("TestDir"))
+ session = podmanTest.Podman([]string{"cp", name + ":/foo.tar.gz", "-"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ os.Remove("file.tar.gz")
+ os.RemoveAll(testDirPath)
})
})
diff --git a/test/e2e/create_test.go b/test/e2e/create_test.go
index 105cba37c..f3367337e 100644
--- a/test/e2e/create_test.go
+++ b/test/e2e/create_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/diff_test.go b/test/e2e/diff_test.go
index fba65823e..920b920c0 100644
--- a/test/e2e/diff_test.go
+++ b/test/e2e/diff_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
@@ -63,6 +61,7 @@ var _ = Describe("Podman diff", func() {
})
It("podman diff container and committed image", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"run", "--name=diff-test", ALPINE, "touch", "/tmp/diff-test"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/images_test.go b/test/e2e/images_test.go
index 5a299fe75..bec6e304b 100644
--- a/test/e2e/images_test.go
+++ b/test/e2e/images_test.go
@@ -169,12 +169,13 @@ var _ = Describe("Podman images", func() {
Skip("Does not work on remote client")
}
dockerfile := `FROM docker.io/library/alpine:latest
+RUN apk update && apk add man
`
podmanTest.BuildImage(dockerfile, "foobar.com/before:latest", "false")
result := podmanTest.Podman([]string{"images", "-q", "-f", "before=foobar.com/before:latest"})
result.WaitWithDefaultTimeout()
Expect(result.ExitCode()).To(Equal(0))
- Expect(len(result.OutputToStringArray())).To(Equal(1))
+ Expect(len(result.OutputToStringArray()) >= 1).To(BeTrue())
})
It("podman images filter after image", func() {
diff --git a/test/e2e/info_test.go b/test/e2e/info_test.go
index c960fb311..ca4012dde 100644
--- a/test/e2e/info_test.go
+++ b/test/e2e/info_test.go
@@ -24,6 +24,7 @@ var _ = Describe("Podman Info", func() {
}
podmanTest = PodmanTestCreate(tempdir)
podmanTest.Setup()
+ podmanTest.DelayForVarlink()
})
AfterEach(func() {
diff --git a/test/e2e/kill_test.go b/test/e2e/kill_test.go
index 618ca5aa0..3286180a4 100644
--- a/test/e2e/kill_test.go
+++ b/test/e2e/kill_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/libpod_suite_remoteclient_test.go b/test/e2e/libpod_suite_remoteclient_test.go
index 1e477fe2f..05c355711 100644
--- a/test/e2e/libpod_suite_remoteclient_test.go
+++ b/test/e2e/libpod_suite_remoteclient_test.go
@@ -3,13 +3,17 @@
package integration
import (
+ "bytes"
"fmt"
"github.com/containers/libpod/pkg/rootless"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
+ "strconv"
"strings"
+ "syscall"
+ "time"
"github.com/onsi/ginkgo"
)
@@ -50,33 +54,76 @@ func PodmanTestCreate(tempDir string) *PodmanTestIntegration {
return pti
}
+func (p *PodmanTestIntegration) ResetVarlinkAddress() {
+ os.Unsetenv("PODMAN_VARLINK_ADDRESS")
+}
+
+func (p *PodmanTestIntegration) SetVarlinkAddress(addr string) {
+ os.Setenv("PODMAN_VARLINK_ADDRESS", addr)
+}
+
func (p *PodmanTestIntegration) StartVarlink() {
if os.Geteuid() == 0 {
os.MkdirAll("/run/podman", 0755)
}
varlinkEndpoint := p.VarlinkEndpoint
- if addr := os.Getenv("PODMAN_VARLINK_ADDRESS"); addr != "" {
- varlinkEndpoint = addr
- }
+ p.SetVarlinkAddress(p.VarlinkEndpoint)
args := []string{"varlink", "--timeout", "0", varlinkEndpoint}
podmanOptions := getVarlinkOptions(p, args)
command := exec.Command(p.PodmanBinary, podmanOptions...)
fmt.Printf("Running: %s %s\n", p.PodmanBinary, strings.Join(podmanOptions, " "))
command.Start()
+ command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+ p.VarlinkCommand = command
p.VarlinkSession = command.Process
}
func (p *PodmanTestIntegration) StopVarlink() {
+ var out bytes.Buffer
+ var pids []int
varlinkSession := p.VarlinkSession
- varlinkSession.Kill()
- varlinkSession.Wait()
if !rootless.IsRootless() {
- socket := strings.Split(p.VarlinkEndpoint, ":")[1]
- if err := os.Remove(socket); err != nil {
- fmt.Println(err)
+ if err := varlinkSession.Kill(); err != nil {
+ fmt.Fprintf(os.Stderr, "error on varlink stop-kill %q", err)
}
+ if _, err := varlinkSession.Wait(); err != nil {
+ fmt.Fprintf(os.Stderr, "error on varlink stop-wait %q", err)
+ }
+
+ } else {
+ p.ResetVarlinkAddress()
+ parentPid := fmt.Sprintf("%d", p.VarlinkSession.Pid)
+ pgrep := exec.Command("pgrep", "-P", parentPid)
+ fmt.Printf("running: pgrep %s\n", parentPid)
+ pgrep.Stdout = &out
+ err := pgrep.Run()
+ if err != nil {
+ fmt.Fprint(os.Stderr, "unable to find varlink pid")
+ }
+
+ for _, s := range strings.Split(out.String(), "\n") {
+ if len(s) == 0 {
+ continue
+ }
+ p, err := strconv.Atoi(s)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "unable to convert %s to int", s)
+ }
+ if p != 0 {
+ pids = append(pids, p)
+ }
+ }
+
+ pids = append(pids, p.VarlinkSession.Pid)
+ for _, pid := range pids {
+ syscall.Kill(pid, syscall.SIGKILL)
+ }
+ }
+ socket := strings.Split(p.VarlinkEndpoint, ":")[1]
+ if err := os.Remove(socket); err != nil {
+ fmt.Println(err)
}
}
@@ -110,3 +157,14 @@ func (p *PodmanTestIntegration) RestoreArtifact(image string) error {
command.Wait()
return nil
}
+
+func (p *PodmanTestIntegration) DelayForVarlink() {
+ for i := 0; i < 5; i++ {
+ session := p.Podman([]string{"info"})
+ session.WaitWithDefaultTimeout()
+ if session.ExitCode() == 0 || i == 4 {
+ break
+ }
+ time.Sleep(1 * time.Second)
+ }
+}
diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go
index 10ca9ac47..0a85c625d 100644
--- a/test/e2e/libpod_suite_test.go
+++ b/test/e2e/libpod_suite_test.go
@@ -79,4 +79,5 @@ func (p *PodmanTestIntegration) RestoreArtifact(image string) error {
restore.Wait(90)
return nil
}
-func (p *PodmanTestIntegration) StopVarlink() {}
+func (p *PodmanTestIntegration) StopVarlink() {}
+func (p *PodmanTestIntegration) DelayForVarlink() {}
diff --git a/test/e2e/logs_test.go b/test/e2e/logs_test.go
index d051e3dba..2c82182cf 100644
--- a/test/e2e/logs_test.go
+++ b/test/e2e/logs_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/negative_test.go b/test/e2e/negative_test.go
new file mode 100644
index 000000000..3cb54a20a
--- /dev/null
+++ b/test/e2e/negative_test.go
@@ -0,0 +1,38 @@
+package integration
+
+import (
+ "os"
+
+ . "github.com/containers/libpod/test/utils"
+ . "github.com/onsi/ginkgo"
+ . "github.com/onsi/gomega"
+)
+
+var _ = Describe("Podman negative command-line", func() {
+ var (
+ tempdir string
+ err error
+ podmanTest *PodmanTestIntegration
+ )
+
+ BeforeEach(func() {
+ tempdir, err = CreateTempDirInTempDir()
+ if err != nil {
+ os.Exit(1)
+ }
+ podmanTest = PodmanTestCreate(tempdir)
+ })
+
+ AfterEach(func() {
+ podmanTest.Cleanup()
+ f := CurrentGinkgoTestDescription()
+ processTestResult(f)
+
+ })
+
+ It("podman snuffleupagus exits non-zero", func() {
+ session := podmanTest.Podman([]string{"snuffleupagus"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Not(Equal(0)))
+ })
+})
diff --git a/test/e2e/pod_create_test.go b/test/e2e/pod_create_test.go
index de0734e9f..84966f77b 100644
--- a/test/e2e/pod_create_test.go
+++ b/test/e2e/pod_create_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_inspect_test.go b/test/e2e/pod_inspect_test.go
index 671d203a6..d1a023153 100644
--- a/test/e2e/pod_inspect_test.go
+++ b/test/e2e/pod_inspect_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_kill_test.go b/test/e2e/pod_kill_test.go
index c1f7503e3..23a8ea97e 100644
--- a/test/e2e/pod_kill_test.go
+++ b/test/e2e/pod_kill_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_pause_test.go b/test/e2e/pod_pause_test.go
index 59a4da176..ab828853b 100644
--- a/test/e2e/pod_pause_test.go
+++ b/test/e2e/pod_pause_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_prune_test.go b/test/e2e/pod_prune_test.go
index c20f602ad..8a4ba2399 100644
--- a/test/e2e/pod_prune_test.go
+++ b/test/e2e/pod_prune_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_ps_test.go b/test/e2e/pod_ps_test.go
index 2fa26d7ad..8513c6c2e 100644
--- a/test/e2e/pod_ps_test.go
+++ b/test/e2e/pod_ps_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_restart_test.go b/test/e2e/pod_restart_test.go
index ffb6cb94c..7b19ecc94 100644
--- a/test/e2e/pod_restart_test.go
+++ b/test/e2e/pod_restart_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_rm_test.go b/test/e2e/pod_rm_test.go
index 5da3d563b..7417a1298 100644
--- a/test/e2e/pod_rm_test.go
+++ b/test/e2e/pod_rm_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_start_test.go b/test/e2e/pod_start_test.go
index de52af2a0..967fbc2da 100644
--- a/test/e2e/pod_start_test.go
+++ b/test/e2e/pod_start_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/pod_stop_test.go b/test/e2e/pod_stop_test.go
index fa285fa80..9fd9e3ef4 100644
--- a/test/e2e/pod_stop_test.go
+++ b/test/e2e/pod_stop_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 957c69aa8..7edb350f3 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/refresh_test.go b/test/e2e/refresh_test.go
deleted file mode 100644
index 56c1d255e..000000000
--- a/test/e2e/refresh_test.go
+++ /dev/null
@@ -1,74 +0,0 @@
-// +build !remoteclient
-
-package integration
-
-import (
- "os"
- "time"
-
- . "github.com/containers/libpod/test/utils"
- . "github.com/onsi/ginkgo"
- . "github.com/onsi/gomega"
-)
-
-var _ = Describe("Podman refresh", func() {
- var (
- tmpdir string
- err error
- podmanTest *PodmanTestIntegration
- )
-
- BeforeEach(func() {
- tmpdir, err = CreateTempDirInTempDir()
- if err != nil {
- os.Exit(1)
- }
- podmanTest = PodmanTestCreate(tmpdir)
- podmanTest.Setup()
- podmanTest.RestoreAllArtifacts()
- })
-
- AfterEach(func() {
- podmanTest.Cleanup()
- f := CurrentGinkgoTestDescription()
- processTestResult(f)
-
- })
-
- Specify("Refresh with no containers succeeds", func() {
- session := podmanTest.Podman([]string{"container", "refresh"})
- session.WaitWithDefaultTimeout()
- Expect(session.ExitCode()).To(Equal(0))
- })
-
- Specify("Refresh with created container succeeds", func() {
- createSession := podmanTest.Podman([]string{"create", ALPINE, "ls"})
- createSession.WaitWithDefaultTimeout()
- Expect(createSession.ExitCode()).To(Equal(0))
- Expect(podmanTest.NumberOfContainers()).To(Equal(1))
- Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
-
- refreshSession := podmanTest.Podman([]string{"container", "refresh"})
- refreshSession.WaitWithDefaultTimeout()
- Expect(refreshSession.ExitCode()).To(Equal(0))
- Expect(podmanTest.NumberOfContainers()).To(Equal(1))
- Expect(podmanTest.NumberOfContainersRunning()).To(Equal(0))
- })
-
- Specify("Refresh with running container restarts container", func() {
- createSession := podmanTest.Podman([]string{"run", "-dt", ALPINE, "top"})
- createSession.WaitWithDefaultTimeout()
- Expect(createSession.ExitCode()).To(Equal(0))
- Expect(podmanTest.NumberOfContainers()).To(Equal(1))
- Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
-
- // HACK: ensure container starts before we move on
- time.Sleep(1 * time.Second)
-
- refreshSession := podmanTest.Podman([]string{"container", "refresh"})
- refreshSession.WaitWithDefaultTimeout()
- Expect(refreshSession.ExitCode()).To(Equal(0))
- Expect(podmanTest.NumberOfContainers()).To(Equal(1))
- Expect(podmanTest.NumberOfContainersRunning()).To(Equal(1))
- })
-})
diff --git a/test/e2e/rm_test.go b/test/e2e/rm_test.go
index 9bf742a63..29150d67c 100644
--- a/test/e2e/rm_test.go
+++ b/test/e2e/rm_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 030722b47..0e1f0d865 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -273,6 +273,7 @@ var _ = Describe("Podman run", func() {
})
It("podman run notify_socket", func() {
+ SkipIfRemote()
host := GetHostDistributionInfo()
if host.Distribution != "rhel" && host.Distribution != "centos" && host.Distribution != "fedora" {
Skip("this test requires a working runc")
diff --git a/test/e2e/save_test.go b/test/e2e/save_test.go
index c3edc7c7e..ffb5182d6 100644
--- a/test/e2e/save_test.go
+++ b/test/e2e/save_test.go
@@ -4,6 +4,7 @@ import (
"os"
"path/filepath"
+ "github.com/containers/libpod/pkg/rootless"
. "github.com/containers/libpod/test/utils"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
@@ -75,6 +76,9 @@ var _ = Describe("Podman save", func() {
})
It("podman save to directory with oci format", func() {
+ if rootless.IsRootless() && podmanTest.RemoteTest {
+ Skip("Requires a fix in containers image for chown/lchown")
+ }
outdir := filepath.Join(podmanTest.TempDir, "save")
save := podmanTest.Podman([]string{"save", "--format", "oci-dir", "-o", outdir, ALPINE})
@@ -83,6 +87,9 @@ var _ = Describe("Podman save", func() {
})
It("podman save to directory with v2s2 docker format", func() {
+ if rootless.IsRootless() && podmanTest.RemoteTest {
+ Skip("Requires a fix in containers image for chown/lchown")
+ }
outdir := filepath.Join(podmanTest.TempDir, "save")
save := podmanTest.Podman([]string{"save", "--format", "docker-dir", "-o", outdir, ALPINE})
@@ -91,6 +98,9 @@ var _ = Describe("Podman save", func() {
})
It("podman save to directory with docker format and compression", func() {
+ if rootless.IsRootless() && podmanTest.RemoteTest {
+ Skip("Requires a fix in containers image for chown/lchown")
+ }
outdir := filepath.Join(podmanTest.TempDir, "save")
save := podmanTest.Podman([]string{"save", "--compress", "--format", "docker-dir", "-o", outdir, ALPINE})
diff --git a/test/e2e/stop_test.go b/test/e2e/stop_test.go
index 717eea441..e201204df 100644
--- a/test/e2e/stop_test.go
+++ b/test/e2e/stop_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/tag_test.go b/test/e2e/tag_test.go
index ff0ac31c4..26d6dfa75 100644
--- a/test/e2e/tag_test.go
+++ b/test/e2e/tag_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/e2e/version_test.go b/test/e2e/version_test.go
index f546158a9..35ee21e49 100644
--- a/test/e2e/version_test.go
+++ b/test/e2e/version_test.go
@@ -31,6 +31,7 @@ var _ = Describe("Podman version", func() {
})
It("podman version", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"version"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -38,6 +39,7 @@ var _ = Describe("Podman version", func() {
})
It("podman version --format json", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"version", "--format", "json"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -45,6 +47,7 @@ var _ = Describe("Podman version", func() {
})
It("podman version --format json", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"version", "--format", "{{ json .}}"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
@@ -52,6 +55,7 @@ var _ = Describe("Podman version", func() {
})
It("podman version --format GO template", func() {
+ SkipIfRemote()
session := podmanTest.Podman([]string{"version", "--format", "{{ .Version }}"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/wait_test.go b/test/e2e/wait_test.go
index 5bf0331e5..28a4c1e40 100644
--- a/test/e2e/wait_test.go
+++ b/test/e2e/wait_test.go
@@ -1,5 +1,3 @@
-// +build !remoteclient
-
package integration
import (
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 1e0391d2e..beadab549 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -4,7 +4,6 @@ import (
"bufio"
"encoding/json"
"fmt"
- "github.com/containers/libpod/pkg/rootless"
"io/ioutil"
"os"
"os/exec"
@@ -42,6 +41,7 @@ type PodmanTest struct {
RemotePodmanBinary string
VarlinkSession *os.Process
VarlinkEndpoint string
+ VarlinkCommand *exec.Cmd
}
// PodmanSession wraps the gexec.session so we can extend it
@@ -69,9 +69,7 @@ func (p *PodmanTest) PodmanAsUserBase(args []string, uid, gid uint32, cwd string
podmanBinary := p.PodmanBinary
if p.RemoteTest {
podmanBinary = p.RemotePodmanBinary
- if !rootless.IsRootless() {
- env = append(env, fmt.Sprintf("PODMAN_VARLINK_ADDRESS=%s", p.VarlinkEndpoint))
- }
+ env = append(env, fmt.Sprintf("PODMAN_VARLINK_ADDRESS=%s", p.VarlinkEndpoint))
}
if env == nil {
diff --git a/vendor.conf b/vendor.conf
index d5e2b60bd..2f7e36d85 100644
--- a/vendor.conf
+++ b/vendor.conf
@@ -93,8 +93,8 @@ 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 64e07fabffa33e385817b41971cf2674f692f391
github.com/containers/buildah v1.8.2
+github.com/varlink/go 0f1d566d194b9d6d48e0d47c5e4d822628919066
# TODO: Gotty has not been updated since 2012. Can we find replacement?
github.com/Nvveen/Gotty cd527374f1e5bff4938207604a14f2e38a9cf512
github.com/fsouza/go-dockerclient v1.3.0
diff --git a/vendor/github.com/varlink/go/varlink/bridge.go b/vendor/github.com/varlink/go/varlink/bridge.go
index 0ea5de682..c478dcd88 100644
--- a/vendor/github.com/varlink/go/varlink/bridge.go
+++ b/vendor/github.com/varlink/go/varlink/bridge.go
@@ -6,6 +6,7 @@ import (
"bufio"
"io"
"net"
+ "os"
"os/exec"
)
@@ -30,12 +31,13 @@ func (p PipeCon) Close() error {
return nil
}
-// NewConnection returns a new connection to the given address.
-func NewBridge(bridge string) (*Connection, error) {
+// NewBridgeWithStderr returns a new connection with the given bridge.
+func NewBridgeWithStderr(bridge string, stderr io.Writer) (*Connection, error) {
//var err error
c := Connection{}
cmd := exec.Command("sh", "-c", bridge)
+ cmd.Stderr = stderr
r, err := cmd.StdoutPipe()
if err != nil {
return nil, err
@@ -56,3 +58,8 @@ func NewBridge(bridge string) (*Connection, error) {
return &c, nil
}
+
+// NewBridge returns a new connection with the given bridge.
+func NewBridge(bridge string) (*Connection, error) {
+ return NewBridgeWithStderr(bridge, os.Stderr)
+}
diff --git a/vendor/github.com/varlink/go/varlink/bridge_windows.go b/vendor/github.com/varlink/go/varlink/bridge_windows.go
index 751224ec8..42953b871 100644
--- a/vendor/github.com/varlink/go/varlink/bridge_windows.go
+++ b/vendor/github.com/varlink/go/varlink/bridge_windows.go
@@ -4,6 +4,7 @@ import (
"bufio"
"io"
"net"
+ "os"
"os/exec"
)
@@ -28,12 +29,13 @@ func (p PipeCon) Close() error {
return nil
}
-// NewConnection returns a new connection to the given address.
-func NewBridge(bridge string) (*Connection, error) {
+// NewBridgeWithStderr returns a new connection with the given bridge.
+func NewBridgeWithStderr(bridge string, stderr io.Writer) (*Connection, error) {
//var err error
c := Connection{}
cmd := exec.Command("cmd", "/C", bridge)
+ cmd.Stderr = stderr
r, err := cmd.StdoutPipe()
if err != nil {
return nil, err
@@ -54,3 +56,8 @@ func NewBridge(bridge string) (*Connection, error) {
return &c, nil
}
+
+// NewBridge returns a new connection with the given bridge.
+func NewBridge(bridge string) (*Connection, error) {
+ return NewBridgeWithStderr(bridge, os.Stderr)
+} \ No newline at end of file
diff --git a/version/version.go b/version/version.go
index 29a576317..c63f8b820 100644
--- a/version/version.go
+++ b/version/version.go
@@ -4,7 +4,7 @@ package version
// NOTE: remember to bump the version at the top
// of the top-level README.md file when this is
// bumped.
-const Version = "1.3.0-dev"
+const Version = "1.3.1-dev"
// RemoteAPIVersion is the version for the remote
// client API. It is used to determine compatibility