diff options
-rw-r--r-- | Dockerfile | 2 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | README.md | 39 | ||||
-rw-r--r-- | cmd/podman/generate_kube.go | 2 | ||||
-rw-r--r-- | cmd/podman/run.go | 5 | ||||
-rw-r--r-- | cmd/podman/start.go | 14 | ||||
-rw-r--r-- | contrib/cirrus/README.md | 52 | ||||
-rw-r--r-- | libpod/boltdb_state_internal.go | 4 | ||||
-rw-r--r-- | libpod/oci.go | 1 | ||||
-rw-r--r-- | test/e2e/run_test.go | 27 | ||||
-rw-r--r-- | test/e2e/start_test.go | 26 | ||||
-rw-r--r-- | test/e2e/systemd_test.go | 81 | ||||
-rw-r--r-- | vendor.conf | 2 | ||||
-rw-r--r-- | vendor/github.com/opencontainers/selinux/go-selinux/label/label.go | 18 | ||||
-rw-r--r-- | vendor/github.com/opencontainers/selinux/go-selinux/label/label_selinux.go | 13 | ||||
-rw-r--r-- | vendor/github.com/opencontainers/selinux/go-selinux/selinux_linux.go | 11 | ||||
-rw-r--r-- | vendor/github.com/opencontainers/selinux/go-selinux/selinux_stub.go | 13 |
17 files changed, 262 insertions, 50 deletions
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 @@ -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/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/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/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/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/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/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 "" |