diff options
38 files changed, 594 insertions, 166 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 09f13a7d0..9d64bb5ab 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -34,14 +34,15 @@ env: CRIU_COMMIT: "c74b83cd49c00589c0c0468ba5fe685b67fdbd0a" RUNC_COMMIT: "25f3f893c86d07426df93b7aa172f33fdf093fbd" # CSV of cache-image names to build (see $PACKER_BASE/libpod_images.json) - PACKER_BUILDS: "ubuntu-18,fedora-29" # TODO: fah-29,rhel-7,centos-7 + PACKER_BUILDS: "ubuntu-18,fedora-29,fedora-28" # TODO: fah-29,rhel-7,centos-7 # Version of packer to use PACKER_VER: "1.3.1" # Google-maintained base-image names UBUNTU_BASE_IMAGE: "ubuntu-1804-bionic-v20181203a" CENTOS_BASE_IMAGE: "centos-7-v20181113" # Manually produced base-image names (see $SCRIPT_BASE/README.md) - FEDORA_BASE_IMAGE: "fedora-cloud-base-29-1-2-1541789245" + FEDORA_BASE_IMAGE: "fedora-cloud-base-29-1-2-1541789245" + PRIOR_FEDORA_BASE_IMAGE: "fedora-cloud-base-28-1-1-1544474897" FAH_BASE_IMAGE: "fedora-atomichost-29-20181025-1-1541787861" # RHEL image must be imported, google bills extra for their native image. RHEL_BASE_IMAGE: "rhel-guest-image-7-6-210-x86-64-qcow2-1541783972" @@ -106,13 +107,15 @@ testing_task: zone: "us-central1-a" # Required by Cirrus for the time being cpu: 2 memory: "4Gb" - disk: 40 + disk: 200 # see https://developers.google.com/compute/docs/disks#performance # Generate multiple parallel tasks, covering all possible # 'matrix' combinations. matrix: # Images are generated separately, from build_images_task (below) - image_name: "ubuntu-18-libpod-0c954a67" - image_name: "fedora-29-libpod-0c954a67" + image_name: "ubuntu-18-libpod-86d821ea" + image_name: "fedora-28-libpod-86d821ea" + image_name: "fedora-29-libpod-86d821ea" + # TODO: tests fail # image_name: "rhel-7-something-something" # image_name: "centos-7-something-something" @@ -148,8 +151,9 @@ optional_testing_task: gce_instance: image_project: "libpod-218412" matrix: - image_name: "ubuntu-18-libpod-0c954a67" - image_name: "fedora-29-libpod-0c954a67" + image_name: "ubuntu-18-libpod-86d821ea" + image_name: "fedora-28-libpod-86d821ea" + image_name: "fedora-29-libpod-86d821ea" # TODO: Make these work (also build_images_task below) #image_name: "rhel-server-ec2-7-5-165-1-libpod-fce09afe" #image_name: "centos-7-v20180911-libpod-fce09afe" @@ -185,7 +189,7 @@ cache_images_task: zone: "us-central1-a" # Required by Cirrus for the time being cpu: 4 memory: "4Gb" - disk: 20 + disk: 200 image_name: "image-builder-image-1541772081" # Simply CentOS 7 + packer dependencies # Additional permissions for building GCE images, within a GCE VM scopes: @@ -22,33 +22,33 @@ context: "FAH28 - Containerized (Podman in Podman)" --- - host: - distro: centos/7/atomic/smoketested - specs: - ram: 8192 - cpus: 4 - extra-repos: - - name: epel - metalink: https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch - gpgcheck: 0 - - name: cri-o - baseurl: https://cbs.centos.org/repos/virt7-container-common-candidate/$basearch/os - gpgcheck: 0 - - required: true +host: + distro: centos/7/atomic/smoketested + specs: + ram: 8192 + cpus: 4 +extra-repos: + - name: epel + metalink: https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch + gpgcheck: 0 + - name: cri-o + baseurl: https://cbs.centos.org/repos/virt7-container-common-candidate/$basearch/os + gpgcheck: 0 - timeout: 90m +required: true - tests: - - CONTAINER_RUNTIME="docker" sh .papr_prepare.sh +timeout: 90m - artifacts: - - build.log +tests: + - CONTAINER_RUNTIME="docker" sh .papr_prepare.sh - context: "CAH 7-smoketested - Containerized (Podman in Docker)" +artifacts: + - build.log ---- +context: "CAH 7-smoketested - Containerized (Podman in Docker)" +#--- +# #host: # distro: centos/7/cloud # specs: @@ -95,41 +95,3 @@ context: "FAH28 - Containerized (Podman in Podman)" #context: "CentOS 7 Cloud" # #--- - -host: - distro: fedora/28/cloud - specs: - ram: 8192 - cpus: 4 -packages: - - btrfs-progs-devel - - glib2-devel - - glibc-devel - - glibc-static - - git - - go-md2man - - gpgme-devel - - libassuan-devel - - libgpg-error-devel - - libseccomp-devel - - libselinux-devel - - ostree-devel - - pkgconfig - - make - - nc - - go-compilers-golang-compiler - - podman - - python3-varlink - - python3-dateutil - - python3-psutil - - https://kojipkgs.fedoraproject.org//packages/runc/1.0.0/54.dev.git00dc700.fc28/x86_64/runc-1.0.0-54.dev.git00dc700.fc28.x86_64.rpm - -tests: - - sed 's/^expand-check.*/expand-check=0/g' -i /etc/selinux/semanage.conf - - yum -y reinstall container-selinux - - sh .papr.sh -b -i -t -p - -required: false - -timeout: 90m -context: "Fedora 28 Cloud" diff --git a/Dockerfile b/Dockerfile index 08af0f851..c227207bd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM golang:1.10 +FROM golang:1.11 RUN echo 'deb http://httpredir.debian.org/debian jessie-backports main' > /etc/apt/sources.list.d/backports.list @@ -1,6 +1,6 @@ GO ?= go DESTDIR ?= / -EPOCH_TEST_COMMIT ?= 1a5024193094a178cd93b675a0178062236c4a22 +EPOCH_TEST_COMMIT ?= e1732a5213147e3c0b7bf60b55a332c3720ecb4b HEAD ?= HEAD CHANGELOG_BASE ?= HEAD~ CHANGELOG_TARGET ?= HEAD @@ -165,7 +165,7 @@ integration.centos: DIST=CentOS sh .papr_prepare.sh shell: libpodimage - ${CONTAINER_RUNTIME} run --tmpfs -e STORAGE_OPTIONS="--storage-driver=vfs" -e CGROUP_MANAGER=cgroupfs -e TESTFLAGS -e TRAVIS -it --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} sh + ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e CGROUP_MANAGER=cgroupfs -e TESTFLAGS -e TRAVIS -it --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} sh testunit: libpodimage ${CONTAINER_RUNTIME} run -e STORAGE_OPTIONS="--storage-driver=vfs" -e TESTFLAGS -e CGROUP_MANAGER=cgroupfs -e TRAVIS -t --privileged --rm -v ${CURDIR}:/go/src/${PROJECT} ${LIBPOD_IMAGE} make localunit @@ -1,15 +1,15 @@ ![PODMAN logo](logo/podman-logo-source.svg) -# libpod - library for running OCI-based containers in Pods -### Latest Version: 0.12.1 -### Status: Active Development +# Library and tool for running OCI-based containers in Pods -### Continuous Integration: [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod) +Libpod provides a library for applications looking to use the Container Pod concept, +popularized by Kubernetes. libpod also contains the `podman` tool, for managing +Pods, Containers, and Container Images. -## What is the scope of this project? +* [Latest Version: 0.12.1](https://github.com/containers/libpod/releases/latest) +* [Continuous Integration:](contrib/cirrus/README.md) [![Build Status](https://api.cirrus-ci.com/github/containers/libpod.svg)](https://cirrus-ci.com/github/containers/libpod/master) -libpod provides a library for applications looking to use the Container Pod concept popularized by Kubernetes. -libpod also contains a tool called podman for managing Pods, Containers, and Container Images. +## Overview and scope At a high level, the scope of libpod and podman is the following: @@ -19,11 +19,22 @@ At a high level, the scope of libpod and podman is the following: * Full management of container lifecycle * Support for pods to manage groups of containers together * Resource isolation of containers and pods. +* Integration with CRI-O to share containers and backend code. -## What is not in scope for this project? +## Roadmap -* Signing and pushing images to various image storages. See [Skopeo](https://github.com/containers/skopeo/). -* Container Runtimes daemons for working with Kubernetes CRIs. See [CRI-O](https://github.com/kubernetes-sigs/cri-o). We are working to integrate libpod into CRI-O to share containers and backend code with Podman. +1. Python frontend for Varlink API +1. Integrate libpod into CRI-O to replace its existing container management backend +1. Further work on the podman pod command +1. Further improvements on rootless containers +1. In-memory locking to replace file locks + +## Out of scope + +* Signing and pushing images to various image storages. + See [Skopeo](https://github.com/containers/skopeo/). +* Container Runtimes daemons for working with Kubernetes CRIs. + See [CRI-O](https://github.com/kubernetes-sigs/cri-o). ## OCI Projects Plans @@ -68,14 +79,6 @@ Release notes for recent Podman versions **[Contributing](CONTRIBUTING.md)** Information about contributing to this project. -## Current Roadmap - -1. Python frontend for Varlink API -1. Integrate libpod into CRI-O to replace its existing container management backend -1. Further work on the podman pod command -1. Further improvements on rootless containers -1. In-memory locking to replace file locks - [spec-hooks]: https://github.com/opencontainers/runtime-spec/blob/v2.0.1/config.md#posix-platform-hooks ## Buildah and Podman relationship diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index b793788cd..2d7ca6cbf 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,5 +1,12 @@ # Release Notes +## 0.12.1.2 +### Bugfixes +- Fixed a bug where an empty path for named volumes could make it impossible to create containers +- Fixed a bug where containers using another container's network namespace would not also use the other container's /etc/hosts and /etc/resolv.conf +- Fixed a bug where containers with `--rm` which failed to start were not removed +- Fixed a potential race condition attempting to read `/etc/passwd` inside containers + ## 0.12.1.1 ### Features - Added the `podman generate kube` command to generate Kubernetes Pod and Service YAML for Podman containers and pods diff --git a/changelog.txt b/changelog.txt index bc141cceb..b0680a02c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,29 @@ +- Changelog for v0.12.1.2 (2018-12-13) + * Add release notes for 0.12.1.2 + * runlabel should sub podman for docker|/usr/bin/docker + * condition fixed for adding volume to boltdb. + * e2e: add tests for systemd + * Add test for sharing resolv and hosts with netns + * Makefile tweaks to fix make shell + * failed containers with --rm should remove themselves + * Fix documentation links and flow + * Set Socket label for contianer + * Containers sharing a netns should share resolv/hosts + * Prevent a second lookup of user for image volumes + * fix typo in kubernetes + * No need to use `-i` in go build (with go 1.10 and above) + * rootless: fix restart when using fuse-overlayfs + * Cirrus: Update base-image build docs + * Add capabilities to generate kube + * disable F29 tests on PAPR + * Ensure storage options are properly initialized + * add more example usage to varlink endpoints + * Update for API change + * Vendor buildah after merging mtrmac/blob-info-caching-on-top-of-contents-caching + * Vendor c/image after merging c/image#536 + * Bump gitvalidation epoch + * Bump to v0.12.2-dev + - Changelog for v0.12.1.1 (2018-12-07) * Update release notes for v0.12.1.1 * Fix errors where OCI hooks directory does not exist diff --git a/cmd/podman/generate_kube.go b/cmd/podman/generate_kube.go index de9f701b0..6483ffd72 100644 --- a/cmd/podman/generate_kube.go +++ b/cmd/podman/generate_kube.go @@ -88,7 +88,7 @@ func generateKubeYAMLCmd(c *cli.Context) error { return err } - header := `# Generation of Kubenetes YAML is still under development! + header := `# Generation of Kubernetes YAML is still under development! # # Save the output of this file and use kubectl create -f to import # it into Kubernetes. diff --git a/cmd/podman/main.go b/cmd/podman/main.go index 796b0b03a..2db6c5dec 100644 --- a/cmd/podman/main.go +++ b/cmd/podman/main.go @@ -34,6 +34,7 @@ var cmdsNotRequiringRootless = map[string]bool{ // If this change, please also update libpod.refreshRootless() "login": true, "logout": true, + "mount": true, "kill": true, "pause": true, "restart": true, diff --git a/cmd/podman/mount.go b/cmd/podman/mount.go index 585f506cd..c91115597 100644 --- a/cmd/podman/mount.go +++ b/cmd/podman/mount.go @@ -3,9 +3,11 @@ package main import ( js "encoding/json" "fmt" + "os" of "github.com/containers/libpod/cmd/podman/formats" "github.com/containers/libpod/cmd/podman/libpodruntime" + "github.com/containers/libpod/pkg/rootless" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -52,6 +54,9 @@ func mountCmd(c *cli.Context) error { if err := validateFlags(c, mountFlags); err != nil { return err } + if os.Geteuid() != 0 { + rootless.SetSkipStorageSetup(true) + } runtime, err := libpodruntime.GetRuntime(c) if err != nil { @@ -59,6 +64,22 @@ func mountCmd(c *cli.Context) error { } defer runtime.Shutdown(false) + if os.Geteuid() != 0 { + if driver := runtime.GetConfig().StorageConfig.GraphDriverName; driver != "vfs" { + // Do not allow to mount a graphdriver that is not vfs if we are creating the userns as part + // of the mount command. + return fmt.Errorf("cannot mount using driver %s in rootless mode", driver) + } + + became, ret, err := rootless.BecomeRootInUserNS() + if err != nil { + return err + } + if became { + os.Exit(ret) + } + } + formats := map[string]bool{ "": true, of.JSONString: true, diff --git a/cmd/podman/run.go b/cmd/podman/run.go index a4b5c918e..20cb85347 100644 --- a/cmd/podman/run.go +++ b/cmd/podman/run.go @@ -116,6 +116,11 @@ func runCmd(c *cli.Context) error { if strings.Index(err.Error(), "permission denied") > -1 { exitCode = 126 } + if c.IsSet("rm") { + if deleteError := runtime.RemoveContainer(ctx, ctr, true); deleteError != nil { + logrus.Errorf("unable to remove container %s after failing to start and attach to it", ctr.ID()) + } + } return err } diff --git a/cmd/podman/shared/funcs.go b/cmd/podman/shared/funcs.go index 8520c0616..8770b8ec0 100644 --- a/cmd/podman/shared/funcs.go +++ b/cmd/podman/shared/funcs.go @@ -10,10 +10,23 @@ import ( ) func substituteCommand(cmd string) (string, error) { + var ( + newCommand string + ) + + // Replace cmd with "/proc/self/exe" if "podman" or "docker" is being + // used. If "/usr/bin/docker" is provided, we also sub in podman. + // Otherwise, leave the command unchanged. + if cmd == "podman" || filepath.Base(cmd) == "docker" { + newCommand = "/proc/self/exe" + } else { + newCommand = cmd + } + // If cmd is an absolute or relative path, check if the file exists. // Throw an error if it doesn't exist. - if strings.Contains(cmd, "/") || strings.HasPrefix(cmd, ".") { - res, err := filepath.Abs(cmd) + if strings.Contains(newCommand, "/") || strings.HasPrefix(newCommand, ".") { + res, err := filepath.Abs(newCommand) if err != nil { return "", err } @@ -24,16 +37,7 @@ func substituteCommand(cmd string) (string, error) { } } - // Replace cmd with "/proc/self/exe" if "podman" or "docker" is being - // used. Otherwise, leave the command unchanged. - switch cmd { - case "podman": - fallthrough - case "docker": - return "/proc/self/exe", nil - default: - return cmd, nil - } + return newCommand, nil } // GenerateCommand takes a label (string) and converts it to an executable command diff --git a/cmd/podman/start.go b/cmd/podman/start.go index 8cf85405e..8bb386c68 100644 --- a/cmd/podman/start.go +++ b/cmd/podman/start.go @@ -1,11 +1,13 @@ package main import ( + "encoding/json" "fmt" "os" "github.com/containers/libpod/cmd/podman/libpodruntime" "github.com/containers/libpod/libpod" + cc "github.com/containers/libpod/pkg/spec" "github.com/pkg/errors" "github.com/sirupsen/logrus" "github.com/urfave/cli" @@ -132,6 +134,18 @@ func startCmd(c *cli.Context) error { } // Handle non-attach start if err := ctr.Start(ctx); err != nil { + var createArtifact cc.CreateConfig + artifact, artifactErr := ctr.GetArtifact("create-config") + if artifactErr == nil { + if jsonErr := json.Unmarshal(artifact, &createArtifact); jsonErr != nil { + logrus.Errorf("unable to detect if container %s should be deleted", ctr.ID()) + } + if createArtifact.Rm { + if rmErr := runtime.RemoveContainer(ctx, ctr, true); rmErr != nil { + logrus.Errorf("unable to remove container %s after it failed to start", ctr.ID()) + } + } + } if lastError != nil { fmt.Fprintln(os.Stderr, lastError) } diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md index 436dc5257..e175479f1 100644 --- a/contrib/cirrus/README.md +++ b/contrib/cirrus/README.md @@ -66,6 +66,18 @@ task (pass or fail) is set based on the exit status of the last script to execut ### ``cache_images`` Task +Modifying the contents of cache-images is done by making changes to +one or more of the ``./contrib/cirrus/packer/*_setup.sh`` files. Testing +those changes currently requires adding a temporary commit to a PR that +updates ``.cirrus.yml``: + +* Remove all task sections except ``cache_images_task``. +* Remove the ``only_if`` condition and ``depends_on`` dependencies + +The new image names will be displayed at the end of output, assuming the build +is successful, at that point the temporary commit may be removed. Finally, +the new names may be used as ``image_name`` values in ``.cirrus.yml``. + ***N/B: Steps below are performed by automation*** 1. When a PR is merged (``$CIRRUS_BRANCH`` == ``master``), run another @@ -90,12 +102,6 @@ task (pass or fail) is set based on the exit status of the last script to execut 3. If successful, shut down each VM and create a new GCE Image named with the base image, and the commit sha of the merge. -***Note:*** The ``.cirrus.yml`` file must be manually updated with the new -images names, then the change sent in via a secondary pull-request. This -ensures that all the ``integration_testing`` tasks can pass with the new images, -before subjecting all future PRs to them. A workflow to automate this -process is described in comments at the end of the ``.cirrus.yml`` file. - ### Base-images Base-images are VM disk-images specially prepared for executing as GCE VMs. @@ -120,27 +126,27 @@ as the standard 'cloud-init' services. To produce new base-images, including an `image-builder-image` (used by the ``cache_images`` Task) some input parameters are required: - * ``GCP_PROJECT_ID``: The complete GCP project ID string e.g. foobar-12345 - identifying where the images will be stored. +* ``GCP_PROJECT_ID``: The complete GCP project ID string e.g. foobar-12345 + identifying where the images will be stored. - * ``GOOGLE_APPLICATION_CREDENTIALS``: A *JSON* file containing - credentials for a GCE service account. This can be [a service - account](https://cloud.google.com/docs/authentication/production#obtaining_and_providing_service_account_credentials_manually) - or [end-user - credentials](https://cloud.google.com/docs/authentication/end-user#creating_your_client_credentials] +* ``GOOGLE_APPLICATION_CREDENTIALS``: A *JSON* file containing + credentials for a GCE service account. This can be [a service + account](https://cloud.google.com/docs/authentication/production#obtaining_and_providing_service_account_credentials_manually) + or [end-user + credentials](https://cloud.google.com/docs/authentication/end-user#creating_your_client_credentials) - * ``RHEL_IMAGE_FILE`` and ``RHEL_CSUM_FILE`` complete paths - to a `rhel-server-ec2-*.raw.xz` and it's cooresponding - checksum file. These must be supplied manually because - they're not available directly via URL like other images. +* ``RHEL_IMAGE_FILE`` and ``RHEL_CSUM_FILE`` complete paths + to a `rhel-server-ec2-*.raw.xz` and it's cooresponding + checksum file. These must be supplied manually because + they're not available directly via URL like other images. - * ``RHSM_COMMAND`` contains the complete string needed to register - the VM for installing package dependencies. The VM will be de-registered - upon completion. +* ``RHSM_COMMAND`` contains the complete string needed to register + the VM for installing package dependencies. The VM will be de-registered + upon completion. - * Optionally, CSV's may be specified to ``PACKER_BUILDS`` - to limit the base-images produced. For example, - ``PACKER_BUILDS=fedora,image-builder-image``. +* Optionally, CSV's may be specified to ``PACKER_BUILDS`` + to limit the base-images produced. For example, + ``PACKER_BUILDS=fedora,image-builder-image``. If there is an existing 'image-builder-image' within GCE, it may be utilized to produce base-images (in addition to cache-images). However it must be diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index 985264f22..51db203fd 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -6,6 +6,19 @@ # Under some contexts these values are not set, make sure they are. export USER="$(whoami)" export HOME="$(getent passwd $USER | cut -d : -f 6)" + +# These are normally set by cirrus, if not use some reasonable defaults +ENVLIB=${ENVLIB:-.bash_profile} +CIRRUS_WORKING_DIR=${CIRRUS_WORKING_DIR:-/var/tmp/go/src/github.com/containers/libpod} +SCRIPT_BASE=${SCRIPT_BASE:-./contrib/cirrus} +PACKER_BASE=${PACKER_BASE:-./contrib/cirrus/packer} +CIRRUS_BUILD_ID=${CIRRUS_BUILD_ID:-DEADBEEF} # a human +cd "$CIRRUS_WORKING_DIR" +CIRRUS_BASE_SHA=${CIRRUS_BASE_SHA:-$(git rev-parse upstream/master || git rev-parse origin/master)} +CIRRUS_CHANGE_IN_REPO=${CIRRUS_CHANGE_IN_REPO:-$(git rev-parse HEAD)} +CIRRUS_REPO_NAME=${CIRRUS_REPO_NAME:-libpod} +cd - + if ! [[ "$PATH" =~ "/usr/local/bin" ]] then export PATH="$PATH:/usr/local/bin" diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh index 4e4391e59..a14e1b01f 100644 --- a/contrib/cirrus/packer/fedora_setup.sh +++ b/contrib/cirrus/packer/fedora_setup.sh @@ -28,7 +28,6 @@ ooe.sh sudo dnf install -y \ atomic-registries \ btrfs-progs-devel \ bzip2 \ - conmon \ device-mapper-devel \ findutils \ git \ diff --git a/contrib/cirrus/packer/libpod_base_images.yml b/contrib/cirrus/packer/libpod_base_images.yml index 4ae44e0d9..109b9b8d5 100644 --- a/contrib/cirrus/packer/libpod_base_images.yml +++ b/contrib/cirrus/packer/libpod_base_images.yml @@ -18,10 +18,14 @@ variables: # RHEL requires a subscription to install/update packages RHSM_COMMAND: - # Fedora images are obtainable by direct download + # Latest Fedora release FEDORA_IMAGE_URL: "https://dl.fedoraproject.org/pub/fedora/linux/releases/29/Cloud/x86_64/images/Fedora-Cloud-Base-29-1.2.x86_64.qcow2" FEDORA_CSUM_URL: "https://dl.fedoraproject.org/pub/fedora/linux/releases/29/Cloud/x86_64/images/Fedora-Cloud-29-1.2-x86_64-CHECKSUM" FEDORA_BASE_IMAGE_NAME: 'fedora-cloud-base-29-1-2' # Name to use in GCE + # Prior Fedora release + PRIOR_FEDORA_IMAGE_URL: "https://dl.fedoraproject.org/pub/fedora/linux/releases/28/Cloud/x86_64/images/Fedora-Cloud-Base-28-1.1.x86_64.qcow2" + PRIOR_FEDORA_CSUM_URL: "https://dl.fedoraproject.org/pub/fedora/linux/releases/28/Cloud/x86_64/images/Fedora-Cloud-28-1.1-x86_64-CHECKSUM" + PRIOR_FEDORA_BASE_IMAGE_NAME: 'fedora-cloud-base-28-1-1' # Name to use in GCE FAH_IMAGE_URL: "https://dl.fedoraproject.org/pub/alt/atomic/stable/Fedora-Atomic-29-20181025.1/AtomicHost/x86_64/images/Fedora-AtomicHost-29-20181025.1.x86_64.qcow2" FAH_CSUM_URL: "https://dl.fedoraproject.org/pub/alt/atomic/stable/Fedora-Atomic-29-20181025.1/AtomicHost/x86_64/images/Fedora-AtomicHost-29-20181025.1-x86_64-CHECKSUM" FAH_BASE_IMAGE_NAME: 'fedora-atomichost-29-20181025-1' # Name to use in GCE @@ -101,6 +105,11 @@ builders: ssh_username: 'root' - <<: *nested_virt + name: 'prior_fedora' + iso_url: '{{user `PRIOR_FEDORA_IMAGE_URL`}}' + iso_checksum_url: '{{user `PRIOR_FEDORA_CSUM_URL`}}' + + - <<: *nested_virt name: 'fah' iso_url: '{{user `FAH_IMAGE_URL`}}' iso_checksum_url: '{{user `FAH_CSUM_URL`}}' @@ -152,7 +161,7 @@ provisioners: post-processors: - - type: "compress" - only: ['fedora', 'fah', 'rhel'] + only: ['fedora', 'prior_fedora', 'fah', 'rhel'] output: '/tmp/{{build_name}}/disk.raw.tar.gz' format: '.tar.gz' compression_level: 9 @@ -167,6 +176,11 @@ post-processors: image_description: 'Based on {{user `FEDORA_IMAGE_URL`}}' image_family: '{{user `FEDORA_BASE_IMAGE_NAME`}}' - <<: *gcp_import + only: ['prior_fedora'] + image_name: "{{user `PRIOR_FEDORA_BASE_IMAGE_NAME`}}-{{user `TIMESTAMP`}}" + image_description: 'Based on {{user `PRIOR_FEDORA_IMAGE_URL`}}' + image_family: '{{user `PRIOR_FEDORA_BASE_IMAGE_NAME`}}' + - <<: *gcp_import only: ['fah'] image_name: "{{user `FAH_BASE_IMAGE_NAME`}}-{{user `TIMESTAMP`}}" image_description: 'Based on {{user `FAH_IMAGE_URL`}}' diff --git a/contrib/cirrus/packer/libpod_images.yml b/contrib/cirrus/packer/libpod_images.yml index 7b95b08cc..d31c11a8d 100644 --- a/contrib/cirrus/packer/libpod_images.yml +++ b/contrib/cirrus/packer/libpod_images.yml @@ -7,6 +7,7 @@ variables: CENTOS_BASE_IMAGE: '{{env `CENTOS_BASE_IMAGE`}}' UBUNTU_BASE_IMAGE: '{{env `UBUNTU_BASE_IMAGE`}}' FEDORA_BASE_IMAGE: '{{env `FEDORA_BASE_IMAGE`}}' + PRIOR_FEDORA_BASE_IMAGE: '{{env `PRIOR_FEDORA_BASE_IMAGE`}}' FAH_BASE_IMAGE: '{{env `FAH_BASE_IMAGE`}}' # libpod dependencies to build and install into images @@ -67,6 +68,10 @@ builders: source_image: '{{user `FEDORA_BASE_IMAGE`}}' - <<: *gce_hosted_image + name: 'fedora-28' + source_image: '{{user `PRIOR_FEDORA_BASE_IMAGE`}}' + + - <<: *gce_hosted_image name: 'fah-29' source_image: '{{user `FAH_BASE_IMAGE`}}' diff --git a/contrib/cirrus/packer/prior_fedora_base-setup.sh b/contrib/cirrus/packer/prior_fedora_base-setup.sh new file mode 120000 index 000000000..998a5d9fd --- /dev/null +++ b/contrib/cirrus/packer/prior_fedora_base-setup.sh @@ -0,0 +1 @@ +fedora_base-setup.sh
\ No newline at end of file diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index 5ba842cf1..174bd3daf 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -4,7 +4,6 @@ set -e source $(dirname $0)/lib.sh req_env_var " -CI $CI USER $USER HOME $HOME ENVLIB $ENVLIB @@ -58,7 +57,11 @@ then envstr='export BUILDTAGS="seccomp $($GOSRC/hack/btrfs_tag.sh) $($GOSRC/hack/btrfs_installed_tag.sh) $($GOSRC/hack/ostree_tag.sh) varlink exclude_graphdriver_devicemapper"' ;; fedora-29) ;& # Continue to the next item - fedora-28) ;& + fedora-28) + RUNC="https://kojipkgs.fedoraproject.org/packages/runc/1.0.0/55.dev.git578fe65.fc${OS_RELEASE_VER}/x86_64/runc-1.0.0-55.dev.git578fe65.fc${OS_RELEASE_VER}.x86_64.rpm" + echo ">>>>> OVERRIDING RUNC WITH $RUNC <<<<<" + dnf -y install "$RUNC" + ;& # Continue to the next item centos-7) ;& rhel-7) envstr='unset BUILDTAGS' # Use default from Makefile diff --git a/contrib/cirrus/unit_test.sh b/contrib/cirrus/unit_test.sh index e5b167e79..61d9dc73d 100755 --- a/contrib/cirrus/unit_test.sh +++ b/contrib/cirrus/unit_test.sh @@ -20,6 +20,7 @@ case "${OS_RELEASE_ID}-${OS_RELEASE_VER}" in make "BUILDTAGS=$BUILDTAGS" ;; fedora-29) ;& # Continue to the next item + fedora-28) ;& centos-7) ;& rhel-7) make install.tools diff --git a/hack/get_ci_vm.sh b/hack/get_ci_vm.sh new file mode 100755 index 000000000..e9a755dd4 --- /dev/null +++ b/hack/get_ci_vm.sh @@ -0,0 +1,85 @@ +#!/bin/bash + +set -e + +cd $(dirname $0)/../ + +VMNAME="${USER}-twidling-$1" +# TODO: Many/most of these values should come from .cirrus.yml +ZONE="us-central1-a" +CPUS="2" +MEMORY="4Gb" +DISK="200" +PROJECT="libpod-218412" +GOSRC="/var/tmp/go/src/github.com/containers/libpod" + +PGCLOUD="sudo podman run -it --rm -e AS_ID=$UID -e AS_USER=$USER -v /home/$USER:$HOME:z quay.io/cevich/gcloud_centos:latest" +CREATE_CMD="$PGCLOUD compute instances create --zone=$ZONE --image=$1 --custom-cpu=$CPUS --custom-memory=$MEMORY --boot-disk-size=$DISK --labels=in-use-by=$USER $VMNAME" +SSH_CMD="ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o CheckHostIP=no -F /dev/null" +CLEANUP_CMD="$PGCLOUD compute instances delete --zone $ZONE --delete-disks=all $VMNAME" + +# COLOR! +RED="\e[1;36;41m" +YEL="\e[1;33;44m" +NOR="\e[0m" + +if [[ -z "$1" ]] +then + echo -e "\n${RED}Error: No image-name specified. Some possible values (from .cirrus.yml).${NOR}" + egrep 'image_name' ".cirrus.yml" | grep -v '#' | cut -d: -f 2 | tr -d [:blank:] + exit 1 +fi + +echo -e "\n${YEL}WARNING: This will not work without local sudo access to run podman,${NOR}" +echo -e " ${YEL}and prior authorization to use the libpod GCP project. Also,${NOR}" +echo -e " ${YEL}possession of the proper ssh private key is required.${NOR}" + +if [[ "$USER" =~ "root" ]] +then + echo -e "\n${RED}ERROR: This script must be run as a regular user${NOR}" + exit 2 +fi + +if [[ ! -r "$HOME/.config/gcloud/active_config" ]] +then + echo -e "\n${RED}ERROR: Can't find gcloud configuration, attempting to run init.${NOR}" + $PGCLOUD init --project=$PROJECT +fi + +cleanup() { + echo -e "\n${YEL}Deleting $VMNAME ${RED}(Might take a minute or two)${NOR} ++ $CLEANUP_CMD +" + $CLEANUP_CMD # prompts for Yes/No +} + +trap cleanup EXIT + +echo -e "\n${YEL}Trying to creating a VM named $VMNAME (not fatal if already exists).${NOR}" +echo "+ $CREATE_CMD" +$CREATE_CMD || true # allow re-running commands below when "delete: N" + +echo -e "\n${YEL}Attempting to retrieve IP address of existing ${VMNAME}${NOR}." +IP=`$PGCLOUD compute instances list --filter=name=$VMNAME --limit=1 '--format=csv(networkInterfaces.accessConfigs.natIP)' | tr --complement --delete .[:digit:]` + +echo -e "\n${YEL}Creating $GOSRC directory.${NOR}" +SSH_MKDIR="$SSH_CMD root@$IP mkdir -vp $GOSRC" +echo "+ $SSH_MKDIR" +$SSH_MKDIR + +echo -e "\n${YEL}Synchronizing local repository to $IP:${GOSRC}${NOR} ." +export RSYNC_RSH="$SSH_CMD" +RSYNC_CMD="rsync --quiet --recursive --update --links --safe-links --perms --sparse $PWD/ root@$IP:$GOSRC/" +echo "+ export RSYNC_RSH=\"$SSH_CMD\"" +echo "+ $RSYNC_CMD" +$RSYNC_CMD + +echo -e "\n${YEL}Executing environment setup${NOR}" +ENV_CMD="$SSH_CMD root@$IP env CI=true $GOSRC/contrib/cirrus/setup_environment.sh" +echo "+ $ENV_CMD" +$SSH_CMD root@$IP $GOSRC/contrib/cirrus/setup_environment.sh + +echo -e "\n${YEL}Connecting to $VMNAME ${RED}(option to delete VM upon logout).${NOR}" +SSH_CMD="$SSH_CMD -t root@$IP" +echo "+ $SSH_CMD" +$SSH_CMD "cd $GOSRC ; bash -il" diff --git a/libpod/boltdb_state_internal.go b/libpod/boltdb_state_internal.go index 0970f4d41..06f8dcb24 100644 --- a/libpod/boltdb_state_internal.go +++ b/libpod/boltdb_state_internal.go @@ -565,10 +565,12 @@ func (s *BoltState) addContainer(ctr *Container, pod *Pod) error { } // Add container to volume dependencies bucket if container is using a named volume + if ctr.runtime.config.VolumePath == "" { + return nil + } for _, vol := range ctr.config.Spec.Mounts { if strings.Contains(vol.Source, ctr.runtime.config.VolumePath) { volName := strings.Split(vol.Source[len(ctr.runtime.config.VolumePath)+1:], "/")[0] - volDB := volBkt.Bucket([]byte(volName)) if volDB == nil { return errors.Wrapf(ErrNoSuchVolume, "no volume with name %s found in database", volName) diff --git a/libpod/container.go b/libpod/container.go index b5346e581..18d867f41 100644 --- a/libpod/container.go +++ b/libpod/container.go @@ -1003,7 +1003,7 @@ func (c *Container) IsReadOnly() bool { // NetworkDisabled returns whether the container is running with a disabled network func (c *Container) NetworkDisabled() (bool, error) { if c.config.NetNsCtr != "" { - container, err := c.runtime.LookupContainer(c.config.NetNsCtr) + container, err := c.runtime.state.Container(c.config.NetNsCtr) if err != nil { return false, err } diff --git a/libpod/container_internal.go b/libpod/container_internal.go index f69acb33b..af17d8495 100644 --- a/libpod/container_internal.go +++ b/libpod/container_internal.go @@ -18,12 +18,12 @@ import ( "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" "github.com/containers/libpod/pkg/rootless" "github.com/containers/storage" "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" @@ -1027,7 +1027,7 @@ func (c *Container) writeStringToRundir(destFile, output string) (string, error) return filepath.Join(c.state.DestinationRunDir, destFile), nil } -func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator) error { +func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator, execUser *user.ExecUser) error { var uid, gid int mountPoint := c.state.Mountpoint if !c.state.Mounted { @@ -1053,12 +1053,8 @@ func (c *Container) addLocalVolumes(ctx context.Context, g *generate.Generator) } if c.config.User != "" { - if !c.state.Mounted { - return errors.Wrapf(ErrCtrStateInvalid, "container %s must be mounted in order to translate User field", c.ID()) - } - execUser, err := lookup.GetUserGroupInfo(c.state.Mountpoint, c.config.User, nil) - if err != nil { - return err + if execUser == nil { + return errors.Wrapf(ErrInternal, "nil pointer passed to addLocalVolumes for execUser") } uid = execUser.Uid gid = execUser.Gid diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index f9b0592f9..93d20491e 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -26,6 +26,7 @@ import ( "github.com/containers/libpod/pkg/rootless" "github.com/containers/libpod/pkg/secrets" "github.com/containers/storage/pkg/idtools" + "github.com/mrunalp/fileutils" "github.com/opencontainers/runc/libcontainer/user" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" @@ -236,7 +237,7 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) { // Bind builtin image volumes if c.config.Rootfs == "" && c.config.ImageVolumes { - if err := c.addLocalVolumes(ctx, &g); err != nil { + if err := c.addLocalVolumes(ctx, &g, execUser); err != nil { return nil, errors.Wrapf(err, "error mounting image volumes") } } @@ -645,28 +646,68 @@ func (c *Container) makeBindMounts() error { } if !netDisabled { - // Make /etc/resolv.conf - if _, ok := c.state.BindMounts["/etc/resolv.conf"]; ok { - // If it already exists, delete so we can recreate + // If /etc/resolv.conf and /etc/hosts exist, delete them so we + // will recreate + if path, ok := c.state.BindMounts["/etc/resolv.conf"]; ok { + if err := os.Remove(path); err != nil && !os.IsNotExist(err) { + return errors.Wrapf(err, "error removing container %s resolv.conf", c.ID()) + } delete(c.state.BindMounts, "/etc/resolv.conf") } - newResolv, err := c.generateResolvConf() - if err != nil { - return errors.Wrapf(err, "error creating resolv.conf for container %s", c.ID()) - } - c.state.BindMounts["/etc/resolv.conf"] = newResolv - - // Make /etc/hosts - if _, ok := c.state.BindMounts["/etc/hosts"]; ok { - // If it already exists, delete so we can recreate + if path, ok := c.state.BindMounts["/etc/hosts"]; ok { + if err := os.Remove(path); err != nil && !os.IsNotExist(err) { + return errors.Wrapf(err, "error removing container %s hosts", c.ID()) + } delete(c.state.BindMounts, "/etc/hosts") } - newHosts, err := c.generateHosts() - if err != nil { - return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) - } - c.state.BindMounts["/etc/hosts"] = newHosts + if c.config.NetNsCtr != "" { + // We share a net namespace + // We want /etc/resolv.conf and /etc/hosts from the + // other container + depCtr, err := c.runtime.state.Container(c.config.NetNsCtr) + if err != nil { + return errors.Wrapf(err, "error fetching dependency %s of container %s", c.config.NetNsCtr, c.ID()) + } + + // We need that container's bind mounts + bindMounts, err := depCtr.BindMounts() + if err != nil { + return errors.Wrapf(err, "error fetching bind mounts from dependency %s of container %s", depCtr.ID(), c.ID()) + } + + // The other container may not have a resolv.conf or /etc/hosts + // If it doesn't, don't copy them + resolvPath, exists := bindMounts["/etc/resolv.conf"] + if exists { + resolvDest := filepath.Join(c.state.RunDir, "resolv.conf") + if err := fileutils.CopyFile(resolvPath, resolvDest); err != nil { + return errors.Wrapf(err, "error copying resolv.conf from dependency container %s of container %s", depCtr.ID(), c.ID()) + } + c.state.BindMounts["/etc/resolv.conf"] = resolvDest + } + + hostsPath, exists := bindMounts["/etc/hosts"] + if exists { + hostsDest := filepath.Join(c.state.RunDir, "hosts") + if err := fileutils.CopyFile(hostsPath, hostsDest); err != nil { + return errors.Wrapf(err, "error copying hosts file from dependency container %s of container %s", depCtr.ID(), c.ID()) + } + c.state.BindMounts["/etc/hosts"] = hostsDest + } + } else { + newResolv, err := c.generateResolvConf() + if err != nil { + return errors.Wrapf(err, "error creating resolv.conf for container %s", c.ID()) + } + c.state.BindMounts["/etc/resolv.conf"] = newResolv + + newHosts, err := c.generateHosts() + if err != nil { + return errors.Wrapf(err, "error creating hosts file for container %s", c.ID()) + } + c.state.BindMounts["/etc/hosts"] = newHosts + } } // SHM is always added when we mount the container diff --git a/libpod/oci.go b/libpod/oci.go index 3222f9403..093bfdd35 100644 --- a/libpod/oci.go +++ b/libpod/oci.go @@ -861,6 +861,7 @@ func (r *OCIRuntime) execStopContainer(ctr *Container, timeout uint) error { // checkpointContainer checkpoints the given container func (r *OCIRuntime) checkpointContainer(ctr *Container, options ContainerCheckpointOptions) error { + label.SetSocketLabel(ctr.ProcessLabel()) // imagePath is used by CRIU to store the actual checkpoint files imagePath := ctr.CheckpointPath() // workPath will be used to store dump.log and stats-dump diff --git a/test/e2e/checkpoint_test.go b/test/e2e/checkpoint_test.go index fe614e911..57322643e 100644 --- a/test/e2e/checkpoint_test.go +++ b/test/e2e/checkpoint_test.go @@ -4,6 +4,7 @@ import ( "fmt" "net" "os" + "strconv" "github.com/containers/libpod/pkg/criu" . "github.com/containers/libpod/test/utils" @@ -29,8 +30,9 @@ var _ = Describe("Podman checkpoint", func() { Skip("CRIU is missing or too old.") } hostInfo := podmanTest.Host - if hostInfo.Distribution == "fedora" && hostInfo.Version == "29" { - Skip("Checkpoint tests appear to fail on F29.") + hostDistVer, _ := strconv.Atoi(hostInfo.Version) + if hostInfo.Distribution == "fedora" && hostDistVer <= 29 { + Skip("Checkpoint tests appear to fail on older (<30) Fedora versions .") } }) diff --git a/test/e2e/libpod_suite_test.go b/test/e2e/libpod_suite_test.go index 268db5aa1..d312124ab 100644 --- a/test/e2e/libpod_suite_test.go +++ b/test/e2e/libpod_suite_test.go @@ -109,7 +109,7 @@ func PodmanTestCreate(tempDir string) *PodmanTestIntegration { } conmonBinary := filepath.Join("/usr/libexec/podman/conmon") altConmonBinary := "/usr/libexec/crio/conmon" - if _, err := os.Stat(altConmonBinary); err == nil { + if _, err := os.Stat(conmonBinary); os.IsNotExist(err) { conmonBinary = altConmonBinary } if os.Getenv("CONMON_BINARY") != "" { diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 1b05ac031..68b1f06de 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -9,7 +9,7 @@ import ( . "github.com/onsi/gomega" ) -var _ = Describe("Podman rmi", func() { +var _ = Describe("Podman run networking", func() { var ( tempdir string err error @@ -145,4 +145,35 @@ var _ = Describe("Podman rmi", func() { match, _ := session.GrepString("foobar") Expect(match).Should(BeTrue()) }) + + It("podman run --net container: copies hosts and resolv", func() { + ctrName := "ctr1" + ctr1 := podmanTest.RunTopContainer(ctrName) + ctr1.WaitWithDefaultTimeout() + Expect(ctr1.ExitCode()).To(Equal(0)) + + // Exec in and modify /etc/resolv.conf and /etc/hosts + exec1 := podmanTest.Podman([]string{"exec", ctrName, "sh", "-c", "echo nameserver 192.0.2.1 > /etc/resolv.conf"}) + exec1.WaitWithDefaultTimeout() + Expect(exec1.ExitCode()).To(Equal(0)) + + exec2 := podmanTest.Podman([]string{"exec", ctrName, "sh", "-c", "echo 192.0.2.2 test1 > /etc/hosts"}) + exec2.WaitWithDefaultTimeout() + Expect(exec2.ExitCode()).To(Equal(0)) + + ctrName2 := "ctr2" + ctr2 := podmanTest.Podman([]string{"run", "-d", "--net=container:" + ctrName, "--name", ctrName2, ALPINE, "top"}) + ctr2.WaitWithDefaultTimeout() + Expect(ctr2.ExitCode()).To(Equal(0)) + + exec3 := podmanTest.Podman([]string{"exec", "-i", ctrName2, "cat", "/etc/resolv.conf"}) + exec3.WaitWithDefaultTimeout() + Expect(exec3.ExitCode()).To(Equal(0)) + Expect(exec3.OutputToString()).To(ContainSubstring("nameserver 192.0.2.1")) + + exec4 := podmanTest.Podman([]string{"exec", "-i", ctrName2, "cat", "/etc/hosts"}) + exec4.WaitWithDefaultTimeout() + Expect(exec4.ExitCode()).To(Equal(0)) + Expect(exec4.OutputToString()).To(ContainSubstring("192.0.2.2 test1")) + }) }) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 4a9bd4e46..2104991b2 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -639,4 +639,31 @@ USER mail` match, _ := check.GrepString("foobar") Expect(match).To(BeTrue()) }) + + It("podman run --rm should work", func() { + session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "ls"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + numContainers := podmanTest.NumberOfContainers() + Expect(numContainers).To(Equal(0)) + }) + + It("podman run --rm failed container should delete itself", func() { + session := podmanTest.Podman([]string{"run", "--rm", ALPINE, "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + + numContainers := podmanTest.NumberOfContainers() + Expect(numContainers).To(Equal(0)) + }) + + It("podman run failed container should NOT delete itself", func() { + session := podmanTest.Podman([]string{"run", ALPINE, "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + + numContainers := podmanTest.NumberOfContainers() + Expect(numContainers).To(Equal(1)) + }) }) diff --git a/test/e2e/start_test.go b/test/e2e/start_test.go index c11511d1f..64245c609 100644 --- a/test/e2e/start_test.go +++ b/test/e2e/start_test.go @@ -89,4 +89,30 @@ var _ = Describe("Podman start", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(125)) }) + + It("podman failed to start with --rm should delete the container", func() { + session := podmanTest.Podman([]string{"create", "-it", "--rm", ALPINE, "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + start := podmanTest.Podman([]string{"start", "-l"}) + start.WaitWithDefaultTimeout() + Expect(start.ExitCode()).To(Not(Equal(0))) + + numContainers := podmanTest.NumberOfContainers() + Expect(numContainers).To(BeZero()) + }) + + It("podman failed to start without --rm should NOT delete the container", func() { + session := podmanTest.Podman([]string{"create", "-it", ALPINE, "foo"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + start := podmanTest.Podman([]string{"start", "-l"}) + start.WaitWithDefaultTimeout() + Expect(start.ExitCode()).To(Not(Equal(0))) + + numContainers := podmanTest.NumberOfContainers() + Expect(numContainers).To(Equal(1)) + }) }) diff --git a/test/e2e/systemd_test.go b/test/e2e/systemd_test.go new file mode 100644 index 000000000..ce67bb469 --- /dev/null +++ b/test/e2e/systemd_test.go @@ -0,0 +1,81 @@ +package integration + +import ( + "fmt" + "io/ioutil" + "os" + + . "github.com/containers/libpod/test/utils" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +var _ = Describe("Podman systemd", func() { + var ( + tempdir string + err error + podmanTest *PodmanTestIntegration + systemd_unit_file string + ) + + BeforeEach(func() { + tempdir, err = CreateTempDirInTempDir() + if err != nil { + os.Exit(1) + } + podmanTest = PodmanTestCreate(tempdir) + podmanTest.RestoreAllArtifacts() + systemd_unit_file = `[Unit] +Description=redis container +[Service] +Restart=always +ExecStart=/usr/bin/podman start -a redis +ExecStop=/usr/bin/podman stop -t 10 redis +KillMode=process +[Install] +WantedBy=multi-user.target +` + }) + + AfterEach(func() { + podmanTest.Cleanup() + f := CurrentGinkgoTestDescription() + timedResult := fmt.Sprintf("Test: %s completed in %f seconds", f.TestText, f.Duration.Seconds()) + GinkgoWriter.Write([]byte(timedResult)) + }) + + It("podman start container by systemd", func() { + if os.Getenv("SKIP_USERNS") != "" { + Skip("Skip userns tests.") + } + + sys_file := ioutil.WriteFile("/etc/systemd/system/redis.service", []byte(systemd_unit_file), 0644) + Expect(sys_file).To(BeNil()) + + create := podmanTest.Podman([]string{"create", "-d", "--name", "redis", "redis"}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(Equal(0)) + + enable := SystemExec("bash", []string{"-c", "systemctl daemon-reload && systemctl enable --now redis"}) + enable.WaitWithDefaultTimeout() + Expect(enable.ExitCode()).To(Equal(0)) + + start := SystemExec("bash", []string{"-c", "systemctl start redis"}) + start.WaitWithDefaultTimeout() + + logs := SystemExec("bash", []string{"-c", "journalctl -n 20 -u redis"}) + logs.WaitWithDefaultTimeout() + + status := SystemExec("bash", []string{"-c", "systemctl status redis"}) + status.WaitWithDefaultTimeout() + Expect(status.OutputToString()).To(ContainSubstring("active (running)")) + + cleanup := SystemExec("bash", []string{"-c", "systemctl stop redis && systemctl disable redis"}) + cleanup.WaitWithDefaultTimeout() + Expect(cleanup.ExitCode()).To(Equal(0)) + os.Remove("/etc/systemd/system/redis.service") + sys_clean := SystemExec("bash", []string{"-c", "systemctl daemon-reload"}) + sys_clean.WaitWithDefaultTimeout() + Expect(sys_clean.ExitCode()).To(Equal(0)) + }) +}) diff --git a/vendor.conf b/vendor.conf index 75483e9f3..f2d7fa414 100644 --- a/vendor.conf +++ b/vendor.conf @@ -51,7 +51,7 @@ github.com/opencontainers/image-spec v1.0.0 github.com/opencontainers/runc b4e2ecb452d9ee4381137cc0a7e6715b96bed6de github.com/opencontainers/runtime-spec d810dbc60d8c5aeeb3d054bd1132fab2121968ce github.com/opencontainers/runtime-tools master -github.com/opencontainers/selinux 6ba084dd09db3dfe49a839bab0bbe97fd9274d80 +github.com/opencontainers/selinux 51c6c0a5dbc675792e953298cb9871819d6f9bb8 github.com/ostreedev/ostree-go master github.com/pkg/errors v0.8.0 github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2 diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go index 2a31cd3c5..bb27ac936 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label.go @@ -9,7 +9,7 @@ func InitLabels(options []string) (string, string, error) { return "", "", nil } -func GetROMountLabel() string { +func ROMountLabel() string { return "" } @@ -25,7 +25,19 @@ func SetProcessLabel(processLabel string) error { return nil } -func GetFileLabel(path string) (string, error) { +func ProcessLabel() (string, error) { + return "", nil +} + +func SetSocketLabel(processLabel string) error { + return nil +} + +func SocketLabel() (string, error) { + return "", nil +} + +func FileLabel(path string) (string, error) { return "", nil } @@ -41,7 +53,7 @@ func Relabel(path string, fileLabel string, shared bool) error { return nil } -func GetPidLabel(pid int) (string, error) { +func PidLabel(pid int) (string, error) { return "", nil } diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go index 63c4edd05..de214b2d5 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go @@ -95,6 +95,17 @@ func SetProcessLabel(processLabel string) error { return selinux.SetExecLabel(processLabel) } +// SetSocketLabel takes a process label and tells the kernel to assign the +// label to the next socket that gets created +func SetSocketLabel(processLabel string) error { + return selinux.SetSocketLabel(processLabel) +} + +// SocketLabel retrieves the current default socket label setting +func SocketLabel() (string, error) { + return selinux.SocketLabel() +} + // ProcessLabel returns the process label that the kernel will assign // to the next program executed by the current process. If "" is returned // this indicates that the default labeling will happen for the process. @@ -102,7 +113,7 @@ func ProcessLabel() (string, error) { return selinux.ExecLabel() } -// GetFileLabel returns the label for specified path +// FileLabel returns the label for specified path func FileLabel(path string) (string, error) { return selinux.FileLabel(path) } diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go index bbaa1e0d7..7832f7497 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go @@ -385,6 +385,17 @@ func SetExecLabel(label string) error { return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/exec", syscall.Gettid()), label) } +// SetSocketLabel takes a process label and tells the kernel to assign the +// label to the next socket that gets created +func SetSocketLabel(label string) error { + return writeCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid()), label) +} + +// SocketLabel retrieves the current socket label setting +func SocketLabel() (string, error) { + return readCon(fmt.Sprintf("/proc/self/task/%d/attr/sockcreate", syscall.Gettid())) +} + // Get returns the Context as a string func (c Context) Get() string { if c["level"] != "" { diff --git a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go index 5abf8a362..99efa155a 100644 --- a/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go +++ b/vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go @@ -96,6 +96,19 @@ func SetExecLabel(label string) error { return nil } +/* +SetSocketLabel sets the SELinux label that the kernel will use for any programs +that are executed by the current process thread, or an error. +*/ +func SetSocketLabel(label string) error { + return nil +} + +// SocketLabel retrieves the current socket label setting +func SocketLabel() (string, error) { + return "", nil +} + // Get returns the Context as a string func (c Context) Get() string { return "" |