summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cirrus.yml20
-rw-r--r--Makefile7
-rw-r--r--README.md2
-rw-r--r--RELEASE_NOTES.md17
-rw-r--r--cmd/podman/containers/create.go13
-rw-r--r--cmd/podman/containers/ps.go4
-rw-r--r--cmd/podman/containers/run.go2
-rw-r--r--cmd/podman/containers/stats.go4
-rw-r--r--cmd/podman/system/service.go5
-rw-r--r--contrib/spec/podman.spec.in4
-rw-r--r--contrib/systemd/system/podman.service4
-rw-r--r--docs/source/markdown/podman-generate-systemd.1.md12
-rw-r--r--libpod/container_internal.go35
-rw-r--r--libpod/define/errors.go16
-rw-r--r--libpod/events/journal_linux.go3
-rw-r--r--libpod/image/errors.go11
-rw-r--r--libpod/oci_conmon_exec_linux.go17
-rw-r--r--libpod/oci_conmon_linux.go17
-rw-r--r--libpod/runtime_img.go2
-rw-r--r--nix/nixpkgs.json6
-rw-r--r--pkg/api/handlers/compat/networks.go7
-rw-r--r--pkg/api/handlers/libpod/images.go10
-rw-r--r--pkg/api/handlers/libpod/networks.go6
-rw-r--r--pkg/api/handlers/utils/errors.go9
-rw-r--r--pkg/api/server/register_images.go4
-rw-r--r--pkg/api/server/register_ping.go9
-rw-r--r--pkg/api/server/register_volumes.go2
-rw-r--r--pkg/bindings/images/images.go1
-rw-r--r--pkg/domain/entities/volumes.go56
-rw-r--r--pkg/network/config.go5
-rw-r--r--pkg/network/files.go3
-rw-r--r--pkg/network/network.go3
-rw-r--r--pkg/rootless/rootless_linux.c2
-rw-r--r--pkg/rootless/rootless_linux.go35
-rw-r--r--pkg/specgen/generate/namespaces.go4
-rw-r--r--test/apiv2/01-basic.at8
-rw-r--r--test/apiv2/35-networks.at8
-rw-r--r--test/apiv2/rest_api/test_rest_v1_0_0.py21
-rw-r--r--test/e2e/commit_test.go15
-rw-r--r--test/e2e/ps_test.go8
-rw-r--r--test/e2e/run_test.go6
-rw-r--r--test/e2e/run_volume_test.go6
-rw-r--r--test/e2e/search_test.go10
-rw-r--r--test/endpoint/endpoint.go4
-rw-r--r--test/system/070-build.bats8
-rw-r--r--test/utils/utils.go6
-rw-r--r--utils/utils.go3
47 files changed, 326 insertions, 134 deletions
diff --git a/.cirrus.yml b/.cirrus.yml
index a8f3a2817..22f84d7ec 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -760,21 +760,33 @@ success_task:
static_build_task:
depends_on:
- "gating"
+
gce_instance:
image_name: "${FEDORA_CACHE_IMAGE_NAME}"
cpu: 8
memory: 12
disk: 200
- script: |
+
+ init_script: |
set -ex
setenforce 0
growpart /dev/sda 1 || true
resize2fs /dev/sda1 || true
yum -y install podman
+
+ nix_cache:
+ folder: '.cache'
+ fingerprint_script: |
+ echo "nix-v1-$(sha1sum nix/nixpkgs.json | head -c 40)"
+
+ build_script: |
+ set -ex
mkdir -p /nix
- podman run --rm --privileged -ti -v /:/mnt nixos/nix cp -rfT /nix /mnt/nix
+ mkdir -p .cache
+ mount --bind .cache /nix
+ if [[ -z $(ls -A /nix) ]]; then podman run --rm --privileged -ti -v /:/mnt nixos/nix cp -rfT /nix /mnt/nix; fi
podman run --rm --privileged -ti -v /nix:/nix -v ${PWD}:${PWD} -w ${PWD} nixos/nix nix --print-build-logs --option cores 8 --option max-jobs 8 build --file nix/
+ chown -Rf $(whoami) .cache
+
binaries_artifacts:
path: "result/bin/podman"
- on_failure:
- failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh |& ${TIMESTAMP}'
diff --git a/Makefile b/Makefile
index 51c2704b7..08a3cddac 100644
--- a/Makefile
+++ b/Makefile
@@ -572,9 +572,14 @@ endif
.PHONY: install.systemd
install.systemd: install.varlink
install ${SELINUXOPT} -m 755 -d ${DESTDIR}${SYSTEMDDIR} ${DESTDIR}${USERSYSTEMDDIR}
- # Install APIV2 services
+ # User services
+ install ${SELINUXOPT} -m 644 contrib/systemd/auto-update/podman-auto-update.service ${DESTDIR}${USERSYSTEMDDIR}/podman-auto-update.service
+ install ${SELINUXOPT} -m 644 contrib/systemd/auto-update/podman-auto-update.timer ${DESTDIR}${USERSYSTEMDDIR}/podman-auto-update.timer
install ${SELINUXOPT} -m 644 contrib/systemd/user/podman.socket ${DESTDIR}${USERSYSTEMDDIR}/podman.socket
install ${SELINUXOPT} -m 644 contrib/systemd/user/podman.service ${DESTDIR}${USERSYSTEMDDIR}/podman.service
+ # System services
+ install ${SELINUXOPT} -m 644 contrib/systemd/auto-update/podman-auto-update.service ${DESTDIR}${SYSTEMDDIR}/podman-auto-update.service
+ install ${SELINUXOPT} -m 644 contrib/systemd/auto-update/podman-auto-update.timer ${DESTDIR}${SYSTEMDDIR}/podman-auto-update.timer
install ${SELINUXOPT} -m 644 contrib/systemd/system/podman.socket ${DESTDIR}${SYSTEMDDIR}/podman.socket
install ${SELINUXOPT} -m 644 contrib/systemd/system/podman.service ${DESTDIR}${SYSTEMDDIR}/podman.service
diff --git a/README.md b/README.md
index 8065e4c49..50af1bdaf 100644
--- a/README.md
+++ b/README.md
@@ -5,7 +5,7 @@
Podman (the POD MANager) is a tool for managing containers and images, volumes mounted into those containers, and pods made from groups of containers.
Podman is based on libpod, a library for container lifecycle management that is also contained in this repository. The libpod library provides APIs for managing containers, pods, container images, and volumes.
-* [Latest Version: 2.0.3](https://github.com/containers/podman/releases/latest)
+* [Latest Version: 2.0.4](https://github.com/containers/podman/releases/latest)
* Latest Remote client for Windows
* Latest Remote client for MacOs
* Latest Static Remote client for Linux
diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md
index 48fe68ef9..d6b0eb3dd 100644
--- a/RELEASE_NOTES.md
+++ b/RELEASE_NOTES.md
@@ -1,5 +1,22 @@
# Release Notes
+## 2.0.4
+### Bugfixes
+- Fixed a bug where the output of `podman image search` did not populate the Description field as it was mistakenly assigned to the ID field.
+- Fixed a bug where `podman build -` and `podman build` on an HTTP target would fail.
+- Fixed a bug where rootless Podman would improperly chown the copied-up contents of anonymous volumes ([#7130](https://github.com/containers/podman/issues/7130)).
+- Fixed a bug where Podman would sometimes HTML-escape special characters in its CLI output.
+- Fixed a bug where the `podman start --attach --interactive` command would print the container ID of the container attached to when exiting ([#7068](https://github.com/containers/podman/pull/7068)).
+- Fixed a bug where `podman run --ipc=host --pid=host` would only set `--pid=host` and not `--ipc=host` ([#7100](https://github.com/containers/podman/issues/7100)).
+- Fixed a bug where the `--publish` argument to `podman run`, `podman create` and `podman pod create` would not allow binding the same container port to more than one host port ([#7062](https://github.com/containers/podman/issues/7062)).
+- Fixed a bug where incorrect arguments to `podman images --format` could cause Podman to segfault.
+- Fixed a bug where `podman rmi --force` on an image ID with more than one name and at least one container using the image would not completely remove containers using the image ([#7153](https://github.com/containers/podman/issues/7153)).
+- Fixed a bug where memory usage in bytes and memory use percentage were swapped in the output of `podman stats --format=json`.
+
+### API
+- Fixed a bug where the libpod and compat events endpoints would fail if no filters were specified ([#7078](https://github.com/containers/podman/issues/7078)).
+- Fixed a bug where the `CgroupVersion` field in responses from the compat Info endpoint was prefixed by "v" (instead of just being "1" or "2", as is documented).
+
## 2.0.3
### Features
- The `podman search` command now allows wildcards in search terms.
diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go
index dd77dc9d7..1516d15e9 100644
--- a/cmd/podman/containers/create.go
+++ b/cmd/podman/containers/create.go
@@ -124,7 +124,7 @@ func create(cmd *cobra.Command, args []string) error {
return err
}
- if _, err := createPodIfNecessary(s); err != nil {
+ if _, err := createPodIfNecessary(s, cliVals.Net); err != nil {
return err
}
@@ -283,7 +283,7 @@ func openCidFile(cidfile string) (*os.File, error) {
// createPodIfNecessary automatically creates a pod when requested. if the pod name
// has the form new:ID, the pod ID is created and the name in the spec generator is replaced
// with ID.
-func createPodIfNecessary(s *specgen.SpecGenerator) (*entities.PodCreateReport, error) {
+func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions) (*entities.PodCreateReport, error) {
if !strings.HasPrefix(s.Pod, "new:") {
return nil, nil
}
@@ -292,11 +292,10 @@ func createPodIfNecessary(s *specgen.SpecGenerator) (*entities.PodCreateReport,
return nil, errors.Errorf("new pod name must be at least one character")
}
createOptions := entities.PodCreateOptions{
- Name: podName,
- Infra: true,
- Net: &entities.NetOptions{
- PublishPorts: s.PortMappings,
- },
+ Name: podName,
+ Infra: true,
+ Net: netOpts,
+ CreateCommand: os.Args,
}
s.Pod = podName
return registry.ContainerEngine().PodCreate(context.Background(), createOptions)
diff --git a/cmd/podman/containers/ps.go b/cmd/podman/containers/ps.go
index 34fa4fab5..64271031d 100644
--- a/cmd/podman/containers/ps.go
+++ b/cmd/podman/containers/ps.go
@@ -307,6 +307,10 @@ func (l psReporter) Status() string {
return l.State()
}
+func (l psReporter) RunningFor() string {
+ return l.CreatedHuman()
+}
+
// Command returns the container command in string format
func (l psReporter) Command() string {
command := strings.Join(l.ListContainer.Command, " ")
diff --git a/cmd/podman/containers/run.go b/cmd/podman/containers/run.go
index 646c52645..d26aed826 100644
--- a/cmd/podman/containers/run.go
+++ b/cmd/podman/containers/run.go
@@ -176,7 +176,7 @@ func run(cmd *cobra.Command, args []string) error {
}
runOpts.Spec = s
- if _, err := createPodIfNecessary(s); err != nil {
+ if _, err := createPodIfNecessary(s, cliVals.Net); err != nil {
return err
}
diff --git a/cmd/podman/containers/stats.go b/cmd/podman/containers/stats.go
index 2b4c46647..ddb5f32ef 100644
--- a/cmd/podman/containers/stats.go
+++ b/cmd/podman/containers/stats.go
@@ -230,8 +230,8 @@ func outputJSON(stats []*containerStats) error {
Id: j.ID(),
Name: j.Name,
CpuPercent: j.CPUPerc(),
- MemUsage: j.MemPerc(),
- MemPerc: j.MemUsage(),
+ MemUsage: j.MemUsage(),
+ MemPerc: j.MemPerc(),
NetIO: j.NetIO(),
BlockIO: j.BlockIO(),
Pids: j.PIDS(),
diff --git a/cmd/podman/system/service.go b/cmd/podman/system/service.go
index 2d511f0ec..7c692b07e 100644
--- a/cmd/podman/system/service.go
+++ b/cmd/podman/system/service.go
@@ -49,7 +49,7 @@ func init() {
flags := srvCmd.Flags()
flags.Int64VarP(&srvArgs.Timeout, "time", "t", 5, "Time until the service session expires in seconds. Use 0 to disable the timeout")
- flags.BoolVar(&srvArgs.Varlink, "varlink", false, "Use legacy varlink service instead of REST")
+ flags.BoolVar(&srvArgs.Varlink, "varlink", false, "Use legacy varlink service instead of REST. Unit of --time changes from seconds to milliseconds.")
_ = flags.MarkDeprecated("varlink", "valink API is deprecated.")
flags.SetNormalizeFunc(aliasTimeoutFlag)
@@ -88,14 +88,15 @@ func service(cmd *cobra.Command, args []string) error {
opts := entities.ServiceOptions{
URI: apiURI,
- Timeout: time.Duration(srvArgs.Timeout) * time.Second,
Command: cmd,
}
if srvArgs.Varlink {
+ opts.Timeout = time.Duration(srvArgs.Timeout) * time.Millisecond
return registry.ContainerEngine().VarlinkService(registry.GetContext(), opts)
}
+ opts.Timeout = time.Duration(srvArgs.Timeout) * time.Second
return restService(opts, cmd.Flags(), registry.PodmanConfig())
}
diff --git a/contrib/spec/podman.spec.in b/contrib/spec/podman.spec.in
index 1795674e3..2411eaabc 100644
--- a/contrib/spec/podman.spec.in
+++ b/contrib/spec/podman.spec.in
@@ -500,10 +500,14 @@ export GOPATH=%{buildroot}/%{gopath}:$(pwd)/vendor:%{gopath}
%{_datadir}/zsh/site-functions/*
%{_libexecdir}/%{name}/conmon
%config(noreplace) %{_sysconfdir}/cni/net.d/87-%{name}-bridge.conflist
+%{_unitdir}/podman-auto-update.service
+%{_unitdir}/podman-auto-update.timer
%{_unitdir}/podman.service
%{_unitdir}/podman.socket
%{_usr}/lib/systemd/user/podman.service
%{_usr}/lib/systemd/user/podman.socket
+%{_usr}/lib/systemd/user/podman-auto-update.service
+%{_usr}/lib/systemd/user/podman-auto-update.timer
%if 0%{?with_devel}
%files -n libpod-devel -f devel.file-list
diff --git a/contrib/systemd/system/podman.service b/contrib/systemd/system/podman.service
index 4a63735a3..c8751168d 100644
--- a/contrib/systemd/system/podman.service
+++ b/contrib/systemd/system/podman.service
@@ -8,7 +8,3 @@ StartLimitIntervalSec=0
[Service]
Type=simple
ExecStart=/usr/bin/podman system service
-
-[Install]
-WantedBy=multi-user.target
-Also=podman.socket
diff --git a/docs/source/markdown/podman-generate-systemd.1.md b/docs/source/markdown/podman-generate-systemd.1.md
index 466c7e2bf..d0b1b3588 100644
--- a/docs/source/markdown/podman-generate-systemd.1.md
+++ b/docs/source/markdown/podman-generate-systemd.1.md
@@ -149,9 +149,9 @@ WantedBy=multi-user.target default.target
Podman-generated unit files include an `[Install]` section, which carries installation information for the unit. It is used by the enable and disable commands of systemctl(1) during installation.
-Once you have generated the systemd unit file, you can copy the generated systemd file to ```/usr/lib/systemd/system``` for installing as a root user and to ```$HOME/.config/systemd/user ``` for installing it as a non-root user. Enable the copied unit file or files using `systemctl enable`.
+Once you have generated the systemd unit file, you can copy the generated systemd file to ```/etc/systemd/system``` for installing as a root user and to ```$HOME/.config/systemd/user``` for installing it as a non-root user. Enable the copied unit file or files using `systemctl enable`.
-Note: Coping unit files to ```/usr/lib/systemd/system``` and enabling it marks the unit file to be automatically started at boot. And smillarly, coping a unit file to ```$HOME/.config/systemd/user ``` and enabling it marks the unit file to be automatically started on user login.
+Note: Coping unit files to ```/etc/systemd/system``` and enabling it marks the unit file to be automatically started at boot. And smillarly, coping a unit file to ```$HOME/.config/systemd/user``` and enabling it marks the unit file to be automatically started on user login.
```
@@ -162,14 +162,14 @@ $ podman generate systemd --files --name systemd-pod
# Copy all the generated files.
-$ sudo cp pod-systemd-pod.service container-great_payne.service /usr/lib/systemd/system
+$ sudo cp pod-systemd-pod.service container-great_payne.service /etc/systemd/system
$ systemctl enable pod-systemd-pod.service
-Created symlink /etc/systemd/system/multi-user.target.wants/pod-systemd-pod.service → /usr/lib/systemd/system/pod-systemd-pod.service.
-Created symlink /etc/systemd/system/default.target.wants/pod-systemd-pod.service → /usr/lib/systemd/system/pod-systemd-pod.service.
+Created symlink /etc/systemd/system/multi-user.target.wants/pod-systemd-pod.service → /etc/systemd/system/pod-systemd-pod.service.
+Created symlink /etc/systemd/system/default.target.wants/pod-systemd-pod.service → /etc/systemd/system/pod-systemd-pod.service.
$ systemctl is-enabled pod-systemd-pod.service
enabled
```
-To run the user services placed in `$HOME/.config/systemd/user/` on first login of that user, enable the service with --user flag.
+To run the user services placed in `$HOME/.config/systemd/user` on first login of that user, enable the service with --user flag.
```
$ systemctl --user enable <.service>
diff --git a/libpod/container_internal.go b/libpod/container_internal.go
index a5208a0df..f3f11f945 100644
--- a/libpod/container_internal.go
+++ b/libpod/container_internal.go
@@ -1534,9 +1534,6 @@ func (c *Container) chownVolume(volumeName string) error {
return errors.Wrapf(err, "error retrieving named volume %s for container %s", volumeName, c.ID())
}
- uid := int(c.config.Spec.Process.User.UID)
- gid := int(c.config.Spec.Process.User.GID)
-
vol.lock.Lock()
defer vol.lock.Unlock()
@@ -1547,22 +1544,34 @@ func (c *Container) chownVolume(volumeName string) error {
if vol.state.NeedsChown {
vol.state.NeedsChown = false
+
+ uid := int(c.config.Spec.Process.User.UID)
+ gid := int(c.config.Spec.Process.User.GID)
+
+ if c.config.IDMappings.UIDMap != nil {
+ p := idtools.IDPair{
+ UID: uid,
+ GID: gid,
+ }
+ mappings := idtools.NewIDMappingsFromMaps(c.config.IDMappings.UIDMap, c.config.IDMappings.GIDMap)
+ newPair, err := mappings.ToHost(p)
+ if err != nil {
+ return errors.Wrapf(err, "error mapping user %d:%d", uid, gid)
+ }
+ uid = newPair.UID
+ gid = newPair.GID
+ }
+
vol.state.UIDChowned = uid
vol.state.GIDChowned = gid
if err := vol.save(); err != nil {
return err
}
- err := filepath.Walk(vol.MountPoint(), func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if err := os.Lchown(path, uid, gid); err != nil {
- return err
- }
- return nil
- })
- if err != nil {
+
+ mountPoint := vol.MountPoint()
+
+ if err := os.Lchown(mountPoint, uid, gid); err != nil {
return err
}
}
diff --git a/libpod/define/errors.go b/libpod/define/errors.go
index 23d10f527..6e372eb5e 100644
--- a/libpod/define/errors.go
+++ b/libpod/define/errors.go
@@ -2,27 +2,27 @@ package define
import (
"errors"
-
- "github.com/containers/podman/v2/libpod/image"
- "github.com/containers/podman/v2/utils"
)
var (
// ErrNoSuchCtr indicates the requested container does not exist
- ErrNoSuchCtr = image.ErrNoSuchCtr
+ ErrNoSuchCtr = errors.New("no such container")
// ErrNoSuchPod indicates the requested pod does not exist
- ErrNoSuchPod = image.ErrNoSuchPod
+ ErrNoSuchPod = errors.New("no such pod")
// ErrNoSuchImage indicates the requested image does not exist
- ErrNoSuchImage = image.ErrNoSuchImage
+ ErrNoSuchImage = errors.New("no such image")
// ErrNoSuchTag indicates the requested image tag does not exist
- ErrNoSuchTag = image.ErrNoSuchTag
+ ErrNoSuchTag = errors.New("no such tag")
// ErrNoSuchVolume indicates the requested volume does not exist
ErrNoSuchVolume = errors.New("no such volume")
+ // ErrNoSuchNetwork indicates the requested network does not exist
+ ErrNoSuchNetwork = errors.New("network not found")
+
// ErrNoSuchExecSession indicates that the requested exec session does
// not exist.
ErrNoSuchExecSession = errors.New("no such exec session")
@@ -76,7 +76,7 @@ var (
// ErrDetach indicates that an attach session was manually detached by
// the user.
- ErrDetach = utils.ErrDetach
+ ErrDetach = errors.New("detached from container")
// ErrWillDeadlock indicates that the requested operation will cause a
// deadlock. This is usually caused by upgrade issues, and is resolved
diff --git a/libpod/events/journal_linux.go b/libpod/events/journal_linux.go
index 7c2a3e0f2..dc55dbc77 100644
--- a/libpod/events/journal_linux.go
+++ b/libpod/events/journal_linux.go
@@ -4,7 +4,6 @@ package events
import (
"context"
- "fmt"
"strconv"
"time"
@@ -50,7 +49,7 @@ func (e EventJournalD) Write(ee Event) error {
case Volume:
m["PODMAN_NAME"] = ee.Name
}
- return journal.Send(fmt.Sprintf("%s", ee.ToHumanReadable()), journal.PriInfo, m)
+ return journal.Send(string(ee.ToHumanReadable()), journal.PriInfo, m)
}
// Read reads events from the journal and sends qualified events to the event channel
diff --git a/libpod/image/errors.go b/libpod/image/errors.go
index ddbf7be4b..3f58b1c6a 100644
--- a/libpod/image/errors.go
+++ b/libpod/image/errors.go
@@ -1,17 +1,16 @@
package image
import (
- "errors"
+ "github.com/containers/podman/v2/libpod/define"
)
-// Copied directly from libpod errors to avoid circular imports
var (
// ErrNoSuchCtr indicates the requested container does not exist
- ErrNoSuchCtr = errors.New("no such container")
+ ErrNoSuchCtr = define.ErrNoSuchCtr
// ErrNoSuchPod indicates the requested pod does not exist
- ErrNoSuchPod = errors.New("no such pod")
+ ErrNoSuchPod = define.ErrNoSuchPod
// ErrNoSuchImage indicates the requested image does not exist
- ErrNoSuchImage = errors.New("no such image")
+ ErrNoSuchImage = define.ErrNoSuchImage
// ErrNoSuchTag indicates the requested image tag does not exist
- ErrNoSuchTag = errors.New("no such tag")
+ ErrNoSuchTag = define.ErrNoSuchTag
)
diff --git a/libpod/oci_conmon_exec_linux.go b/libpod/oci_conmon_exec_linux.go
index f8d87759a..cfe3745fa 100644
--- a/libpod/oci_conmon_exec_linux.go
+++ b/libpod/oci_conmon_exec_linux.go
@@ -449,9 +449,12 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
return nil, nil, err
}
+ var filesToClose []*os.File
if options.PreserveFDs > 0 {
for fd := 3; fd < int(3+options.PreserveFDs); fd++ {
- execCmd.ExtraFiles = append(execCmd.ExtraFiles, os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)))
+ f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd))
+ filesToClose = append(filesToClose, f)
+ execCmd.ExtraFiles = append(execCmd.ExtraFiles, f)
}
}
@@ -483,14 +486,10 @@ func (r *ConmonOCIRuntime) startExec(c *Container, sessionID string, options *Ex
return nil, nil, err
}
- if options.PreserveFDs > 0 {
- for fd := 3; fd < int(3+options.PreserveFDs); fd++ {
- // These fds were passed down to the runtime. Close them
- // and not interfere
- if err := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close(); err != nil {
- logrus.Debugf("unable to close file fd-%d", fd)
- }
- }
+ // These fds were passed down to the runtime. Close them
+ // and not interfere
+ for _, f := range filesToClose {
+ errorhandling.CloseQuiet(f)
}
return execCmd, pipes, nil
diff --git a/libpod/oci_conmon_linux.go b/libpod/oci_conmon_linux.go
index e677ece31..67593a68b 100644
--- a/libpod/oci_conmon_linux.go
+++ b/libpod/oci_conmon_linux.go
@@ -954,9 +954,12 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
return err
}
+ var filesToClose []*os.File
if ctr.config.PreserveFDs > 0 {
for fd := 3; fd < int(3+ctr.config.PreserveFDs); fd++ {
- cmd.ExtraFiles = append(cmd.ExtraFiles, os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)))
+ f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd))
+ filesToClose = append(filesToClose, f)
+ cmd.ExtraFiles = append(cmd.ExtraFiles, f)
}
}
@@ -1052,14 +1055,10 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
}
}
- if ctr.config.PreserveFDs > 0 {
- for fd := 3; fd < int(3+ctr.config.PreserveFDs); fd++ {
- // These fds were passed down to the runtime. Close them
- // and not interfere
- if err := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)).Close(); err != nil {
- logrus.Debugf("unable to close file fd-%d", fd)
- }
- }
+ // These fds were passed down to the runtime. Close them
+ // and not interfere
+ for _, f := range filesToClose {
+ errorhandling.CloseQuiet(f)
}
return nil
diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go
index 72cd26a4e..4b5129f44 100644
--- a/libpod/runtime_img.go
+++ b/libpod/runtime_img.go
@@ -51,7 +51,7 @@ func (r *Runtime) RemoveImage(ctx context.Context, img *image.Image, force bool)
imageCtrs = append(imageCtrs, ctr)
}
}
- if len(imageCtrs) > 0 && len(img.Names()) <= 1 {
+ if len(imageCtrs) > 0 && (len(img.Names()) <= 1 || (force && img.InputIsID())) {
if force {
for _, ctr := range imageCtrs {
if err := r.removeContainer(ctx, ctr, true, false, false); err != nil {
diff --git a/nix/nixpkgs.json b/nix/nixpkgs.json
index 98ed710a4..8eeb4f470 100644
--- a/nix/nixpkgs.json
+++ b/nix/nixpkgs.json
@@ -1,7 +1,7 @@
{
"url": "https://github.com/nixos/nixpkgs",
- "rev": "02591d02a910b3b92092153c5f3419a8d696aa1d",
- "date": "2020-07-09T03:52:28+02:00",
- "sha256": "1pp9v4rqmgx1b298gxix8b79m8pvxy1rcf8l25rxxxxnkr5ls1ng",
+ "rev": "b49e7987632e4c7ab3a093fdfc433e1826c4b9d7",
+ "date": "2020-07-26T09:18:52+02:00",
+ "sha256": "1mj6fy0p24izmasl653s5z4f2ka9v3b6mys45kjrqmkv889yk2r6",
"fetchSubmodules": false
}
diff --git a/pkg/api/handlers/compat/networks.go b/pkg/api/handlers/compat/networks.go
index 1e80cc91d..80b7505df 100644
--- a/pkg/api/handlers/compat/networks.go
+++ b/pkg/api/handlers/compat/networks.go
@@ -10,6 +10,7 @@ import (
"github.com/containernetworking/cni/libcni"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/abi"
@@ -44,9 +45,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
name := utils.GetName(r)
_, err = network.InspectNetwork(config, name)
if err != nil {
- // TODO our network package does not distinguish between not finding a
- // specific network vs not being able to read it
- utils.InternalServerError(w, err)
+ utils.NetworkNotFound(w, name, err)
return
}
report, err := getNetworkResourceByName(name, runtime)
@@ -285,7 +284,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
return
}
if !exists {
- utils.Error(w, "network not found", http.StatusNotFound, network.ErrNetworkNotFound)
+ utils.Error(w, "network not found", http.StatusNotFound, define.ErrNoSuchNetwork)
return
}
if err := network.RemoveNetwork(config, name); err != nil {
diff --git a/pkg/api/handlers/libpod/images.go b/pkg/api/handlers/libpod/images.go
index 3421f0836..51013acf1 100644
--- a/pkg/api/handlers/libpod/images.go
+++ b/pkg/api/handlers/libpod/images.go
@@ -594,11 +594,9 @@ func CommitContainer(w http.ResponseWriter, r *http.Request) {
return
}
- // I know mitr hates this ... but doing for now
- if len(query.Repo) > 1 {
+ if len(query.Repo) > 0 {
destImage = fmt.Sprintf("%s:%s", query.Repo, tag)
}
-
commitImage, err := ctr.Commit(r.Context(), destImage, options)
if err != nil && !strings.Contains(err.Error(), "is not running") {
utils.Error(w, "Something went wrong.", http.StatusInternalServerError, errors.Wrapf(err, "CommitFailure"))
@@ -638,6 +636,7 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
query := struct {
Term string `json:"term"`
Limit int `json:"limit"`
+ NoTrunc bool `json:"noTrunc"`
Filters []string `json:"filters"`
TLSVerify bool `json:"tlsVerify"`
}{
@@ -650,7 +649,8 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
}
options := image.SearchOptions{
- Limit: query.Limit,
+ Limit: query.Limit,
+ NoTrunc: query.NoTrunc,
}
if _, found := r.URL.Query()["tlsVerify"]; found {
options.InsecureSkipTLSVerify = types.NewOptionalBool(!query.TLSVerify)
@@ -677,7 +677,7 @@ func SearchImages(w http.ResponseWriter, r *http.Request) {
for i := range searchResults {
reports[i].Index = searchResults[i].Index
reports[i].Name = searchResults[i].Name
- reports[i].Description = searchResults[i].Index
+ reports[i].Description = searchResults[i].Description
reports[i].Stars = searchResults[i].Stars
reports[i].Official = searchResults[i].Official
reports[i].Automated = searchResults[i].Automated
diff --git a/pkg/api/handlers/libpod/networks.go b/pkg/api/handlers/libpod/networks.go
index 9237a41ce..475522664 100644
--- a/pkg/api/handlers/libpod/networks.go
+++ b/pkg/api/handlers/libpod/networks.go
@@ -5,10 +5,10 @@ import (
"net/http"
"github.com/containers/podman/v2/libpod"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/api/handlers/utils"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/containers/podman/v2/pkg/domain/infra/abi"
- "github.com/containers/podman/v2/pkg/network"
"github.com/gorilla/schema"
"github.com/pkg/errors"
)
@@ -78,7 +78,7 @@ func RemoveNetwork(w http.ResponseWriter, r *http.Request) {
}
if reports[0].Err != nil {
// If the network cannot be found, we return a 404.
- if errors.Cause(err) == network.ErrNetworkNotFound {
+ if errors.Cause(err) == define.ErrNoSuchNetwork {
utils.Error(w, "Something went wrong", http.StatusNotFound, err)
return
}
@@ -104,7 +104,7 @@ func InspectNetwork(w http.ResponseWriter, r *http.Request) {
reports, err := ic.NetworkInspect(r.Context(), []string{name}, options)
if err != nil {
// If the network cannot be found, we return a 404.
- if errors.Cause(err) == network.ErrNetworkNotFound {
+ if errors.Cause(err) == define.ErrNoSuchNetwork {
utils.Error(w, "Something went wrong", http.StatusNotFound, err)
return
}
diff --git a/pkg/api/handlers/utils/errors.go b/pkg/api/handlers/utils/errors.go
index 5a99529c6..bf9b18960 100644
--- a/pkg/api/handlers/utils/errors.go
+++ b/pkg/api/handlers/utils/errors.go
@@ -39,6 +39,7 @@ func VolumeNotFound(w http.ResponseWriter, name string, err error) {
msg := fmt.Sprintf("No such volume: %s", name)
Error(w, msg, http.StatusNotFound, err)
}
+
func ContainerNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchCtr {
InternalServerError(w, err)
@@ -55,6 +56,14 @@ func ImageNotFound(w http.ResponseWriter, name string, err error) {
Error(w, msg, http.StatusNotFound, err)
}
+func NetworkNotFound(w http.ResponseWriter, name string, err error) {
+ if errors.Cause(err) != define.ErrNoSuchNetwork {
+ InternalServerError(w, err)
+ }
+ msg := fmt.Sprintf("No such network: %s", name)
+ Error(w, msg, http.StatusNotFound, err)
+}
+
func PodNotFound(w http.ResponseWriter, name string, err error) {
if errors.Cause(err) != define.ErrNoSuchPod {
InternalServerError(w, err)
diff --git a/pkg/api/server/register_images.go b/pkg/api/server/register_images.go
index 7f060d098..cb4ce4fe7 100644
--- a/pkg/api/server/register_images.go
+++ b/pkg/api/server/register_images.go
@@ -972,6 +972,10 @@ func (s *APIServer) registerImagesHandlers(r *mux.Router) error {
// type: integer
// description: maximum number of results
// - in: query
+ // name: noTrunc
+ // type: boolean
+ // description: do not truncate any of the result strings
+ // - in: query
// name: filters
// type: string
// description: |
diff --git a/pkg/api/server/register_ping.go b/pkg/api/server/register_ping.go
index 4a8d2c768..4e299008c 100644
--- a/pkg/api/server/register_ping.go
+++ b/pkg/api/server/register_ping.go
@@ -9,9 +9,8 @@ import (
func (s *APIServer) registerPingHandlers(r *mux.Router) error {
- r.Handle("/_ping", s.APIHandler(compat.Ping)).Methods(http.MethodGet)
- r.Handle("/_ping", s.APIHandler(compat.Ping)).Methods(http.MethodHead)
-
+ r.Handle("/_ping", s.APIHandler(compat.Ping)).Methods(http.MethodGet, http.MethodHead)
+ r.Handle(VersionedPath("/_ping"), s.APIHandler(compat.Ping)).Methods(http.MethodGet, http.MethodHead)
// swagger:operation GET /libpod/_ping libpod libpodPingGet
// ---
// summary: Ping service
@@ -62,7 +61,7 @@ func (s *APIServer) registerPingHandlers(r *mux.Router) error {
// determine if talking to Podman engine or another engine
// 500:
// $ref: "#/responses/InternalError"
- r.Handle("/libpod/_ping", s.APIHandler(compat.Ping)).Methods(http.MethodGet)
- r.Handle("/libpod/_ping", s.APIHandler(compat.Ping)).Methods(http.MethodHead)
+ r.Handle("/libpod/_ping", s.APIHandler(compat.Ping)).Methods(http.MethodGet, http.MethodHead)
+ r.Handle(VersionedPath("/libpod/_ping"), s.APIHandler(compat.Ping)).Methods(http.MethodGet, http.MethodHead)
return nil
}
diff --git a/pkg/api/server/register_volumes.go b/pkg/api/server/register_volumes.go
index b509a332a..8f7848ed4 100644
--- a/pkg/api/server/register_volumes.go
+++ b/pkg/api/server/register_volumes.go
@@ -128,7 +128,7 @@ func (s *APIServer) registerVolumeHandlers(r *mux.Router) error {
// The boolean `dangling` filter is not yet implemented for this endpoint.
// responses:
// '200':
- // "$ref": "#/responses/DockerVolumeList"
+ // "$ref": "#/responses/VolumeListResponse"
// '500':
// "$ref": "#/responses/InternalError"
r.Handle(VersionedPath("/volumes"), s.APIHandler(compat.ListVolumes)).Methods(http.MethodGet)
diff --git a/pkg/bindings/images/images.go b/pkg/bindings/images/images.go
index fc8c9996e..12d1a9ce9 100644
--- a/pkg/bindings/images/images.go
+++ b/pkg/bindings/images/images.go
@@ -439,6 +439,7 @@ func Search(ctx context.Context, term string, opts entities.ImageSearchOptions)
params := url.Values{}
params.Set("term", term)
params.Set("limit", strconv.Itoa(opts.Limit))
+ params.Set("noTrunc", strconv.FormatBool(opts.NoTrunc))
for _, f := range opts.Filters {
params.Set("filters", f)
}
diff --git a/pkg/domain/entities/volumes.go b/pkg/domain/entities/volumes.go
index 2311d1f25..53d30ffdf 100644
--- a/pkg/domain/entities/volumes.go
+++ b/pkg/domain/entities/volumes.go
@@ -59,6 +59,42 @@ type VolumeConfigResponse struct {
Anonymous bool `json:"Anonymous"`
}
+// VolumeInfo Volume list response
+// swagger:model VolumeInfo
+type VolumeInfo struct {
+
+ // Date/Time the volume was created.
+ CreatedAt string `json:"CreatedAt,omitempty"`
+
+ // Name of the volume driver used by the volume. Only supports local driver
+ // Required: true
+ Driver string `json:"Driver"`
+
+ // User-defined key/value metadata.
+ // Always included
+ Labels map[string]string `json:"Labels"`
+
+ // Mount path of the volume on the host.
+ // Required: true
+ Mountpoint string `json:"Mountpoint"`
+
+ // Name of the volume.
+ // Required: true
+ Name string `json:"Name"`
+
+ // The driver specific options used when creating the volume.
+ // Required: true
+ Options map[string]string `json:"Options"`
+
+ // The level at which the volume exists.
+ // Libpod does not implement volume scoping, and this is provided solely for
+ // Docker compatibility. The value is only "local".
+ // Required: true
+ Scope string `json:"Scope"`
+
+ // TODO: We don't include the volume `Status` for now
+}
+
type VolumeRmOptions struct {
All bool
Force bool
@@ -94,17 +130,25 @@ type VolumeListReport struct {
VolumeConfigResponse
}
-/*
- * Docker API compatibility types
- */
-// swagger:response DockerVolumeList
-type SwagDockerVolumeListResponse struct {
+// VolumeListBody Volume list response
+// swagger:model VolumeListBody
+type VolumeListBody struct {
+ Volumes []*VolumeInfo
+}
+
+// Volume list response
+// swagger:response VolumeListResponse
+type SwagVolumeListResponse struct {
// in:body
Body struct {
- docker_api_types_volume.VolumeListOKBody
+ VolumeListBody
}
}
+/*
+ * Docker API compatibility types
+ */
+
// swagger:model DockerVolumeCreate
type DockerVolumeCreate docker_api_types_volume.VolumeCreateBody
diff --git a/pkg/network/config.go b/pkg/network/config.go
index a504e0ad0..0115433e1 100644
--- a/pkg/network/config.go
+++ b/pkg/network/config.go
@@ -2,7 +2,6 @@ package network
import (
"encoding/json"
- "errors"
"net"
)
@@ -20,10 +19,6 @@ const (
DefaultPodmanDomainName = "dns.podman"
)
-var (
- ErrNetworkNotFound = errors.New("network not found")
-)
-
// GetDefaultPodmanNetwork outputs the default network for podman
func GetDefaultPodmanNetwork() (*net.IPNet, error) {
_, n, err := net.ParseCIDR("10.88.1.0/24")
diff --git a/pkg/network/files.go b/pkg/network/files.go
index beb3289f3..38ce38b97 100644
--- a/pkg/network/files.go
+++ b/pkg/network/files.go
@@ -10,6 +10,7 @@ import (
"github.com/containernetworking/cni/libcni"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
"github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/pkg/errors"
)
@@ -55,7 +56,7 @@ func GetCNIConfigPathByName(config *config.Config, name string) (string, error)
return confFile, nil
}
}
- return "", errors.Wrap(ErrNetworkNotFound, fmt.Sprintf("unable to find network configuration for %s", name))
+ return "", errors.Wrap(define.ErrNoSuchNetwork, fmt.Sprintf("unable to find network configuration for %s", name))
}
// ReadRawCNIConfByName reads the raw CNI configuration for a CNI
diff --git a/pkg/network/network.go b/pkg/network/network.go
index 6c84c8a8a..b24c72f5f 100644
--- a/pkg/network/network.go
+++ b/pkg/network/network.go
@@ -8,6 +8,7 @@ import (
"github.com/containernetworking/cni/pkg/types"
"github.com/containernetworking/plugins/plugins/ipam/host-local/backend/allocator"
"github.com/containers/common/pkg/config"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/pkg/util"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -200,7 +201,7 @@ func InspectNetwork(config *config.Config, name string) (map[string]interface{},
func Exists(config *config.Config, name string) (bool, error) {
_, err := ReadRawCNIConfByName(config, name)
if err != nil {
- if errors.Cause(err) == ErrNetworkNotFound {
+ if errors.Cause(err) == define.ErrNoSuchNetwork {
return false, nil
}
return false, err
diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index d3e43e44d..eaf2d4551 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -860,7 +860,7 @@ reexec_in_user_namespace (int ready, char *pause_pid_file_path, char *file_to_re
fprintf (stderr, "cannot read from sync pipe: %s\n", strerror (errno));
_exit (EXIT_FAILURE);
}
- if (b != '0')
+ if (ret != 1 || b != '0')
_exit (EXIT_FAILURE);
if (syscall_setresgid (0, 0, 0) < 0)
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index b1f200cc2..ccc8a1d94 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -97,7 +97,11 @@ func GetRootlessGID() int {
return os.Getegid()
}
-func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap) error {
+func tryMappingTool(uid bool, pid int, hostID int, mappings []idtools.IDMap) error {
+ var tool = "newuidmap"
+ if !uid {
+ tool = "newgidmap"
+ }
path, err := exec.LookPath(tool)
if err != nil {
return errors.Wrapf(err, "cannot find %s", tool)
@@ -110,6 +114,15 @@ func tryMappingTool(tool string, pid int, hostID int, mappings []idtools.IDMap)
args := []string{path, fmt.Sprintf("%d", pid)}
args = appendTriplet(args, 0, hostID, 1)
for _, i := range mappings {
+ if hostID >= i.HostID && hostID < i.HostID+i.Size {
+ what := "UID"
+ where := "/etc/subuid"
+ if !uid {
+ what = "GID"
+ where = "/etc/subgid"
+ }
+ return errors.Errorf("invalid configuration: the specified mapping %d:%d in %q includes the user %s", i.HostID, i.Size, where, what)
+ }
args = appendTriplet(args, i.ContainerID+1, i.HostID, i.Size)
}
cmd := exec.Cmd{
@@ -175,7 +188,7 @@ func GetConfiguredMappings() ([]idtools.IDMap, []idtools.IDMap, error) {
return uids, gids, nil
}
-func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool, int, error) {
+func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (_ bool, _ int, retErr error) {
if os.Geteuid() == 0 || os.Getenv("_CONTAINERS_USERNS_CONFIGURED") != "" {
if os.Getenv("_CONTAINERS_USERNS_CONFIGURED") == "init" {
return false, 0, runInUser()
@@ -205,7 +218,11 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
defer errorhandling.CloseQuiet(r)
defer errorhandling.CloseQuiet(w)
defer func() {
- if _, err := w.Write([]byte("0")); err != nil {
+ toWrite := []byte("0")
+ if retErr != nil {
+ toWrite = []byte("1")
+ }
+ if _, err := w.Write(toWrite); err != nil {
logrus.Errorf("failed to write byte 0: %q", err)
}
}()
@@ -223,7 +240,11 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
uidsMapped := false
if uids != nil {
- err := tryMappingTool("newuidmap", pid, os.Geteuid(), uids)
+ err := tryMappingTool(true, pid, os.Geteuid(), uids)
+ // If some mappings were specified, do not ignore the error
+ if err != nil && len(uids) > 0 {
+ return false, -1, err
+ }
uidsMapped = err == nil
}
if !uidsMapped {
@@ -245,7 +266,11 @@ func becomeRootInUserNS(pausePid, fileToRead string, fileOutput *os.File) (bool,
gidsMapped := false
if gids != nil {
- err := tryMappingTool("newgidmap", pid, os.Getegid(), gids)
+ err := tryMappingTool(false, pid, os.Getegid(), gids)
+ // If some mappings were specified, do not ignore the error
+ if err != nil && len(gids) > 0 {
+ return false, -1, err
+ }
gidsMapped = err == nil
}
if !gidsMapped {
diff --git a/pkg/specgen/generate/namespaces.go b/pkg/specgen/generate/namespaces.go
index b8ab1399e..7adb8be6a 100644
--- a/pkg/specgen/generate/namespaces.go
+++ b/pkg/specgen/generate/namespaces.go
@@ -462,6 +462,10 @@ func specConfigureNamespaces(s *specgen.SpecGenerator, g *generate.Generator, rt
func GetNamespaceOptions(ns []string) ([]libpod.PodCreateOption, error) {
var options []libpod.PodCreateOption
var erroredOptions []libpod.PodCreateOption
+ if ns == nil {
+ //set the default namespaces
+ ns = strings.Split(specgen.DefaultKernelNamespaces, ",")
+ }
for _, toShare := range ns {
switch toShare {
case "cgroup":
diff --git a/test/apiv2/01-basic.at b/test/apiv2/01-basic.at
index 79dac990a..96b6aef7c 100644
--- a/test/apiv2/01-basic.at
+++ b/test/apiv2/01-basic.at
@@ -5,9 +5,15 @@
# NOTE: paths with a leading slash will be interpreted as-is;
# paths without will have '/v1.40/' prepended.
-t GET /_ping 200 OK
+t GET /_ping 200 OK
t HEAD /_ping 200
t GET /libpod/_ping 200 OK
+t HEAD /libpod/_ping 200
+
+t GET _ping 200 OK
+t HEAD _ping 200
+t GET libpod/_ping 200 OK
+t HEAD libpod/_ping 200
for i in /version version; do
t GET $i 200 \
diff --git a/test/apiv2/35-networks.at b/test/apiv2/35-networks.at
new file mode 100644
index 000000000..fff3f3b1f
--- /dev/null
+++ b/test/apiv2/35-networks.at
@@ -0,0 +1,8 @@
+# -*- sh -*-
+#
+# network-related tests
+#
+
+t GET /networks/non-existing-network 404
+
+# vim: filetype=sh
diff --git a/test/apiv2/rest_api/test_rest_v1_0_0.py b/test/apiv2/rest_api/test_rest_v1_0_0.py
index 7c53623cb..2e574e015 100644
--- a/test/apiv2/rest_api/test_rest_v1_0_0.py
+++ b/test/apiv2/rest_api/test_rest_v1_0_0.py
@@ -13,9 +13,11 @@ from multiprocessing import Process
import requests
from dateutil.parser import parse
+PODMAN_URL = "http://localhost:8080"
+
def _url(path):
- return "http://localhost:8080/v1.0.0/libpod" + path
+ return PODMAN_URL + "/v1.0.0/libpod" + path
def podman():
@@ -205,7 +207,21 @@ class TestApi(unittest.TestCase):
search.join(timeout=10)
self.assertFalse(search.is_alive(), "/images/search took too long")
- def validateObjectFields(self, buffer):
+ def test_ping(self):
+ r = requests.get(PODMAN_URL + "/_ping")
+ self.assertEqual(r.status_code, 200, r.text)
+
+ r = requests.head(PODMAN_URL + "/_ping")
+ self.assertEqual(r.status_code, 200, r.text)
+
+ r = requests.get(_url("/_ping"))
+ self.assertEqual(r.status_code, 200, r.text)
+
+ r = requests.get(_url("/_ping"))
+ self.assertEqual(r.status_code, 200, r.text)
+
+
+def validateObjectFields(self, buffer):
objs = json.loads(buffer)
if not isinstance(objs, dict):
for o in objs:
@@ -214,6 +230,5 @@ class TestApi(unittest.TestCase):
_ = objs["Id"]
return objs
-
if __name__ == '__main__':
unittest.main()
diff --git a/test/e2e/commit_test.go b/test/e2e/commit_test.go
index 568ee080d..c122ce50f 100644
--- a/test/e2e/commit_test.go
+++ b/test/e2e/commit_test.go
@@ -49,6 +49,21 @@ var _ = Describe("Podman commit", func() {
Expect(StringInSlice("foobar.com/test1-image:latest", data[0].RepoTags)).To(BeTrue())
})
+ It("podman commit single letter container", func() {
+ _, ec, _ := podmanTest.RunLsContainer("test1")
+ Expect(ec).To(Equal(0))
+ Expect(podmanTest.NumberOfContainers()).To(Equal(1))
+
+ session := podmanTest.Podman([]string{"commit", "test1", "a"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ check := podmanTest.Podman([]string{"inspect", "localhost/a:latest"})
+ check.WaitWithDefaultTimeout()
+ data := check.InspectImageJSON()
+ Expect(StringInSlice("localhost/a:latest", data[0].RepoTags)).To(BeTrue())
+ })
+
It("podman container commit container", func() {
_, ec, _ := podmanTest.RunLsContainer("test1")
Expect(ec).To(Equal(0))
diff --git a/test/e2e/ps_test.go b/test/e2e/ps_test.go
index 281968fcd..f10ef5c99 100644
--- a/test/e2e/ps_test.go
+++ b/test/e2e/ps_test.go
@@ -476,5 +476,13 @@ var _ = Describe("Podman ps", func() {
session.WaitWithDefaultTimeout()
Expect(session.OutputToString()).To(ContainSubstring("echo very long cr..."))
})
+ It("podman ps --format {{RunningFor}}", func() {
+ _, ec, _ := podmanTest.RunLsContainer("")
+ Expect(ec).To(Equal(0))
+ result := podmanTest.Podman([]string{"ps", "-a", "--format", "{{.RunningFor}}"})
+ result.WaitWithDefaultTimeout()
+ Expect(result.ExitCode()).To(Equal(0))
+ Expect(result.OutputToString()).To(ContainSubstring("ago"))
+ })
})
diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go
index 1f9cc3cb0..6bb12b54a 100644
--- a/test/e2e/run_test.go
+++ b/test/e2e/run_test.go
@@ -812,7 +812,11 @@ USER mail`
})
It("podman run --pod automatically", func() {
- session := podmanTest.Podman([]string{"run", "--pod", "new:foobar", ALPINE, "ls"})
+ session := podmanTest.Podman([]string{"run", "-d", "--pod", "new:foobar", ALPINE, "nc", "-l", "-p", "8080"})
+ session.WaitWithDefaultTimeout()
+ Expect(session.ExitCode()).To(Equal(0))
+
+ session = podmanTest.Podman([]string{"run", "--pod", "foobar", ALPINE, "/bin/sh", "-c", "echo test | nc -w 1 127.0.0.1 8080"})
session.WaitWithDefaultTimeout()
Expect(session.ExitCode()).To(Equal(0))
diff --git a/test/e2e/run_volume_test.go b/test/e2e/run_volume_test.go
index c729423a3..c4ee05af9 100644
--- a/test/e2e/run_volume_test.go
+++ b/test/e2e/run_volume_test.go
@@ -241,7 +241,7 @@ var _ = Describe("Podman run with volumes", func() {
Expect(mountCmd1.ExitCode()).To(Equal(0))
os.Stdout.Sync()
os.Stderr.Sync()
- mountOut1 := strings.Join(strings.Fields(fmt.Sprintf("%s", mountCmd1.Out.Contents())), " ")
+ mountOut1 := strings.Join(strings.Fields(string(mountCmd1.Out.Contents())), " ")
fmt.Printf("Output: %s", mountOut1)
Expect(strings.Contains(mountOut1, volName)).To(BeFalse())
@@ -257,7 +257,7 @@ var _ = Describe("Podman run with volumes", func() {
Expect(mountCmd2.ExitCode()).To(Equal(0))
os.Stdout.Sync()
os.Stderr.Sync()
- mountOut2 := strings.Join(strings.Fields(fmt.Sprintf("%s", mountCmd2.Out.Contents())), " ")
+ mountOut2 := strings.Join(strings.Fields(string(mountCmd2.Out.Contents())), " ")
fmt.Printf("Output: %s", mountOut2)
Expect(strings.Contains(mountOut2, volName)).To(BeTrue())
@@ -278,7 +278,7 @@ var _ = Describe("Podman run with volumes", func() {
Expect(mountCmd3.ExitCode()).To(Equal(0))
os.Stdout.Sync()
os.Stderr.Sync()
- mountOut3 := strings.Join(strings.Fields(fmt.Sprintf("%s", mountCmd3.Out.Contents())), " ")
+ mountOut3 := strings.Join(strings.Fields(string(mountCmd3.Out.Contents())), " ")
fmt.Printf("Output: %s", mountOut3)
Expect(strings.Contains(mountOut3, volName)).To(BeFalse())
})
diff --git a/test/e2e/search_test.go b/test/e2e/search_test.go
index 1e7dff697..c6766fe2a 100644
--- a/test/e2e/search_test.go
+++ b/test/e2e/search_test.go
@@ -5,6 +5,7 @@ import (
"fmt"
"io/ioutil"
"os"
+ "regexp"
"strconv"
"text/template"
@@ -98,6 +99,15 @@ registries = ['{{.Host}}:{{.Port}}']`
Expect(search.LineInOutputContains("quay.io/libpod/gate")).To(BeTrue())
})
+ It("podman search image with description", func() {
+ search := podmanTest.Podman([]string{"search", "quay.io/libpod/whalesay"})
+ search.WaitWithDefaultTimeout()
+ Expect(search.ExitCode()).To(Equal(0))
+ output := string(search.Out.Contents())
+ match, _ := regexp.MatchString(`(?m)^quay.io\s+quay.io/libpod/whalesay\s+Static image used for automated testing.+$`, output)
+ Expect(match).To(BeTrue())
+ })
+
It("podman search format flag", func() {
search := podmanTest.Podman([]string{"search", "--format", "table {{.Index}} {{.Name}}", "alpine"})
search.WaitWithDefaultTimeout()
diff --git a/test/endpoint/endpoint.go b/test/endpoint/endpoint.go
index 0593b05cd..d2c143824 100644
--- a/test/endpoint/endpoint.go
+++ b/test/endpoint/endpoint.go
@@ -192,12 +192,12 @@ func (p *EndpointTestIntegration) Varlink(endpoint, message string, more bool) *
}
func (s *EndpointSession) StdErrToString() string {
- fields := strings.Fields(fmt.Sprintf("%s", s.Err.Contents()))
+ fields := strings.Fields(string(s.Err.Contents()))
return strings.Join(fields, " ")
}
func (s *EndpointSession) OutputToString() string {
- fields := strings.Fields(fmt.Sprintf("%s", s.Out.Contents()))
+ fields := strings.Fields(string(s.Out.Contents()))
return strings.Join(fields, " ")
}
diff --git a/test/system/070-build.bats b/test/system/070-build.bats
index 627b9caa6..a69d32a2f 100644
--- a/test/system/070-build.bats
+++ b/test/system/070-build.bats
@@ -143,7 +143,7 @@ RUN mkdir -p /a/b/c
RUN ln -s /no/such/nonesuch /a/b/c/badsymlink
RUN ln -s /bin/mydefaultcmd /a/b/c/goodsymlink
RUN touch /a/b/c/myfile
-RUN chown -h 1:2 /a/b/c/badsymlink /a/b/c/goodsymlink /a/b/c/myfile
+RUN chown -h 1:2 /a/b/c/badsymlink /a/b/c/goodsymlink && chown -h 4:5 /a/b/c/myfile
VOLUME /a/b/c
# Test for environment passing and override
@@ -216,18 +216,18 @@ Labels.$label_name | $label_value
# be they dangling or valid, would barf with
# Error: chown <mountpath>/_data/symlink: ENOENT
run_podman run --rm build_test stat -c'%u:%g:%N' /a/b/c/badsymlink
- is "$output" "0:0:'/a/b/c/badsymlink' -> '/no/such/nonesuch'" \
+ is "$output" "1:2:'/a/b/c/badsymlink' -> '/no/such/nonesuch'" \
"bad symlink to nonexistent file is chowned and preserved"
run_podman run --rm build_test stat -c'%u:%g:%N' /a/b/c/goodsymlink
- is "$output" "0:0:'/a/b/c/goodsymlink' -> '/bin/mydefaultcmd'" \
+ is "$output" "1:2:'/a/b/c/goodsymlink' -> '/bin/mydefaultcmd'" \
"good symlink to existing file is chowned and preserved"
run_podman run --rm build_test stat -c'%u:%g' /bin/mydefaultcmd
is "$output" "2:3" "target of symlink is not chowned"
run_podman run --rm build_test stat -c'%u:%g:%N' /a/b/c/myfile
- is "$output" "0:0:/a/b/c/myfile" "file in volume is chowned to root"
+ is "$output" "4:5:/a/b/c/myfile" "file in volume is chowned"
# Clean up
run_podman rmi -f build_test
diff --git a/test/utils/utils.go b/test/utils/utils.go
index 0597cd292..2c454f532 100644
--- a/test/utils/utils.go
+++ b/test/utils/utils.go
@@ -215,7 +215,7 @@ func (s *PodmanSession) OutputToString() string {
// where each array item is a line split by newline
func (s *PodmanSession) OutputToStringArray() []string {
var results []string
- output := fmt.Sprintf("%s", s.Out.Contents())
+ output := string(s.Out.Contents())
for _, line := range strings.Split(output, "\n") {
if line != "" {
results = append(results, line)
@@ -226,14 +226,14 @@ func (s *PodmanSession) OutputToStringArray() []string {
// ErrorToString formats session stderr to string
func (s *PodmanSession) ErrorToString() string {
- fields := strings.Fields(fmt.Sprintf("%s", s.Err.Contents()))
+ fields := strings.Fields(string(s.Err.Contents()))
return strings.Join(fields, " ")
}
// ErrorToStringArray returns the stderr output as a []string
// where each array item is a line split by newline
func (s *PodmanSession) ErrorToStringArray() []string {
- output := fmt.Sprintf("%s", s.Err.Contents())
+ output := string(s.Err.Contents())
return strings.Split(output, "\n")
}
diff --git a/utils/utils.go b/utils/utils.go
index 27ce1821d..a6ef663d7 100644
--- a/utils/utils.go
+++ b/utils/utils.go
@@ -9,6 +9,7 @@ import (
"strconv"
"strings"
+ "github.com/containers/podman/v2/libpod/define"
"github.com/containers/storage/pkg/archive"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -51,7 +52,7 @@ func ExecCmdWithStdStreams(stdin io.Reader, stdout, stderr io.Writer, env []stri
// ErrDetach is an error indicating that the user manually detached from the
// container.
-var ErrDetach = errors.New("detached from container")
+var ErrDetach = define.ErrDetach
// CopyDetachable is similar to io.Copy but support a detach key sequence to break out.
func CopyDetachable(dst io.Writer, src io.Reader, keys []byte) (written int64, err error) {