summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml2
-rw-r--r--.papr.sh3
-rw-r--r--Makefile2
-rw-r--r--RELEASE_NOTES.md35
-rw-r--r--changelog.txt101
-rwxr-xr-xcontrib/cirrus/optional_system_test.sh24
-rw-r--r--contrib/python/podman/podman/libs/images.py2
-rw-r--r--contrib/python/podman/test/test_pods_ctnrs.py3
-rw-r--r--contrib/python/pypodman/pypodman/lib/__init__.py5
-rw-r--r--contrib/python/pypodman/pypodman/lib/actions/commit_action.py32
-rw-r--r--contrib/python/pypodman/pypodman/lib/actions/export_action.py22
-rw-r--r--contrib/python/pypodman/pypodman/lib/actions/import_action.py41
-rw-r--r--contrib/python/pypodman/pypodman/lib/parser_actions.py51
-rw-r--r--contrib/spec/podman.spec.in2
-rw-r--r--docs/podman-build.1.md2
-rw-r--r--docs/podman-create.1.md12
-rw-r--r--docs/podman-run.1.md13
-rw-r--r--libpod/container_api.go23
-rw-r--r--libpod/container_internal.go106
-rw-r--r--libpod/container_internal_linux.go41
-rw-r--r--libpod/oci.go61
-rw-r--r--libpod/runtime_ctr.go2
-rw-r--r--libpod/runtime_pod_linux.go19
-rw-r--r--pkg/lookup/lookup.go8
-rw-r--r--seccomp.json33
-rw-r--r--test/e2e/pause_test.go4
-rw-r--r--test/e2e/run_dns_test.go9
-rw-r--r--version/version.go2
28 files changed, 508 insertions, 152 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index c5d35141e..f78205a49 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -63,6 +63,8 @@ full_vm_testing_task:
integration_test_script: $SCRIPT_BASE/integration_test.sh
+ optional_system_test_script: $SCRIPT_BASE/optional_system_test.sh
+
success_script: $SCRIPT_BASE/success.sh
diff --git a/.papr.sh b/.papr.sh
index 120b3d94b..284326709 100644
--- a/.papr.sh
+++ b/.papr.sh
@@ -139,6 +139,3 @@ if [ $integrationtest -eq 1 ]; then
fi
make ginkgo GOPATH=/go $INTEGRATION_TEST_ENVS
fi
-
-
-exit 0
diff --git a/Makefile b/Makefile
index ae1b263ad..04d6230d6 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
GO ?= go
DESTDIR ?= /
-EPOCH_TEST_COMMIT ?= 733cfe96819e1dc044e982b5321b3c902d1a47c6
+EPOCH_TEST_COMMIT ?= 921ccac10c47e0865ec5e4ba00ebb69a03d89473
HEAD ?= HEAD
CHANGELOG_BASE ?= HEAD~
CHANGELOG_TARGET ?= HEAD
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 6c7bf1a8f..9cdf3faae 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,40 @@
# Release Notes
+## 0.11.1
+### Features
+- Added `--all` and `--latest` flags to `podman checkpoint` and `podman restore`
+- Added `--max-workers` flag to all Podman commands that support operating in parallel, allowing the maximum number of parallel workers used to be specified
+- Added `--all` flag to `podman restart`
+
+### Bugfixes
+- Fixed a bug where `podman port -l` would segfault if no containers were present
+- Fixed a bug where `podman stats -a` would error if containers were present but not running
+- Fixed a bug where container status checks would sometimes leave zombie OCI runtime processes
+- Fixed checkpoint and restore code to verify an appropriate version of `criu` is being used
+- Fixed a bug where environment variables with no specified value (e.g. `-e FOO`) caused errors (they are now added as empty)
+- Fixed a bug where rootless Podman would attempt to configure the system firewall, causing errors on some systems where iptables is not in the user's PATH
+- Fixed a bug where rootless Podman was unable to successfully write the container ID to a file when `--cid-file` was specified to `podman run`
+- Fixed a bug where `podman unmount` would refuse to unmount a container if it was running (the unmount will now be deferred until the container stops)
+- Fixed a bug where rootless `podman attach` would fail to attach due to a too-long path name
+- Fixed a bug where `podman info` was not properly reporting the Git commit Podman was built from
+- Fixed a bug where `podman run --interactive` was not holding STDIN open when `-a` flag was specified
+- Fixed a bug where Podman with the `cgroupfs` CGroup driver was sometimes not successfully removing pod CGroups
+- Fixed a bug where rootless Podman was unable to run systemd containers (note that this also requires an update to systemd)
+- Fixed a bug where `podman run` with the `--user` flag would fail if the container image did not contain `/etc/passwd` or `/etc/group`
+
+### Misc
+- `podman rm`, `podman restart`, `podman kill`, `podman pause`, and `podman unpause` now operate in parallel, greatly improving speed when multiple containers are specified
+- `podman create`, `podman run`, and `podman ps` have a number of improvements which should greatly increase their speed
+- Greatly improved performance and reduced memory utilization of container status checks, which should improve the speed of most Podman commands
+- Improve ability of `podman runlabel` to run commands that are not Podman
+- Podman containers with an IP address now add their hostnames to `/etc/hosts`
+- Changed default location of temporary libpod files in rootless Podman
+- Updated the default Podman seccomp profile
+
+### Compatability
+Several paths related to rootless Podman had their default values changed in this release.
+If paths were not hardcoded in libpod.conf, your system may lose track of running containers and believe they are newly-created.
+
## 0.10.1.3
### Bugfixes
- Fixed a bug where `podman build` would not work while any containers were running
diff --git a/changelog.txt b/changelog.txt
index ace41f1d9..9aaec0e74 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,104 @@
+- Changelog for v0.11.1 (2018-11-08)
+ * Update release notes for 0.11.1
+ * update seccomp.json
+ * Touch up --log* options and daemons in man pages
+ * Fix run --hostname test that started failing post-merge
+ * move defer'd function declaration ahead of prepare error return
+ * Don't fail if /etc/passwd or /etc/group does not exists
+ * Print error status code if we fail to parse it
+ * Properly set Running state when starting containers
+ * Fix misspelling
+ * Retrieve container PID from conmon
+ * If a container ceases to exist in runc, set exit status
+ * EXPERIMENTAL: Do not call out to runc for sync
+ * Actually save changes from post-stop sync
+ * rootless: mount /sys/fs/cgroup/systemd from the host
+ * rootless: don't bind mount /sys/fs/cgroup/systemd in systemd mode
+ * Add hostname to /etc/hosts
+ * Temporarily fix the Python tests to fix some PRs
+ * Remove conmon cgroup before pod cgroup for cgroupfs
+ * Fix cleanup for "Pause a bunch of running containers"
+ * --interactive shall keep STDIN attached even when not explicitly called out
+ * Do never override podman with docker
+ * Make kill, pause, and unpause parallel.
+ * Fix long image name handling
+ * Make restart parallel and add --all
+ * Add ChangeAction to parse sub-options from --change
+ * replace quay.io/baude to quay.io/libpod
+ * Change humanize to use MB vs MiB.
+ * allow ppc64le to pass libpod integration tests
+ * Cirrus-CI: Add option to run system-tests
+ * Cirrus: Skip rebuilding images unless instructed
+ * Cirrus: Disable image build job abort on push
+ * Cirrus: Add a readme
+ * Ubuntu VM image build: try update twice
+ * Cirrus: Enable updating F28 image
+ * rootless: do not add an additional /run to runroot
+ * rootless: avoid hang on failed slirp4netns
+ * Fix setting of version information
+ * runtime: do not allow runroot longer than 50 characters
+ * attach: fix attach when cuid is too long
+ * truncate command output in ps by default
+ * Update the runc commit used for testing
+ * make various changes to ps output
+ * Sync default config with libpod.conf
+ * Use two spaces to pad PS fields
+ * unmount: fix error logic
+ * get user and group information using securejoin and runc's user library
+ * CONTRIBUTING.md: add section about describing changes
+ * Change to exported name in ParseDevice
+ * Vendor in latest containers/storage
+ * fix bug in rm -fa parallel deletes
+ * Ensure test container in running state
+ * Add tests for selinux labels
+ * Add --max-workers and heuristics for parallel operations
+ * Increase security and performance when looking up groups
+ * run prepare in parallel
+ * downgrade runc due a rootless bug
+ * runlabel: run any command
+ * Eat our own dogfood
+ * vendor: update containers/storage
+ * Add support for /usr/local installation
+ * create: fix writing cidfile when using rootless
+ * Explain the device format in man pages
+ * read conmon output and convert to json in two steps
+ * Cirrus: Use images w/ buildah fix
+ * Add --all and --latest to checkpoint/restore
+ * Use the newly added getAllOrLatestContainers() function
+ * Use the new checkAllAndLatest() function
+ * Also factor out getAllOrLatestContainers() function
+ * Add checkAllAndLatest() function
+ * Downgrade code to support python3.4
+ * Allow containers/storage to handle on SELinux labeling
+ * Use more reliable check for rootless for firewall init
+ * Vendor in latest containers/storage opencontainers/selinux
+ * Make podman ps fast
+ * Support auth file environment variable in podman build
+ * fix environment variable parsing
+ * tests: use existing CRIU version check
+ * Use the CRIU version check in checkpoint/restore
+ * Add helper function to read out CRIU version
+ * vendor in go-criu and dependencies
+ * oci: cleanup process status
+ * Handle http/https in registry given to login/out
+ * re-enable f29 testing
+ * correct stats err with non-running containers
+ * Use restoreArtifacts to save time in integration tests
+ * Make rm faster
+ * Fix man page to show info on storage
+ * Move rootless directory handling to the libpod/pkg/util directory
+ * Fix podman port -l
+ * Fix trivial missing markup in manpage
+ * Cirrus: Install CRIU in test images
+ * Cirrus: Use different CNI_COMMIT for Fedora
+ * Fix Cirrus/Packer VM image building
+ * Revert "Cirrus: Enable debugging delay on non-zero exit"
+ * Cirrus: IRC message when cirrus testing successful
+ * cirrus: Add simple IRC messenger
+ * fix NOTIFY_SOCKET in e2e testfix NOTIFY_SOCKET in e2e tests
+ * Bump gitvalidation epoch
+ * Bump to v0.10.2-dev
+
- Changelog for v0.10.1.3 (2018-10-17)
* Update release notes for 0.10.1.3
* Vendor in new new buildah/ci
diff --git a/contrib/cirrus/optional_system_test.sh b/contrib/cirrus/optional_system_test.sh
new file mode 100755
index 000000000..705dda5ad
--- /dev/null
+++ b/contrib/cirrus/optional_system_test.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+source $(dirname $0)/lib.sh
+
+MAGIC_RE='\*\*\*\s*CIRRUS:\s*SYSTEM\s*TEST\s*\*\*\*'
+if ! echo "$CIRRUS_CHANGE_MESSAGE" | egrep -q "$MAGIC_RE"
+then
+ echo "Skipping system-testing because PR title or description"
+ echo "does not match regular expression: $MAGIC_RE"
+ exit 0
+fi
+
+req_env_var "
+GOSRC $GOSRC
+OS_RELEASE_ID $OS_RELEASE_ID
+OS_RELEASE_VER $OS_RELEASE_VER
+"
+
+show_env_vars
+
+set -x
+cd "$GOSRC"
+make localsystem
diff --git a/contrib/python/podman/podman/libs/images.py b/contrib/python/podman/podman/libs/images.py
index 982546cd2..9453fb416 100644
--- a/contrib/python/podman/podman/libs/images.py
+++ b/contrib/python/podman/podman/libs/images.py
@@ -137,7 +137,7 @@ class Images():
results = podman.DeleteUnusedImages()
return results['images']
- def import_image(self, source, reference, message=None, changes=None):
+ def import_image(self, source, reference, message='', changes=None):
"""Read image tarball from source and save in image store."""
with self._client() as podman:
results = podman.ImportImage(source, reference, message, changes)
diff --git a/contrib/python/podman/test/test_pods_ctnrs.py b/contrib/python/podman/test/test_pods_ctnrs.py
index 14ce95c8a..009e30720 100644
--- a/contrib/python/podman/test/test_pods_ctnrs.py
+++ b/contrib/python/podman/test/test_pods_ctnrs.py
@@ -52,7 +52,8 @@ class TestPodsCtnrs(PodmanTestCase):
status = FoldedString(pod.containersinfo[0]['status'])
self.assertIn(status, ('stopped', 'exited', 'running'))
- killed = pod.kill()
+ # Pod kill is broken, so use stop for now
+ killed = pod.stop()
self.assertEqual(pod, killed)
def test_999_remove(self):
diff --git a/contrib/python/pypodman/pypodman/lib/__init__.py b/contrib/python/pypodman/pypodman/lib/__init__.py
index 5525ddaef..be1b5f467 100644
--- a/contrib/python/pypodman/pypodman/lib/__init__.py
+++ b/contrib/python/pypodman/pypodman/lib/__init__.py
@@ -4,14 +4,15 @@ import sys
import podman
from pypodman.lib.action_base import AbstractActionBase
from pypodman.lib.parser_actions import (BooleanAction, BooleanValidate,
- PathAction, PositiveIntAction,
- UnitAction)
+ ChangeAction, PathAction,
+ PositiveIntAction, UnitAction)
from pypodman.lib.podman_parser import PodmanArgumentParser
from pypodman.lib.report import Report, ReportColumn
# Silence pylint overlording...
assert BooleanAction
assert BooleanValidate
+assert ChangeAction
assert PathAction
assert PositiveIntAction
assert UnitAction
diff --git a/contrib/python/pypodman/pypodman/lib/actions/commit_action.py b/contrib/python/pypodman/pypodman/lib/actions/commit_action.py
index 0da6a2078..21665ad0b 100644
--- a/contrib/python/pypodman/pypodman/lib/actions/commit_action.py
+++ b/contrib/python/pypodman/pypodman/lib/actions/commit_action.py
@@ -2,7 +2,7 @@
import sys
import podman
-from pypodman.lib import AbstractActionBase, BooleanAction
+from pypodman.lib import AbstractActionBase, BooleanAction, ChangeAction
class Commit(AbstractActionBase):
@@ -12,7 +12,9 @@ class Commit(AbstractActionBase):
def subparser(cls, parent):
"""Add Commit command to parent parser."""
parser = parent.add_parser(
- 'commit', help='create image from container')
+ 'commit',
+ help='create image from container',
+ )
parser.add_argument(
'--author',
help='Set the author for the committed image',
@@ -20,11 +22,7 @@ class Commit(AbstractActionBase):
parser.add_argument(
'--change',
'-c',
- choices=('CMD', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'LABEL', 'ONBUILD',
- 'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR'),
- action='append',
- type=str.upper,
- help='Apply the following possible changes to the created image',
+ action=ChangeAction,
)
parser.add_argument(
'--format',
@@ -69,27 +67,11 @@ class Commit(AbstractActionBase):
)
parser.set_defaults(class_=cls, method='commit')
- def __init__(self, args):
- """Construct Commit class."""
- if not args.container:
- raise ValueError('You must supply one container id'
- ' or name to be used as source.')
- if not args.image:
- raise ValueError('You must supply one image id'
- ' or name to be created.')
- super().__init__(args)
-
- # used only on client
- del self.opts['image']
- del self.opts['container']
-
def commit(self):
"""Create image from container."""
try:
try:
ctnr = self.client.containers.get(self._args.container[0])
- ident = ctnr.commit(**self.opts)
- print(ident)
except podman.ContainerNotFound as e:
sys.stdout.flush()
print(
@@ -97,6 +79,9 @@ class Commit(AbstractActionBase):
file=sys.stderr,
flush=True)
return 1
+ else:
+ ident = ctnr.commit(self.opts['image'][0], **self.opts)
+ print(ident)
except podman.ErrorOccurred as e:
sys.stdout.flush()
print(
@@ -104,3 +89,4 @@ class Commit(AbstractActionBase):
file=sys.stderr,
flush=True)
return 1
+ return 0
diff --git a/contrib/python/pypodman/pypodman/lib/actions/export_action.py b/contrib/python/pypodman/pypodman/lib/actions/export_action.py
index f62cd3535..7ef178c4c 100644
--- a/contrib/python/pypodman/pypodman/lib/actions/export_action.py
+++ b/contrib/python/pypodman/pypodman/lib/actions/export_action.py
@@ -12,13 +12,16 @@ class Export(AbstractActionBase):
def subparser(cls, parent):
"""Add Export command to parent parser."""
parser = parent.add_parser(
- 'export', help='export container to tarball')
+ 'export',
+ help='export container to tarball',
+ )
parser.add_argument(
'--output',
'-o',
metavar='PATH',
nargs=1,
- help='Write to a file',
+ required=True,
+ help='Write to this file on host',
)
parser.add_argument(
'container',
@@ -27,23 +30,11 @@ class Export(AbstractActionBase):
)
parser.set_defaults(class_=cls, method='export')
- def __init__(self, args):
- """Construct Export class."""
- if not args.container:
- raise ValueError('You must supply one container id'
- ' or name to be used as source.')
-
- if not args.output:
- raise ValueError('You must supply one filename'
- ' to be created as tarball using --output.')
- super().__init__(args)
-
def export(self):
"""Create tarball from container filesystem."""
try:
try:
ctnr = self.client.containers.get(self._args.container[0])
- ctnr.export(self._args.output[0])
except podman.ContainerNotFound as e:
sys.stdout.flush()
print(
@@ -51,6 +42,8 @@ class Export(AbstractActionBase):
file=sys.stderr,
flush=True)
return 1
+ else:
+ ctnr.export(self._args.output[0])
except podman.ErrorOccurred as e:
sys.stdout.flush()
print(
@@ -58,3 +51,4 @@ class Export(AbstractActionBase):
file=sys.stderr,
flush=True)
return 1
+ return 0
diff --git a/contrib/python/pypodman/pypodman/lib/actions/import_action.py b/contrib/python/pypodman/pypodman/lib/actions/import_action.py
index 49b8a5a57..43448144a 100644
--- a/contrib/python/pypodman/pypodman/lib/actions/import_action.py
+++ b/contrib/python/pypodman/pypodman/lib/actions/import_action.py
@@ -2,7 +2,7 @@
import sys
import podman
-from pypodman.lib import AbstractActionBase
+from pypodman.lib import AbstractActionBase, ChangeAction
class Import(AbstractActionBase):
@@ -12,18 +12,19 @@ class Import(AbstractActionBase):
def subparser(cls, parent):
"""Add Import command to parent parser."""
parser = parent.add_parser(
- 'import', help='import tarball as image filesystem')
+ 'import',
+ help='import tarball as image filesystem',
+ )
parser.add_argument(
'--change',
'-c',
- action='append',
- choices=('CMD', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'LABEL',
- 'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR'),
- type=str.upper,
- help='Apply the following possible instructions',
+ action=ChangeAction,
)
parser.add_argument(
- '--message', '-m', help='Set commit message for imported image.')
+ '--message',
+ '-m',
+ help='Set commit message for imported image.',
+ )
parser.add_argument(
'source',
metavar='PATH',
@@ -38,18 +39,25 @@ class Import(AbstractActionBase):
)
parser.set_defaults(class_=cls, method='import_')
- def __init__(self, args):
- """Construct Import class."""
- super().__init__(args)
-
def import_(self):
"""Import tarball as image filesystem."""
+ # ImportImage() validates it's parameters therefore we need to create
+ # pristine dict() for keywords
+ options = {}
+ if 'message' in self.opts:
+ options['message'] = self.opts['message']
+ if 'change' in self.opts and self.opts['change']:
+ options['changes'] = self.opts['change']
+
+ reference = self.opts['reference'][0] if 'reference' in self.opts\
+ else None
+
try:
ident = self.client.images.import_image(
- self.opts.source,
- self.opts.reference,
- message=self.opts.message,
- changes=self.opts.change)
+ self.opts['source'][0],
+ reference,
+ **options,
+ )
print(ident)
except podman.ErrorOccurred as e:
sys.stdout.flush()
@@ -58,3 +66,4 @@ class Import(AbstractActionBase):
file=sys.stderr,
flush=True)
return 1
+ return 0
diff --git a/contrib/python/pypodman/pypodman/lib/parser_actions.py b/contrib/python/pypodman/pypodman/lib/parser_actions.py
index 2a5859e47..c10b85495 100644
--- a/contrib/python/pypodman/pypodman/lib/parser_actions.py
+++ b/contrib/python/pypodman/pypodman/lib/parser_actions.py
@@ -4,9 +4,10 @@ Supplimental argparse.Action converters and validaters.
The constructors are very verbose but remain for IDE support.
"""
import argparse
+import copy
import os
-# API defined by argparse.Action shut up pylint
+# API defined by argparse.Action therefore shut up pylint
# pragma pylint: disable=redefined-builtin
# pragma pylint: disable=too-few-public-methods
# pragma pylint: disable=too-many-arguments
@@ -63,6 +64,54 @@ class BooleanAction(argparse.Action):
setattr(namespace, self.dest, val)
+class ChangeAction(argparse.Action):
+ """Convert and validate change argument."""
+
+ def __init__(self,
+ option_strings,
+ dest,
+ nargs=None,
+ const=None,
+ default=[],
+ type=None,
+ choices=None,
+ required=False,
+ help=None,
+ metavar='OPT=VALUE'):
+ """Create ChangeAction object."""
+ help = (help or '') + ('Apply change(s) to the new image.'
+ ' May be given multiple times.')
+
+ super().__init__(
+ option_strings=option_strings,
+ dest=dest,
+ nargs=nargs,
+ const=const,
+ default=default,
+ type=type,
+ choices=choices,
+ required=required,
+ help=help,
+ metavar=metavar)
+
+ def __call__(self, parser, namespace, values, option_string=None):
+ """Convert and Validate input."""
+ print(self.dest)
+ items = getattr(namespace, self.dest, None) or []
+ items = copy.copy(items)
+
+ choices = ('CMD', 'ENTRYPOINT', 'ENV', 'EXPOSE', 'LABEL', 'ONBUILD',
+ 'STOPSIGNAL', 'USER', 'VOLUME', 'WORKDIR')
+
+ opt, val = values.split('=', 1)
+ if opt not in choices:
+ parser.error('{} is not a supported "--change" option,'
+ ' valid options are: {}'.format(
+ opt, ', '.join(choices)))
+ items.append(values)
+ setattr(namespace, self.dest, items)
+
+
class UnitAction(argparse.Action):
"""Validate number given is positive integer, with optional suffix."""
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index c2d8fc59d..f6ebfa148 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -39,7 +39,7 @@
%global shortcommit_conmon %(c=%{commit_conmon}; echo ${c:0:7})
Name: podman
-Version: 0.10.2
+Version: 0.11.2
Release: #COMMITDATE#.git%{shortcommit0}%{?dist}
Summary: Manage Pods, Containers and Container Images
License: ASL 2.0
diff --git a/docs/podman-build.1.md b/docs/podman-build.1.md
index 0cbce15c0..f887d68cd 100644
--- a/docs/podman-build.1.md
+++ b/docs/podman-build.1.md
@@ -171,7 +171,7 @@ value can be entered. The password is entered without echo.
**--disable-content-trust**
This is a Docker specific option to disable image verification to a Docker
-registry and is not supported by Buildah. This flag is a NOOP and provided
+registry and is not supported by Podman. This flag is a NOOP and provided
soley for scripting compatibility.
**--file, -f** *Dockerfile*
diff --git a/docs/podman-create.1.md b/docs/podman-create.1.md
index 5a4d7fb5a..68c00685b 100644
--- a/docs/podman-create.1.md
+++ b/docs/podman-create.1.md
@@ -66,7 +66,7 @@ Write the container ID to the file
**--conmon-pidfile**=""
-Write the pid of the `conmon` process to a file. `conmon` daemonizes separate from Podman, so this is necessary when using systemd to restart Podman containers.
+Write the pid of the `conmon` process to a file. `conmon` runs in a separate process than Podman, so this is necessary when using systemd to restart Podman containers.
**--cpu-count**=*0*
@@ -321,13 +321,13 @@ Not implemented
**--log-driver**="*json-file*"
-Logging driver for the container. Default is defined by daemon `--log-driver` flag.
-**Warning**: the `podman logs` command works only for the `json-file` and
-`journald` logging drivers.
+Logging driver for the container. Currently not supported. This flag is a NOOP provided soley for scripting compatibility.
**--log-opt**=[]
-Logging driver specific options.
+Logging driver specific options. Used to set the path to the container log file. For example:
+
+`--log-opt path=/var/log/container/mycontainer.json`
**--mac-address**=""
@@ -414,7 +414,7 @@ UUID short identifier (“f78375b1c487”)
Name (“jonah”)
podman generates a UUID for each container, and if a name is not assigned
-to the container with **--name** then the daemon will also generate a random
+to the container with **--name** then it will generate a random
string name. The name is useful any place you need to identify a container.
This works for both background and foreground containers.
diff --git a/docs/podman-run.1.md b/docs/podman-run.1.md
index b708e3407..912026a55 100644
--- a/docs/podman-run.1.md
+++ b/docs/podman-run.1.md
@@ -78,7 +78,7 @@ Write the container ID to the file
**--conmon-pidfile**=""
-Write the pid of the `conmon` process to a file. `conmon` daemonizes separate from Podman, so this is necessary when using systemd to restart Podman containers.
+Write the pid of the `conmon` process to a file. `conmon` runs in a separate process than Podman, so this is necessary when using systemd to restart Podman containers.
**--cpu-period**=*0*
@@ -333,16 +333,13 @@ Not implemented
**--log-driver**="*json-file*"
-Logging driver for the container. Default is defined by daemon `--log-driver` flag.
-
-**Warning**: the `podman logs` command works only for the `json-file` and
-`journald` logging drivers.
+Logging driver for the container. Currently not supported. This flag is a NOOP provided soley for scripting compatibility.
**--log-opt**=[]
-Logging driver specific options.
+Logging driver specific options. Used to set the path to the container log file. For example:
-`path=/var/log/container/mycontainer.json`: Set the path to the container log file.
+`--log-opt path=/var/log/container/mycontainer.json`
**--mac-address**=""
@@ -399,7 +396,7 @@ The operator can identify a container in three ways:
- Name (“jonah”)
podman generates a UUID for each container, and if a name is not assigned
-to the container with **--name** then the daemon will also generate a random
+to the container with **--name** then it will generate a random
string name. The name is useful any place you need to identify a container.
This works for both background and foreground containers.
diff --git a/libpod/container_api.go b/libpod/container_api.go
index 30c67eb2a..d99aec5b4 100644
--- a/libpod/container_api.go
+++ b/libpod/container_api.go
@@ -46,9 +46,6 @@ func (c *Container) Init(ctx context.Context) (err error) {
return errors.Wrapf(ErrCtrStateInvalid, "some dependencies of container %s are not started: %s", c.ID(), depString)
}
- if err := c.prepare(); err != nil {
- return err
- }
defer func() {
if err != nil {
if err2 := c.cleanup(ctx); err2 != nil {
@@ -57,6 +54,10 @@ func (c *Container) Init(ctx context.Context) (err error) {
}
}()
+ if err := c.prepare(); err != nil {
+ return err
+ }
+
if c.state.State == ContainerStateStopped {
// Reinitialize the container
return c.reinit(ctx)
@@ -99,9 +100,6 @@ func (c *Container) Start(ctx context.Context) (err error) {
return errors.Wrapf(ErrCtrStateInvalid, "some dependencies of container %s are not started: %s", c.ID(), depString)
}
- if err := c.prepare(); err != nil {
- return err
- }
defer func() {
if err != nil {
if err2 := c.cleanup(ctx); err2 != nil {
@@ -110,6 +108,10 @@ func (c *Container) Start(ctx context.Context) (err error) {
}
}()
+ if err := c.prepare(); err != nil {
+ return err
+ }
+
if c.state.State == ContainerStateStopped {
// Reinitialize the container if we need to
if err := c.reinit(ctx); err != nil {
@@ -164,9 +166,6 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams,
return nil, errors.Wrapf(ErrCtrStateInvalid, "some dependencies of container %s are not started: %s", c.ID(), depString)
}
- if err := c.prepare(); err != nil {
- return nil, err
- }
defer func() {
if err != nil {
if err2 := c.cleanup(ctx); err2 != nil {
@@ -175,6 +174,10 @@ func (c *Container) StartAndAttach(ctx context.Context, streams *AttachStreams,
}
}()
+ if err := c.prepare(); err != nil {
+ return nil, err
+ }
+
if c.state.State == ContainerStateStopped {
// Reinitialize the container if we need to
if err := c.reinit(ctx); err != nil {
@@ -685,7 +688,7 @@ func (c *Container) Sync() error {
(c.state.State != ContainerStateConfigured) {
oldState := c.state.State
// TODO: optionally replace this with a stat for the exit file
- if err := c.runtime.ociRuntime.updateContainerStatus(c); err != nil {
+ if err := c.runtime.ociRuntime.updateContainerStatus(c, true); err != nil {
return err
}
// Only save back to DB if state changed
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index d928c4aed..d2f48d661 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -5,7 +5,6 @@ import (
"context"
"encoding/json"
"fmt"
- "github.com/opencontainers/runc/libcontainer/user"
"io"
"io/ioutil"
"os"
@@ -13,8 +12,10 @@ import (
"strconv"
"strings"
"syscall"
+ "time"
"github.com/containers/buildah/imagebuildah"
+ "github.com/containers/libpod/pkg/ctime"
"github.com/containers/libpod/pkg/hooks"
"github.com/containers/libpod/pkg/hooks/exec"
"github.com/containers/libpod/pkg/lookup"
@@ -25,12 +26,14 @@ import (
"github.com/containers/storage/pkg/archive"
"github.com/containers/storage/pkg/chrootarchive"
"github.com/containers/storage/pkg/mount"
+ "github.com/opencontainers/runc/libcontainer/user"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/opencontainers/runtime-tools/generate"
"github.com/opencontainers/selinux/go-selinux/label"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"golang.org/x/text/language"
+ kwait "k8s.io/apimachinery/pkg/util/wait"
)
const (
@@ -147,6 +150,77 @@ func (c *Container) execPidPath(sessionID string) string {
return filepath.Join(c.state.RunDir, "exec_pid_"+sessionID)
}
+// exitFilePath gets the path to the container's exit file
+func (c *Container) exitFilePath() string {
+ return filepath.Join(c.runtime.ociRuntime.exitsDir, c.ID())
+}
+
+// Wait for the container's exit file to appear.
+// When it does, update our state based on it.
+func (c *Container) waitForExitFileAndSync() error {
+ exitFile := c.exitFilePath()
+
+ err := kwait.ExponentialBackoff(
+ kwait.Backoff{
+ Duration: 500 * time.Millisecond,
+ Factor: 1.2,
+ Steps: 6,
+ },
+ func() (bool, error) {
+ _, err := os.Stat(exitFile)
+ if err != nil {
+ // wait longer
+ return false, nil
+ }
+ return true, nil
+ })
+ if err != nil {
+ // Exit file did not appear
+ // Reset our state
+ c.state.ExitCode = -1
+ c.state.FinishedTime = time.Now()
+ c.state.State = ContainerStateStopped
+
+ if err2 := c.save(); err2 != nil {
+ logrus.Errorf("Error saving container %s state: %v", c.ID(), err2)
+ }
+
+ return err
+ }
+
+ if err := c.runtime.ociRuntime.updateContainerStatus(c, false); err != nil {
+ return err
+ }
+
+ return c.save()
+}
+
+// Handle the container exit file.
+// The exit file is used to supply container exit time and exit code.
+// This assumes the exit file already exists.
+func (c *Container) handleExitFile(exitFile string, fi os.FileInfo) error {
+ c.state.FinishedTime = ctime.Created(fi)
+ statusCodeStr, err := ioutil.ReadFile(exitFile)
+ if err != nil {
+ return errors.Wrapf(err, "failed to read exit file for container %s", c.ID())
+ }
+ statusCode, err := strconv.Atoi(string(statusCodeStr))
+ if err != nil {
+ return errors.Wrapf(err, "error converting exit status code (%q) for container %s to int",
+ c.ID(), statusCodeStr)
+ }
+ c.state.ExitCode = int32(statusCode)
+
+ oomFilePath := filepath.Join(c.bundlePath(), "oom")
+ if _, err = os.Stat(oomFilePath); err == nil {
+ c.state.OOMKilled = true
+ }
+
+ c.state.Exited = true
+
+ return nil
+}
+
// Sync this container with on-disk state and runtime status
// Should only be called with container lock held
// This function should suffice to ensure a container's state is accurate and
@@ -162,7 +236,7 @@ func (c *Container) syncContainer() error {
(c.state.State != ContainerStateExited) {
oldState := c.state.State
// TODO: optionally replace this with a stat for the exit file
- if err := c.runtime.ociRuntime.updateContainerStatus(c); err != nil {
+ if err := c.runtime.ociRuntime.updateContainerStatus(c, false); err != nil {
return err
}
// Only save back to DB if state changed
@@ -623,9 +697,6 @@ func (c *Container) initAndStart(ctx context.Context) (err error) {
return errors.Wrapf(ErrCtrStateInvalid, "cannot start paused container %s", c.ID())
}
- if err := c.prepare(); err != nil {
- return err
- }
defer func() {
if err != nil {
if err2 := c.cleanup(ctx); err2 != nil {
@@ -634,6 +705,10 @@ func (c *Container) initAndStart(ctx context.Context) (err error) {
}
}()
+ if err := c.prepare(); err != nil {
+ return err
+ }
+
// If we are ContainerStateStopped we need to remove from runtime
// And reset to ContainerStateConfigured
if c.state.State == ContainerStateStopped {
@@ -673,13 +748,8 @@ func (c *Container) stop(timeout uint) error {
return err
}
- // Sync the container's state to pick up return code
- if err := c.runtime.ociRuntime.updateContainerStatus(c); err != nil {
- return err
- }
-
- // Container should clean itself up
- return nil
+ // Wait until we have an exit file, and sync once we do
+ return c.waitForExitFileAndSync()
}
// Internal, non-locking function to pause a container
@@ -719,9 +789,6 @@ func (c *Container) restartWithTimeout(ctx context.Context, timeout uint) (err e
return err
}
}
- if err := c.prepare(); err != nil {
- return err
- }
defer func() {
if err != nil {
if err2 := c.cleanup(ctx); err2 != nil {
@@ -729,6 +796,9 @@ func (c *Container) restartWithTimeout(ctx context.Context, timeout uint) (err e
}
}
}()
+ if err := c.prepare(); err != nil {
+ return err
+ }
if c.state.State == ContainerStateStopped {
// Reinitialize the container if we need to
@@ -1069,7 +1139,7 @@ func (c *Container) generatePasswd() (string, error) {
}
originPasswdFile := filepath.Join(c.state.Mountpoint, "/etc/passwd")
orig, err := ioutil.ReadFile(originPasswdFile)
- if err != nil {
+ if err != nil && !os.IsNotExist(err) {
return "", errors.Wrapf(err, "unable to read passwd file %s", originPasswdFile)
}
@@ -1157,6 +1227,10 @@ func (c *Container) generateHosts() (string, error) {
hosts += fmt.Sprintf("%s %s\n", fields[1], fields[0])
}
}
+ if len(c.state.NetworkStatus) > 0 && len(c.state.NetworkStatus[0].IPs) > 0 {
+ ipAddress := strings.Split(c.state.NetworkStatus[0].IPs[0].Address.String(), "/")[0]
+ hosts += fmt.Sprintf("%s\t%s\n", ipAddress, c.Hostname())
+ }
return c.writeStringToRundir("hosts", hosts)
}
diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go
index 7bf2c71ca..163cd75e7 100644
--- a/libpod/container_internal_linux.go
+++ b/libpod/container_internal_linux.go
@@ -360,19 +360,31 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro
g.AddMount(tmpfsMnt)
}
- cgroupPath, err := c.CGroupPath()
- if err != nil {
- return err
- }
- sourcePath := filepath.Join("/sys/fs/cgroup/systemd", cgroupPath)
+ // rootless containers have no write access to /sys/fs/cgroup, so don't
+ // add any mount into the container.
+ if !rootless.IsRootless() {
+ cgroupPath, err := c.CGroupPath()
+ if err != nil {
+ return err
+ }
+ sourcePath := filepath.Join("/sys/fs/cgroup/systemd", cgroupPath)
- systemdMnt := spec.Mount{
- Destination: "/sys/fs/cgroup/systemd",
- Type: "bind",
- Source: sourcePath,
- Options: []string{"bind", "private"},
+ systemdMnt := spec.Mount{
+ Destination: "/sys/fs/cgroup/systemd",
+ Type: "bind",
+ Source: sourcePath,
+ Options: []string{"bind", "private"},
+ }
+ g.AddMount(systemdMnt)
+ } else {
+ systemdMnt := spec.Mount{
+ Destination: "/sys/fs/cgroup/systemd",
+ Type: "bind",
+ Source: "/sys/fs/cgroup/systemd",
+ Options: []string{"bind", "nodev", "noexec", "nosuid"},
+ }
+ g.AddMount(systemdMnt)
}
- g.AddMount(systemdMnt)
return nil
}
@@ -484,9 +496,6 @@ func (c *Container) restore(ctx context.Context, keep bool) (err error) {
}
}
- if err := c.prepare(); err != nil {
- return err
- }
defer func() {
if err != nil {
if err2 := c.cleanup(ctx); err2 != nil {
@@ -495,6 +504,10 @@ func (c *Container) restore(ctx context.Context, keep bool) (err error) {
}
}()
+ if err := c.prepare(); err != nil {
+ return err
+ }
+
// TODO: use existing way to request static IPs, once it is merged in ocicni
// https://github.com/cri-o/ocicni/pull/23/
diff --git a/libpod/oci.go b/libpod/oci.go
index ca8f967c4..233bacfbb 100644
--- a/libpod/oci.go
+++ b/libpod/oci.go
@@ -11,12 +11,10 @@ import (
"os/exec"
"path/filepath"
"runtime"
- "strconv"
"strings"
"syscall"
"time"
- "github.com/containers/libpod/pkg/ctime"
"github.com/containers/libpod/pkg/rootless"
"github.com/containers/libpod/pkg/util"
"github.com/coreos/go-systemd/activation"
@@ -443,6 +441,7 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
}
return errors.Wrapf(ErrInternal, "container create failed")
}
+ ctr.state.PID = ss.si.Pid
case <-time.After(ContainerCreateTimeout):
return errors.Wrapf(ErrInternal, "container creation timeout")
}
@@ -451,17 +450,47 @@ func (r *OCIRuntime) createOCIContainer(ctr *Container, cgroupParent string, res
// updateContainerStatus retrieves the current status of the container from the
// runtime. It updates the container's state but does not save it.
-func (r *OCIRuntime) updateContainerStatus(ctr *Container) error {
- state := new(spec.State)
+// If useRunc is false, we will not directly hit runc to see the container's
+// status, but will instead only check for the existence of the conmon exit file
+// and update state to stopped if it exists.
+func (r *OCIRuntime) updateContainerStatus(ctr *Container, useRunc bool) error {
+ exitFile := ctr.exitFilePath()
runtimeDir, err := util.GetRootlessRuntimeDir()
if err != nil {
return err
}
+ // If not using runc, we don't need to do most of this.
+ if !useRunc {
+ // If the container's not running, nothing to do.
+ if ctr.state.State != ContainerStateRunning {
+ return nil
+ }
+
+ // Check for the exit file conmon makes
+ info, err := os.Stat(exitFile)
+ if err != nil {
+ if os.IsNotExist(err) {
+ // Container is still running, no error
+ return nil
+ }
+
+ return errors.Wrapf(err, "error running stat on container %s exit file", ctr.ID())
+ }
+
+ // Alright, it exists. Transition to Stopped state.
+ ctr.state.State = ContainerStateStopped
+
+ // Read the exit file to get our stopped time and exit code.
+ return ctr.handleExitFile(exitFile, info)
+ }
+
// Store old state so we know if we were already stopped
oldState := ctr.state.State
+ state := new(spec.State)
+
cmd := exec.Command(r.path, "state", ctr.ID())
cmd.Env = append(cmd.Env, fmt.Sprintf("XDG_RUNTIME_DIR=%s", runtimeDir))
outPipe, err := cmd.StdoutPipe()
@@ -480,6 +509,8 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container) error {
}
if strings.Contains(string(out), "does not exist") {
ctr.removeConmonFiles()
+ ctr.state.ExitCode = -1
+ ctr.state.FinishedTime = time.Now()
ctr.state.State = ContainerStateExited
return nil
}
@@ -514,7 +545,6 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container) error {
// Only grab exit status if we were not already stopped
// If we were, it should already be in the database
if ctr.state.State == ContainerStateStopped && oldState != ContainerStateStopped {
- exitFile := filepath.Join(r.exitsDir, ctr.ID())
var fi os.FileInfo
err = kwait.ExponentialBackoff(
kwait.Backoff{
@@ -538,24 +568,7 @@ func (r *OCIRuntime) updateContainerStatus(ctr *Container) error {
return nil
}
- ctr.state.FinishedTime = ctime.Created(fi)
- statusCodeStr, err := ioutil.ReadFile(exitFile)
- if err != nil {
- return errors.Wrapf(err, "failed to read exit file for container %s", ctr.ID())
- }
- statusCode, err := strconv.Atoi(string(statusCodeStr))
- if err != nil {
- return errors.Wrapf(err, "error converting exit status code for container %s to int",
- ctr.ID())
- }
- ctr.state.ExitCode = int32(statusCode)
-
- oomFilePath := filepath.Join(ctr.bundlePath(), "oom")
- if _, err = os.Stat(oomFilePath); err == nil {
- ctr.state.OOMKilled = true
- }
-
- ctr.state.Exited = true
+ return ctr.handleExitFile(exitFile, fi)
}
return nil
@@ -601,6 +614,8 @@ func (r *OCIRuntime) killContainer(ctr *Container, signal uint) error {
// Does not set finished time for container, assumes you will run updateStatus
// after to pull the exit code
func (r *OCIRuntime) stopContainer(ctr *Container, timeout uint) error {
+ logrus.Debugf("Stopping container %s (PID %d)", ctr.ID(), ctr.state.PID)
+
// Ping the container to see if it's alive
// If it's not, it's already stopped, return
err := unix.Kill(ctr.state.PID, 0)
diff --git a/libpod/runtime_ctr.go b/libpod/runtime_ctr.go
index b63726f29..09dc7c48b 100644
--- a/libpod/runtime_ctr.go
+++ b/libpod/runtime_ctr.go
@@ -256,7 +256,7 @@ func (r *Runtime) removeContainer(ctx context.Context, c *Container, force bool)
}
// Need to update container state to make sure we know it's stopped
- if err := c.syncContainer(); err != nil {
+ if err := c.waitForExitFileAndSync(); err != nil {
return err
}
} else if !(c.state.State == ContainerStateConfigured ||
diff --git a/libpod/runtime_pod_linux.go b/libpod/runtime_pod_linux.go
index eb3d471dd..3d6fad52f 100644
--- a/libpod/runtime_pod_linux.go
+++ b/libpod/runtime_pod_linux.go
@@ -265,15 +265,26 @@ func (r *Runtime) removePod(ctx context.Context, p *Pod, removeCtrs, force bool)
}
case CgroupfsCgroupsManager:
// Delete the cgroupfs cgroup
+ // Make sure the conmon cgroup is deleted first
+ // Since the pod is almost gone, don't bother failing
+ // hard - instead, just log errors.
v1CGroups := GetV1CGroups(getExcludedCGroups())
+ conmonCgroupPath := filepath.Join(p.state.CgroupPath, "conmon")
+ conmonCgroup, err := cgroups.Load(v1CGroups, cgroups.StaticPath(conmonCgroupPath))
+ if err != nil && err != cgroups.ErrCgroupDeleted {
+ return err
+ }
+ if err == nil {
+ if err := conmonCgroup.Delete(); err != nil {
+ 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
- } else if err == nil {
+ }
+ if err == nil {
if err := cgroup.Delete(); 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)
}
}
diff --git a/pkg/lookup/lookup.go b/pkg/lookup/lookup.go
index b27e2a724..a9d975b4b 100644
--- a/pkg/lookup/lookup.go
+++ b/pkg/lookup/lookup.go
@@ -1,10 +1,12 @@
package lookup
import (
+ "os"
+ "strconv"
+
"github.com/cyphar/filepath-securejoin"
"github.com/opencontainers/runc/libcontainer/user"
"github.com/sirupsen/logrus"
- "strconv"
)
const (
@@ -116,7 +118,7 @@ func GetUser(containerMount, userIDorName string) (*user.User, error) {
}
return u.Uid == uid
})
- if err != nil {
+ if err != nil && !os.IsNotExist(err) {
return nil, err
}
if len(users) > 0 {
@@ -146,7 +148,7 @@ func GetGroup(containerMount, groupIDorName string) (*user.Group, error) {
}
return g.Gid == gid
})
- if err != nil {
+ if err != nil && !os.IsNotExist(err) {
return nil, err
}
if len(groups) > 0 {
diff --git a/seccomp.json b/seccomp.json
index 19fadb4bb..fd0681a86 100644
--- a/seccomp.json
+++ b/seccomp.json
@@ -322,13 +322,13 @@
"stat64",
"statfs",
"statfs64",
+ "statx",
"symlink",
"symlinkat",
"sync",
"sync_file_range",
"syncfs",
"sysinfo",
- "syslog",
"tee",
"tgkill",
"time",
@@ -565,6 +565,7 @@
"setdomainname",
"sethostname",
"setns",
+ "syslog",
"umount",
"umount2",
"unshare"
@@ -750,6 +751,36 @@
]
},
"excludes": {}
+ },
+ {
+ "names": [
+ "get_mempolicy",
+ "mbind",
+ "set_mempolicy"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [],
+ "comment": "",
+ "includes": {
+ "caps": [
+ "CAP_SYS_NICE"
+ ]
+ },
+ "excludes": {}
+ },
+ {
+ "names": [
+ "syslog"
+ ],
+ "action": "SCMP_ACT_ALLOW",
+ "args": [],
+ "comment": "",
+ "includes": {
+ "caps": [
+ "CAP_SYSLOG"
+ ]
+ },
+ "excludes": {}
}
]
}
diff --git a/test/e2e/pause_test.go b/test/e2e/pause_test.go
index 24876b6d6..1a2eb1a09 100644
--- a/test/e2e/pause_test.go
+++ b/test/e2e/pause_test.go
@@ -250,6 +250,10 @@ var _ = Describe("Podman pause", func() {
running.WaitWithDefaultTimeout()
Expect(running.ExitCode()).To(Equal(0))
Expect(len(running.OutputToStringArray())).To(Equal(0))
+
+ unpause := podmanTest.Podman([]string{"unpause", "--all"})
+ unpause.WaitWithDefaultTimeout()
+ Expect(unpause.ExitCode()).To(Equal(0))
})
It("Unpause a bunch of running containers", func() {
diff --git a/test/e2e/run_dns_test.go b/test/e2e/run_dns_test.go
index c5a02c776..a617035a1 100644
--- a/test/e2e/run_dns_test.go
+++ b/test/e2e/run_dns_test.go
@@ -1,9 +1,9 @@
package integration
import (
+ "fmt"
"os"
- "fmt"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
@@ -83,4 +83,11 @@ var _ = Describe("Podman run dns", func() {
Expect(session.ExitCode()).To(Equal(0))
Expect(session.OutputToString()).To(Equal("foobar"))
})
+
+ It("podman run add hostname sets /etc/hosts", func() {
+ session := podmanTest.Podman([]string{"run", "-t", "-i", "--hostname=foobar", ALPINE, "cat", "/etc/hosts"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+ Expect(session.LineInOutputContains("foobar")).To(BeTrue())
+ })
})
diff --git a/version/version.go b/version/version.go
index 0fd4e5aeb..01b9b7a8d 100644
--- a/version/version.go
+++ b/version/version.go
@@ -4,4 +4,4 @@ package version
// NOTE: remember to bump the version at the top
// of the top-level README.md file when this is
// bumped.
-const Version = "0.10.2-dev"
+const Version = "0.11.2-dev"