diff options
-rw-r--r-- | .cirrus.yml | 39 | ||||
-rw-r--r-- | Makefile | 7 | ||||
-rw-r--r-- | contrib/cirrus/README.md | 20 | ||||
-rw-r--r-- | contrib/cirrus/lib.sh | 53 | ||||
-rwxr-xr-x | contrib/cirrus/rootless_test.sh | 36 | ||||
-rwxr-xr-x | contrib/cirrus/setup_environment.sh | 20 | ||||
-rw-r--r-- | crio-umount.conf | 8 | ||||
-rw-r--r-- | libpod/runtime_pod_infra_linux.go | 24 | ||||
-rw-r--r-- | test/README.md | 32 | ||||
-rw-r--r-- | test/e2e/pod_infra_container_test.go | 12 | ||||
-rw-r--r-- | troubleshooting.md | 39 |
11 files changed, 256 insertions, 34 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 328b2e676..9ce690196 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -67,6 +67,13 @@ env: RHEL_BASE_IMAGE: "rhel-guest-image-7-6-210-x86-64-qcow2-1548099756" #### + #### Default to NOT running in rootless-testing mode + #### + ROOTLESS_USER: + ROOTLESS_UID: + ROOTLESS_GID: + + #### #### Credentials and other secret-sauces, decrypted at runtime when authorized. #### # Freenode IRC credentials for posting status messages @@ -94,7 +101,7 @@ env: CIRRUS_TASK_ID CIRRUS_REPO_NAME CIRRUS_REPO_OWNER CIRRUS_REPO_FULL_NAME CIRRUS_REPO_CLONE_URL CIRRUS_SHELL CIRRUS_USER_COLLABORATOR CIRRUS_USER_PERMISSION CIRRUS_WORKING_DIR CIRRUS_HTTP_CACHE_HOST PACKER_BUILDS BUILT_IMAGE_SUFFIX - XDG_DATA_DIRS XDG_RUNTIME_DIR XDG_SESSION_ID + XDG_DATA_DIRS XDG_RUNTIME_DIR XDG_SESSION_ID ROOTLESS_USER ROOTLESS_UID ROOTLESS_GID # Every *_task runs in parallel in separate VMsd. The name prefix only for reference @@ -220,6 +227,36 @@ testing_task: integration_test_script: $SCRIPT_BASE/integration_test.sh +# This task executes tests as a regular user on a system +rootless_testing_task: + + depends_on: + - "gating" + - "build_each_commit" + + gce_instance: + image_project: "libpod-218412" + zone: "us-central1-a" # Required by Cirrus for the time being + cpu: 2 + memory: "4Gb" + disk: 200 + # A matrix could be used here, for now just one VM + image_name: "${FEDORA_CACHE_IMAGE_NAME}" + + env: + ROOTLESS_USER: "olympiclongjumpingwithjesus" + ROOTLESS_UID: 123456 + ROOTLESS_GID: 123456 + + timeout_in: 120m + + setup_environment_script: $SCRIPT_BASE/setup_environment.sh + rootless_test_script: >- + ssh $ROOTLESS_USER@localhost + -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -o CheckHostIP=no + $CIRRUS_WORKING_DIR/$SCRIPT_BASE/rootless_test.sh + + # Because system tests are stored within the repository, it is sometimes # necessary to execute them within a PR to validate changes. optional_testing_task: @@ -16,7 +16,6 @@ LIBEXECDIR ?= ${PREFIX}/libexec MANDIR ?= ${PREFIX}/share/man SHAREDIR_CONTAINERS ?= ${PREFIX}/share/containers ETCDIR ?= ${DESTDIR}/etc -ETCDIR_LIBPOD ?= ${ETCDIR}/crio TMPFILESDIR ?= ${PREFIX}/lib/tmpfiles.d SYSTEMDDIR ?= ${PREFIX}/lib/systemd/system BUILDTAGS ?= seccomp $(shell hack/btrfs_tag.sh) $(shell hack/btrfs_installed_tag.sh) $(shell hack/ostree_tag.sh) $(shell hack/selinux_tag.sh) $(shell hack/apparmor_tag.sh) varlink exclude_graphdriver_devicemapper @@ -28,7 +27,6 @@ CONTAINER_RUNTIME := $(shell command -v podman 2> /dev/null || echo docker) OCI_RUNTIME ?= "" BASHINSTALLDIR=${PREFIX}/share/bash-completion/completions -OCIUMOUNTINSTALLDIR=$(PREFIX)/share/oci-umount/oci-umount.d SELINUXOPT ?= $(shell test -x /usr/sbin/selinuxenabled && selinuxenabled && echo -Z) PACKAGES ?= $(shell $(GO) list -tags "${BUILDTAGS}" ./... | grep -v github.com/containers/libpod/vendor | grep -v e2e | grep -v system ) @@ -242,10 +240,9 @@ install.man: docs install ${SELINUXOPT} -m 644 docs/links/*1 -t $(MANDIR)/man1 install.config: - install ${SELINUXOPT} -d -m 755 $(SHAREDIR_CONTAINERS) $(ETCDIR_LIBPOD) $(OCIUMOUNTINSTALLDIR) + install ${SELINUXOPT} -d -m 755 $(SHAREDIR_CONTAINERS) install ${SELINUXOPT} -m 644 libpod.conf $(SHAREDIR_CONTAINERS)/libpod.conf - install ${SELINUXOPT} -m 644 seccomp.json $(ETCDIR_LIBPOD)/seccomp.json - install ${SELINUXOPT} -m 644 crio-umount.conf $(OCIUMOUNTINSTALLDIR)/crio-umount.conf + install ${SELINUXOPT} -m 644 seccomp.json $(SHAREDIR_CONTAINERS)/seccomp.json install.completions: install ${SELINUXOPT} -d -m 755 ${BASHINSTALLDIR} diff --git a/contrib/cirrus/README.md b/contrib/cirrus/README.md index e3b3182ec..0dabf5df6 100644 --- a/contrib/cirrus/README.md +++ b/contrib/cirrus/README.md @@ -63,6 +63,26 @@ task (pass or fail) is set based on the exit status of the last script to execut Total execution time is capped at 2-hours (includes all the above) but this script normally completes in less than an hour. +### ``rootless_testing`` Task + +***N/B: Steps below are performed by automation*** + +1. After `gating` passes, spin up one VM per + `matrix: image_name` item. Once accessible, ``ssh`` + into each VM as the `root` user. + +2. ``setup_environment.sh``: Configure root's `.bash_profile` + the same as for other tasks. However, also add a regular + user account, chown all the source code to them. Set up + fresh ssh pub/priv. keys for the root user, adding the + public part to the user's `authorized_keys` file. + +3. As root, call ssh to connect to localhost as the user, + and run the ``rootless_test.sh`` script from the source + tree. This is needed so the user has a clean process tree + and environment - i.e. without `sudo`, `su`, `runuser`, + etc. in the mix. From here, all testing as the user may + be performed. ### ``optional_testing`` Task diff --git a/contrib/cirrus/lib.sh b/contrib/cirrus/lib.sh index acd2447c0..9419dad05 100644 --- a/contrib/cirrus/lib.sh +++ b/contrib/cirrus/lib.sh @@ -53,6 +53,9 @@ show_env_vars() { echo " BUILDTAGS $BUILDTAGS BUILT_IMAGE_SUFFIX $BUILT_IMAGE_SUFFIX +ROOTLESS_USER $ROOTLESS_USER +ROOTLESS_UID $ROOTLESS_UID +ROOTLESS_GID $ROOTLESS_GID CI $CI CIRRUS_CI $CIRRUS_CI CI_NODE_INDEX $CI_NODE_INDEX @@ -117,6 +120,15 @@ bad_os_id_ver() { exit 42 } +run_rootless() { + if [[ -z "$ROOTLESS_USER" ]] && [[ -z "$ROOTLESS_UID" ]] && [[ -z "$ROOTLESS_GID" ]] + then + return 1 + else + return 0 + fi +} + stub() { echo "STUB: Pretending to do $1" } @@ -146,12 +158,41 @@ record_timestamp() { echo -e "BLEEEEEEEEEEP!\n." } -# Run sudo in directory with GOPATH set -cdsudo() { - DIR="$1" - shift - CMD="cd $DIR && $@" - sudo --preserve-env=GOPATH --non-interactive bash -c "$CMD" +setup_rootless() { + req_env_var " + ROOTLESS_USER $ROOTLESS_USER + ROOTLESS_UID $ROOTLESS_UID + ROOTLESS_GID $ROOTLESS_GID + GOSRC $GOSRC + ENVLIB $ENVLIB + " + echo "creating $ROOTLESS_UID:$ROOTLESS_GID $ROOTLESS_USER user" + groupadd -g $ROOTLESS_GID $ROOTLESS_USER + useradd -g $ROOTLESS_GID -u $ROOTLESS_UID --no-user-group --create-home $ROOTLESS_USER + chown -R $ROOTLESS_UID:$ROOTLESS_GID "$GOSRC" + + echo "creating ssh keypair for $USER" + ssh-keygen -P "" -f $HOME/.ssh/id_rsa + + echo "Allowing ssh key for $ROOTLESS_USER" + (umask 077 && mkdir "/home/$ROOTLESS_USER/.ssh") + chown -R $ROOTLESS_UID:$ROOTLESS_GID "/home/$ROOTLESS_USER/.ssh" + install -o $ROOTLESS_UID -g $ROOTLESS_GID -m 0600 \ + "$HOME/.ssh/id_rsa.pub" "/home/$ROOTLESS_USER/.ssh/authorized_keys" + + echo "Setting permissions on automation files" + chmod 666 "$TIMESTAMPS_FILEPATH" + + echo "Copying $HOME/$ENVLIB" + install -o $ROOTLESS_UID -g $ROOTLESS_GID -m 0700 \ + "$HOME/$ENVLIB" "/home/$ROOTLESS_USER/$ENVLIB" + + echo "Configuring user's go environment variables" + su --login --command 'go env' $ROOTLESS_USER | \ + while read envline + do + X=$(echo "export $envline" | tee -a "/home/$ROOTLESS_USER/$ENVLIB") && echo "$X" + done } # Helper/wrapper script to only show stderr/stdout on non-zero exit diff --git a/contrib/cirrus/rootless_test.sh b/contrib/cirrus/rootless_test.sh new file mode 100755 index 000000000..811b7cf2e --- /dev/null +++ b/contrib/cirrus/rootless_test.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +set -e +source $HOME/.bash_profile + +cd $GOSRC +source $(dirname $0)/lib.sh + +req_env_var " +GOSRC $GOSRC +OS_RELEASE_ID $OS_RELEASE_ID +OS_RELEASE_VER $OS_RELEASE_VER +" + +if ! run_rootless +then + echo "Error: Expected rootless env. vars not set or empty" + exit 1 +fi + +echo "." +echo "Hello, my name is $USER and I live in $PWD can I be your friend?" + +record_timestamp "rootless test start" + +cd "$GOSRC" +case "${OS_RELEASE_ID}-${OS_RELEASE_VER}" in + ubuntu-18) ;& # Continue to the next item + fedora-29) ;& + fedora-28) + make + ;; + *) bad_os_id_ver ;; +esac + +record_timestamp "rootless test end" diff --git a/contrib/cirrus/setup_environment.sh b/contrib/cirrus/setup_environment.sh index c3276bb6f..d8d97904b 100755 --- a/contrib/cirrus/setup_environment.sh +++ b/contrib/cirrus/setup_environment.sh @@ -43,6 +43,9 @@ then "export OS_RELEASE_ID=\"$(os_release_id)\"" \ "export OS_RELEASE_VER=\"$(os_release_ver)\"" \ "export OS_REL_VER=\"$(os_release_id)-$(os_release_ver)\"" \ + "export ROOTLESS_USER=$ROOTLESS_USER" \ + "export ROOTLESS_UID=$ROOTLESS_UID" \ + "export ROOTLESS_GID=$ROOTLESS_GID" \ "export BUILT_IMAGE_SUFFIX=\"-$CIRRUS_REPO_NAME-${CIRRUS_CHANGE_IN_REPO:0:8}\"" \ "export GOPATH=\"/var/tmp/go\"" \ 'export PATH="$HOME/bin:$GOPATH/bin:/usr/local/bin:$PATH"' \ @@ -70,14 +73,19 @@ then *) bad_os_id_ver ;; esac - # Do the same for golang env. vars - go env | while read envline - do - X=$(echo "export $envline" | tee -a "$HOME/$ENVLIB") && eval "$X" && echo "$X" - done - cd "${GOSRC}/" source "$SCRIPT_BASE/lib.sh" + + if run_rootless + then + setup_rootless + else + # Includes some $HOME relative details + go env | while read envline + do + X=$(echo "export $envline" | tee -a "$HOME/$ENVLIB") && eval "$X" && echo "$X" + done + fi fi record_timestamp "env. setup end" diff --git a/crio-umount.conf b/crio-umount.conf deleted file mode 100644 index 5177e6362..000000000 --- a/crio-umount.conf +++ /dev/null @@ -1,8 +0,0 @@ -# This contains a list of paths on host which will be unmounted inside -# container. (If they are mounted inside container). - -# If there is a "/*" at the end, that means only mounts underneath that -# mounts (submounts) will be unmounted but top level mount will remain -# in place. -/var/run/containers/* -/var/lib/containers/storage/* diff --git a/libpod/runtime_pod_infra_linux.go b/libpod/runtime_pod_infra_linux.go index 4f221764a..81579db4b 100644 --- a/libpod/runtime_pod_infra_linux.go +++ b/libpod/runtime_pod_infra_linux.go @@ -4,11 +4,14 @@ package libpod import ( "context" + "strings" "github.com/containers/libpod/libpod/image" "github.com/containers/libpod/pkg/rootless" + "github.com/opencontainers/image-spec/specs-go/v1" spec "github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-tools/generate" + "github.com/pkg/errors" ) const ( @@ -17,7 +20,7 @@ const ( IDTruncLength = 12 ) -func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID string) (*Container, error) { +func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID string, config *v1.ImageConfig) (*Container, error) { // Set up generator for infra container defaults g, err := generate.New("linux") @@ -27,8 +30,23 @@ func (r *Runtime) makeInfraContainer(ctx context.Context, p *Pod, imgName, imgID isRootless := rootless.IsRootless() + entryCmd := []string{r.config.InfraCommand} + // default to entrypoint in image if there is one + if len(config.Entrypoint) > 0 { + entryCmd = config.Entrypoint + } + if len(config.Env) > 0 { + for _, nameValPair := range config.Env { + nameValSlice := strings.Split(nameValPair, "=") + if len(nameValSlice) < 2 { + return nil, errors.Errorf("Invalid environment variable structure in pause image") + } + g.AddProcessEnv(nameValSlice[0], nameValSlice[1]) + } + } + g.SetRootReadonly(true) - g.SetProcessArgs([]string{r.config.InfraCommand}) + g.SetProcessArgs(entryCmd) if isRootless { g.RemoveMount("/dev/pts") @@ -79,5 +97,5 @@ func (r *Runtime) createInfraContainer(ctx context.Context, p *Pod) (*Container, imageName := newImage.Names()[0] imageID := data.ID - return r.makeInfraContainer(ctx, p, imageName, imageID) + return r.makeInfraContainer(ctx, p, imageName, imageID, newImage.Config) } diff --git a/test/README.md b/test/README.md index 5e5a7da61..4e61a0774 100644 --- a/test/README.md +++ b/test/README.md @@ -43,6 +43,11 @@ Build ginkgo and install it under $GOPATH/bin with the following command: ``` GOPATH=~/go make .install.ginkgo ``` +If your PATH does not include $GOPATH/bin, you might consider adding it. + +``` +PATH=$PATH:$GOPATH/bin +``` # Integration Tests Test suite for integration test for podman command line. It has its own structs: @@ -63,21 +68,38 @@ GOPATH=~/go ginkgo -v test/e2e/. Note the trailing period on the command above. Also, **-v** invokes verbose mode. That switch is optional. + +### Running a single file of integration tests You can run a single file of integration tests using the go test command: ``` GOPATH=~/go go test -v test/e2e/libpod_suite_test.go test/e2e/common_test.go test/e2e/config.go test/e2e/config_amd64.go test/e2e/your_test.go ``` -#### Run all tests like PAPR -You can closely emulate the PAPR run for Fedora with the following command: +### Running a single integration test +Before running the test suite, you have to declare which test you want run in the test +file itself. Consider the following actual test: +``` +It("podman inspect bogus pod", func() { + session := podmanTest.Podman([]string{"pod", "inspect", "foobar"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) +``` + +To mark this as the test you want run, you simply change the *It* description to *FIt*. Please note how +both the `F` and `I` are capitalized. + +You can run a single integration test using the same command we used to run all the tests in a single +file. ``` -make integration.fedora +GOPATH=~/go go test -v test/e2e/libpod_suite_test.go test/e2e/common_test.go test/e2e/config.go test/e2e/config_amd64.go test/e2e/your_test.go ``` -This will run lint, git-validation, and gofmt tests and then execute unit and integration -tests as well. +*Note*: Be sure you remove the `F` from the tests before committing your changes or you will skip all tests +in that file except the one with the `FIt` denotation. + ### Run tests in a container In case you have issue running the tests locally on your machine, you can run diff --git a/test/e2e/pod_infra_container_test.go b/test/e2e/pod_infra_container_test.go index 99197dc39..82f35999c 100644 --- a/test/e2e/pod_infra_container_test.go +++ b/test/e2e/pod_infra_container_test.go @@ -69,6 +69,18 @@ var _ = Describe("Podman pod create", func() { Expect(len(check.OutputToStringArray())).To(Equal(1)) }) + It("podman start infra container different image", func() { + session := podmanTest.Podman([]string{"pod", "create", "--infra-image", BB}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + podID := session.OutputToString() + + session = podmanTest.Podman([]string{"pod", "start", podID}) + session.WaitWithDefaultTimeout() + // If we use the default entry point, we should exit with no error + Expect(session.ExitCode()).To(Equal(0)) + }) + It("podman infra container namespaces", func() { session := podmanTest.Podman([]string{"pod", "create"}) session.WaitWithDefaultTimeout() diff --git a/troubleshooting.md b/troubleshooting.md index 24a1dc6cb..33434cdbb 100644 --- a/troubleshooting.md +++ b/troubleshooting.md @@ -254,3 +254,42 @@ grep johndoe /etc/subuid /etc/subgid /etc/subuid:johndoe:200000:1001 /etc/subgid:johndoe:200000:1001 ``` + +### 11) Changing the location of the Graphroot leads to permission denied + +When I change the graphroot storage location in storage.conf, the next time I +run podman I get an error like: + +``` +# podman run -p 5000:5000 -it centos bash + +bash: error while loading shared libraries: /lib64/libc.so.6: cannot apply additional memory protection after relocation: Permission denied +``` + +For example, the admin sets up a spare disk to be mounted at `/src/containers`, +and points storage.conf at this directory. + + +#### Symptom + +SELinux blocks containers from using random locations for overlay storage. +These directories need to be labeled with the same labels as if the content was +under /var/lib/containers/storage. + +#### Solution + +Tell SELinux about the new containers storage by setting up an equivalence record. +This tells SELinux to label content under the new path, as if it was stored +under `/var/lib/containers/storage`. + +``` +semanage fcontext -a -e /var/lib/containers /srv/containers +restorecon -R -v /src/containers +``` + +The semanage command above tells SELinux to setup the default labeling of +`/srv/containers` to match `/var/lib/containers`. The `restorecon` command +tells SELinux to apply the labels to the actual content. + +Now all new content created in these directories will automatically be created +with the correct label. |