diff options
-rw-r--r-- | .cirrus.yml | 15 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | cmd/podman/cp.go | 4 | ||||
-rwxr-xr-x | contrib/cirrus/build_release.sh | 24 | ||||
-rw-r--r-- | contrib/cirrus/packer/fedora_setup.sh | 3 | ||||
-rwxr-xr-x | contrib/cirrus/upload_release_archive.sh | 62 | ||||
-rwxr-xr-x | contrib/upldrel/entrypoint.sh | 57 | ||||
-rw-r--r-- | docs/podman-cp.1.md | 2 | ||||
-rw-r--r-- | docs/podman-derivative-api.md | 44 | ||||
-rw-r--r-- | docs/tutorials/README.md | 10 | ||||
-rwxr-xr-x | hack/get_release_info.sh | 2 | ||||
-rw-r--r-- | pkg/adapter/pods.go | 3 | ||||
-rw-r--r-- | test/e2e/cp_test.go | 51 | ||||
-rw-r--r-- | test/system/065-cp.bats | 13 |
14 files changed, 198 insertions, 95 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index d128337c3..1665f3d9c 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -351,8 +351,14 @@ testing_task: integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP}' system_test_script: '$SCRIPT_BASE/system_test.sh |& ${TIMESTAMP}' build_release_script: '$SCRIPT_BASE/build_release.sh |& ${TIMESTAMP}' + # For PRs this confirms uploading releases after merge, is functional. upload_release_archive_script: '$SCRIPT_BASE/upload_release_archive.sh |& ${TIMESTAMP}' + # When examining a particular run, provide convenient access to release files. + tar_artifacts: + path: "*.tar.gz" + type: "application/x-tar" + on_failure: failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh' @@ -480,6 +486,15 @@ special_testing_cross_task: on_failure: failed_branch_script: '$CIRRUS_WORKING_DIR/$SCRIPT_BASE/notice_branch_failure.sh' + # When examining a particular run, provide convenient access to release files. + zip_artifacts: + path: "*.zip" + type: "application/zip" + + msi_artifacts: + path: "*.msi" + type: "application/octet-stream" + special_testing_cgroupv2_task: @@ -35,6 +35,9 @@ This project tests all builds against each supported version of Fedora, the late ## Communications +If you think you've identified a security issue in the project, please *DO NOT* report the issue publically via the Github issue tracker, mailing list, or IRC. +Instead, send an email with as many details as possible to `security@lists.podman.io`. This is a private mailing list for the core maintainers. + For general questions and discussion, please use the IRC `#podman` channel on `irc.freenode.net`. diff --git a/cmd/podman/cp.go b/cmd/podman/cp.go index 7205f9357..75a23afd6 100644 --- a/cmd/podman/cp.go +++ b/cmd/podman/cp.go @@ -290,7 +290,7 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch } destdir := destPath - if !srcfi.IsDir() && !strings.HasSuffix(dest, string(os.PathSeparator)) { + if !srcfi.IsDir() { destdir = filepath.Dir(destPath) } _, err = os.Stat(destdir) @@ -329,7 +329,7 @@ func copy(src, destPath, dest string, idMappingOpts storage.IDMappingOptions, ch destfi, err := os.Stat(destPath) if err != nil { - if !os.IsNotExist(err) { + if !os.IsNotExist(err) || strings.HasSuffix(dest, string(os.PathSeparator)) { return errors.Wrapf(err, "failed to get stat of dest path %s", destPath) } } diff --git a/contrib/cirrus/build_release.sh b/contrib/cirrus/build_release.sh index 287643f47..07db88f81 100755 --- a/contrib/cirrus/build_release.sh +++ b/contrib/cirrus/build_release.sh @@ -1,5 +1,7 @@ #!/bin/bash +set -e + source $(dirname $0)/lib.sh req_env_var TEST_REMOTE_CLIENT OS_RELEASE_ID GOSRC @@ -13,18 +15,20 @@ fi if [[ -n "$CROSS_PLATFORM" ]] then + # Will fail if $CROSS_PLATFORM is unsupported cross-compile $GOOS value + make podman-remote-${CROSS_PLATFORM}-release + echo "Compiling podman-remote release archive for ${CROSS_PLATFORM}" - case "$CROSS_PLATFORM" in - linux) ;& - windows) ;& - darwin) - make podman-remote-${CROSS_PLATFORM}-release - ;; - *) - die 1 "Unknown/unsupported cross-compile platform '$CROSS_PLATFORM'" - ;; - esac + if [[ "$CROSS_PLATFORM" == "windows" ]] + then + # TODO: Remove next line, part of VM images next time they're built. + dnf install -y libmsi1 msitools pandoc + make podman.msi + fi else echo "Compiling release archive for $OS_RELEASE_ID" make podman-release fi + +echo "Preserving build details for later use." +mv -v release.txt actual_release.txt # Another 'make' during testing could overwrite it diff --git a/contrib/cirrus/packer/fedora_setup.sh b/contrib/cirrus/packer/fedora_setup.sh index 6709eecaf..f84645a04 100644 --- a/contrib/cirrus/packer/fedora_setup.sh +++ b/contrib/cirrus/packer/fedora_setup.sh @@ -53,6 +53,7 @@ ooe.sh sudo dnf install -y \ jq \ libassuan-devel \ libcap-devel \ + libmsi1 \ libnet \ libnet-devel \ libnl3-devel \ @@ -62,9 +63,11 @@ ooe.sh sudo dnf install -y \ libvarlink-util \ lsof \ make \ + msitools \ nmap-ncat \ ostree \ ostree-devel \ + pandoc \ podman \ procps-ng \ protobuf \ diff --git a/contrib/cirrus/upload_release_archive.sh b/contrib/cirrus/upload_release_archive.sh index 942255821..25107f0ef 100755 --- a/contrib/cirrus/upload_release_archive.sh +++ b/contrib/cirrus/upload_release_archive.sh @@ -9,6 +9,7 @@ req_env_var CI UPLDREL_IMAGE CIRRUS_BUILD_ID GOSRC RELEASE_GCPJSON RELEASE_GCPNA [[ "$CI" == "true" ]] || \ die 56 "$0 must be run under Cirrus-CI to function" +# We store "releases" for each PR, mostly to validate the process is functional unset PR_OR_BRANCH BUCKET if [[ -n "$CIRRUS_PR" ]] then @@ -22,31 +23,76 @@ else die 1 "Expecting either \$CIRRUS_PR or \$CIRRUS_BRANCH to be non-empty." fi -# Functional local podman required for uploading a release +echo "Parsing actual_release.txt contents: $(< actual_release.txt)" cd $GOSRC +RELEASETXT=$(<actual_release.txt) # see build_release.sh +[[ -n "$RELEASETXT" ]] || \ + die 3 "Could not obtain metadata from actual_release.txt" +RELEASE_INFO=$(echo "$RELEASETXT" | grep -m 1 'X-RELEASE-INFO:' | sed -r -e 's/X-RELEASE-INFO:\s*(.+)/\1/') +if [[ "$?" -ne "0" ]] || [[ -z "$RELEASE_INFO" ]] +then + die 4 "Metadata is empty or invalid: '$RELEASETXT'" +fi +# Format specified in Makefile +# e.g. libpod v1.3.1-166-g60df124e fedora 29 amd64 +# or libpod-remote v1.3.1-166-g60df124e windows - amd64 +FIELDS="RELEASE_BASENAME RELEASE_VERSION RELEASE_DIST RELEASE_DIST_VER RELEASE_ARCH" +read $FIELDS <<< $RELEASE_INFO +req_env_var $FIELDS + +# Functional local podman required for uploading +echo "Verifying a local, functional podman, building one if necessary." [[ -n "$(type -P podman)" ]] || \ - make install || \ + make install PREFIX=/usr || \ die 57 "$0 requires working podman binary on path to function" TMPF=$(mktemp -p '' $(basename $0)_XXXX.json) trap "rm -f $TMPF" EXIT set +x echo "$RELEASE_GCPJSON" > "$TMPF" +[[ "$OS_RELEASE_ID" == "ubuntu" ]] || \ + chcon -t container_file_t "$TMPF" unset RELEASE_GCPJSON cd $GOSRC -for filename in $(ls -1 *.tar.gz *.zip) +for filename in $(ls -1 *.tar.gz *.zip *.msi) do - echo "Running podman ... $UPLDREL_IMAGE $filename" + unset EXT + EXT=$(echo "$filename" | sed -r -e 's/.+\.(.+$)/\1/g') + if [[ -z "$EXT" ]] || [[ "$EXT" == "$filename" ]] + then + echo "Warning: Not processing $filename (invalid extension '$EXT')" + continue + fi + + [[ "$OS_RELEASE_ID" == "ubuntu" ]] || \ + chcon -t container_file_t "$filename" + # Form the generic "latest" file for this branch or pr + TO_PREFIX="${RELEASE_BASENAME}-latest-${PR_OR_BRANCH}-${RELEASE_DIST}" + # Form the fully-versioned filename for historical sake + ALSO_PREFIX="${RELEASE_BASENAME}-${RELEASE_VERSION}-${PR_OR_BRANCH}-${RELEASE_DIST}" + TO_SUFFIX="${RELEASE_ARCH}.${EXT}" + if [[ "$RELEASE_DIST" == "windows" ]] || [[ "$RELEASE_DIST" == "darwin" ]] + then + TO_FILENAME="${TO_PREFIX}-${TO_SUFFIX}" + ALSO_FILENAME="${ALSO_PREFIX}-${TO_SUFFIX}" + else + TO_FILENAME="${TO_PREFIX}-${RELEASE_DIST_VER}-${TO_SUFFIX}" + ALSO_FILENAME="${ALSO_PREFIX}-${TO_SUFFIX}" + fi + + echo "Running podman ... $UPLDREL_IMAGE for $filename -> $TO_FILENAME" + echo "Warning: upload failures are completely ignored, avoiding any needless holdup of PRs." podman run -i --rm \ -e "GCPNAME=$RELEASE_GCPNAME" \ -e "GCPPROJECT=$RELEASE_GCPROJECT" \ -e "GCPJSON_FILEPATH=$TMPF" \ - -e "REL_ARC_FILEPATH=/tmp/$filename" \ + -e "FROM_FILEPATH=/tmp/$filename" \ + -e "TO_FILENAME=$TO_FILENAME" \ + -e "ALSO_FILENAME=$ALSO_FILENAME" \ -e "PR_OR_BRANCH=$PR_OR_BRANCH" \ -e "BUCKET=$BUCKET" \ - --security-opt label=disable \ -v "$TMPF:$TMPF:ro" \ - -v "$GOSRC/$filename:/tmp/$filename:ro" \ - $UPLDREL_IMAGE + -v "$(realpath $GOSRC/$filename):/tmp/$filename:ro" \ + $UPLDREL_IMAGE || true done diff --git a/contrib/upldrel/entrypoint.sh b/contrib/upldrel/entrypoint.sh index 985b828a0..6af6829c5 100755 --- a/contrib/upldrel/entrypoint.sh +++ b/contrib/upldrel/entrypoint.sh @@ -4,59 +4,22 @@ set -e source /usr/local/bin/lib_entrypoint.sh -req_env_var GCPJSON_FILEPATH GCPNAME GCPPROJECT REL_ARC_FILEPATH PR_OR_BRANCH BUCKET +req_env_var GCPJSON_FILEPATH GCPNAME GCPPROJECT BUCKET FROM_FILEPATH TO_FILENAME ALSO_FILENAME -[[ -r "$REL_ARC_FILEPATH" ]] || \ +[[ -r "$FROM_FILEPATH" ]] || \ die 2 ERROR Cannot read release archive file: "$REL_ARC_FILEPATH" [[ -r "$GCPJSON_FILEPATH" ]] || \ die 3 ERROR Cannot read GCP credentials file: "$GCPJSON_FILEPATH" -cd $TMPDIR -echo "Attempting to extract release.txt from tar or zip $REL_ARC_FILEPATH" -unset SFX -if tar xzf "$REL_ARC_FILEPATH" "./release.txt" -then - echo "It's a tarball" - SFX="tar.gz" -elif unzip "$REL_ARC_FILEPATH" release.txt -then - echo "It's a zip" - SFX="zip" -else - die 5 ERROR Could not extract release.txt from $REL_ARC_FILEPATH -fi - -echo "Parsing release.txt contents" -RELEASETXT=$(<release.txt) -cd - -[[ -n "$RELEASETXT" ]] || \ - die 3 ERROR Could not obtain metadata from release.txt in $REL_ARC_FILEPATH - -RELEASE_INFO=$(echo "$RELEASETXT" | grep -m 1 'X-RELEASE-INFO:' | sed -r -e 's/X-RELEASE-INFO:\s*(.+)/\1/') -if [[ "$?" -ne "0" ]] || [[ -z "$RELEASE_INFO" ]] -then - die 4 ERROR Metadata is empty or invalid: '$RELEASETXT' -fi - -# e.g. libpod v1.3.1-166-g60df124e fedora 29 amd64 -# or libpod v1.3.1-166-g60df124e amd64 -FIELDS="RELEASE_BASENAME RELEASE_VERSION RELEASE_DIST RELEASE_DIST_VER RELEASE_ARCH" -read $FIELDS <<< $RELEASE_INFO -for f in $FIELDS -do - [[ -n "${!f}" ]] || \ - die 5 ERROR Expecting $f to be non-empty in metadata: '$RELEASE_INFO' -done - +echo "Authenticating to google cloud for upload" gcloud_init "$GCPJSON_FILEPATH" -# Drop version number to enable "latest" representation -# (version available w/in zip-file comment) -RELEASE_ARCHIVE_NAME="${RELEASE_BASENAME}-${PR_OR_BRANCH}-${RELEASE_DIST}-${RELEASE_DIST_VER}-${RELEASE_ARCH}.${SFX}" - -echo "Uploading archive as $RELEASE_ARCHIVE_NAME" -gsutil cp "$REL_ARC_FILEPATH" "gs://$BUCKET/$RELEASE_ARCHIVE_NAME" +echo "Uploading archive as $TO_FILENAME" +gsutil cp "$FROM_FILEPATH" "gs://$BUCKET/$TO_FILENAME" +gsutil cp "$FROM_FILEPATH" "gs://$BUCKET/$ALSO_FILENAME" -echo "Release now available at:" -echo " https://storage.cloud.google.com/$BUCKET/$RELEASE_ARCHIVE_NAME" +echo "." +echo "Release now available for download at:" +echo " https://storage.cloud.google.com/$BUCKET/$TO_FILENAME" +echo " https://storage.cloud.google.com/$BUCKET/$ALSO_FILENAME" diff --git a/docs/podman-cp.1.md b/docs/podman-cp.1.md index 736bdb12a..0f54b2e8b 100644 --- a/docs/podman-cp.1.md +++ b/docs/podman-cp.1.md @@ -29,7 +29,7 @@ Assuming a path separator of /, a first argument of **src_path** and second argu - **dest_path** does not exist - the file is saved to a file created at **dest_path** - **dest_path** does not exist and ends with / - - **dest_path** is created as a directory and the file is copied into this directory using the basename from **src_path** + - Error condition: the destination directory must exist. - **dest_path** exists and is a file - the destination is overwritten with the source file's contents - **dest_path** exists and is a directory diff --git a/docs/podman-derivative-api.md b/docs/podman-derivative-api.md new file mode 100644 index 000000000..0342bb740 --- /dev/null +++ b/docs/podman-derivative-api.md @@ -0,0 +1,44 @@ +# How to use libpod for custom/derivative projects + +libpod today is a Golang library and a CLI. The choice of interface you make has advantages and disadvantages. + +Running as a subprocess +--- + +Advantages: + + - Many commands output JSON + - Works with languages other than Golang + - Easy to get started + +Disadvantages: + + - Error handling is harder + - May be slower + - Can't hook into or control low-level things like how images are pulled + +Vendoring into a Go project +--- + +Advantages: + + - Significant power and control + +Disadvantages: + + - You are now on the hook for container runtime security updates (partially, `runc`/`crun` are separate) + - Binary size + - Potential skew between multiple libpod versions operating on the same storage can cause problems + +Varlink +--- + +Some code exists for this; splits the difference. Future uncertain. + +Making the choice +--- + +A good question to ask first is: Do you want users to be able to use `podman` to manipulate the containers created by your project? +If so, that makes it more likely that you want to run `podman` as a subprocess. If you want a separate image store and a fundamentally +different experience; if what you're doing with containers is quite different from those created by the `podman` CLI, +that may drive you towards vendoring.
\ No newline at end of file diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md index c340d683f..2cf9613b6 100644 --- a/docs/tutorials/README.md +++ b/docs/tutorials/README.md @@ -4,18 +4,18 @@ ## Links to a number of useful tutorials for the Podman utility. -**[Introduction Tutorial](https://github.com/containers/libpod/tree/master/docs/tutorials/podman_tutorial.md)** +**[Introduction Tutorial](podman_tutorial.md)** Learn how to setup Podman and perform some basic commands with the utility. -**[Basic Setup and Use of Podman in a Rootless environment.](https://github.com/containers/libpod/blob/master/docs/tutorials/rootless_tutorial.md).** +**[Basic Setup and Use of Podman in a Rootless environment](rootless_tutorial.md)** The steps required to setup rootless Podman are enumerated. -**[Setup on OS X](https://github.com/containers/libpod/blob/master/doc/tutorials/mac_client.md)** +**[Setup on OS X](mac_client.md)** -Special setup for running the Podman remote client on a Mac and connecting to Podman running on a Linux VM are documented +Special setup for running the Podman remote client on a Mac and connecting to Podman running on a Linux VM are documented. -**[Remote Client](https://github.com/containers/libpod/blob/master/doc/tutorials/remote_client.md)** +**[Remote Client](remote_client.md)** A brief how-to on using the Podman remote-client. diff --git a/hack/get_release_info.sh b/hack/get_release_info.sh index 29b4237b4..b75751170 100755 --- a/hack/get_release_info.sh +++ b/hack/get_release_info.sh @@ -33,7 +33,7 @@ case "$1" in OUTPUT="${GOARCH:-$(go env GOARCH 2> /dev/null)}" ;; BASENAME*) - OUTPUT="${CIRRUS_REPO_NAME:-$(basename $(git rev-parse --show-toplevel))}" + OUTPUT="podman" ;; REMOTENAME*) OUTPUT="$($0 BASENAME)-remote" diff --git a/pkg/adapter/pods.go b/pkg/adapter/pods.go index 2905d5466..c8d57e2a2 100644 --- a/pkg/adapter/pods.go +++ b/pkg/adapter/pods.go @@ -473,6 +473,9 @@ func (r *LocalRuntime) PlayKubeYAML(ctx context.Context, c *cliconfig.KubePlayVa // check for name collision between pod and container podName := podYAML.ObjectMeta.Name + if podName == "" { + return nil, errors.Errorf("pod does not have a name") + } for _, n := range podYAML.Spec.Containers { if n.Name == podName { fmt.Printf("a container exists with the same name (%s) as the pod in your YAML file; changing pod name to %s_pod\n", podName, podName) diff --git a/test/e2e/cp_test.go b/test/e2e/cp_test.go index 9b0cb757d..3317683de 100644 --- a/test/e2e/cp_test.go +++ b/test/e2e/cp_test.go @@ -51,6 +51,10 @@ var _ = Describe("Podman cp", func() { err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644) Expect(err).To(BeNil()) + session = podmanTest.Podman([]string{"cp", srcPath, name + ":foo/"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + session = podmanTest.Podman([]string{"cp", srcPath, name + ":foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -65,30 +69,29 @@ var _ = Describe("Podman cp", func() { }) It("podman cp file to dir", func() { - srcPath := filepath.Join(podmanTest.RunRoot, "cp_test.txt") - dstDir := filepath.Join(podmanTest.RunRoot, "receive") + name := "testctr" + setup := podmanTest.RunTopContainer(name) + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + + srcPath := "/tmp/cp_test.txt" fromHostToContainer := []byte("copy from host to container directory") + err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644) + Expect(err).To(BeNil()) - session := podmanTest.Podman([]string{"create", ALPINE, "ls", "foodir/"}) + session := podmanTest.Podman([]string{"exec", name, "mkdir", "foodir"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - name := session.OutputToString() - - err := ioutil.WriteFile(srcPath, fromHostToContainer, 0644) - Expect(err).To(BeNil()) - err = os.Mkdir(dstDir, 0755) - Expect(err).To(BeNil()) session = podmanTest.Podman([]string{"cp", srcPath, name + ":foodir/"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"cp", name + ":foodir/cp_test.txt", dstDir}) + session = podmanTest.Podman([]string{"exec", name, "ls", "foodir/cp_test.txt"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - os.Remove("cp_test.txt") - os.RemoveAll("receive") + os.Remove("/tmp/cp_test.txt") }) It("podman cp dir to dir", func() { @@ -137,10 +140,18 @@ var _ = Describe("Podman cp", func() { session = podmanTest.Podman([]string{"cp", name + ":/foo.tar.gz", "-"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + + os.RemoveAll(testDirPath) + os.Remove("file.tar.gz") }) It("podman cp tar", func() { - session := podmanTest.Podman([]string{"create", "--name", "testctr", ALPINE, "ls", "-l", "foo"}) + testctr := "testctr" + setup := podmanTest.RunTopContainer(testctr) + setup.WaitWithDefaultTimeout() + Expect(setup.ExitCode()).To(Equal(0)) + + session := podmanTest.Podman([]string{"exec", testctr, "mkdir", "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) @@ -157,7 +168,7 @@ var _ = Describe("Podman cp", func() { session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) - session = podmanTest.Podman([]string{"start", "-a", "testctr"}) + session = podmanTest.Podman([]string{"exec", testctr, "ls", "-l", "foo"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) Expect(session.OutputToString()).To(ContainSubstring("file.tar")) @@ -187,6 +198,15 @@ var _ = Describe("Podman cp", func() { _, err = os.Stat("/tmp/cp_test.txt") Expect(err).To(Not(BeNil())) + + session = podmanTest.Podman([]string{"exec", name, "ln", "-s", "/tmp/nonesuch", "/test1"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + + session = podmanTest.Podman([]string{"cp", "--pause=false", srcPath, name + ":/test1/"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Not(Equal(0))) + }) It("podman cp volume", func() { session := podmanTest.Podman([]string{"volume", "create", "data"}) @@ -208,6 +228,9 @@ var _ = Describe("Podman cp", func() { session = podmanTest.Podman([]string{"cp", "container1" + ":/data/cp_vol1", "cp_vol2"}) session.WaitWithDefaultTimeout() Expect(session.ExitCode()).To(Equal(0)) + + os.Remove("cp_vol") + os.Remove("cp_vol2") }) It("podman cp from ctr chown ", func() { diff --git a/test/system/065-cp.bats b/test/system/065-cp.bats index 0ca730a50..38660a13c 100644 --- a/test/system/065-cp.bats +++ b/test/system/065-cp.bats @@ -144,12 +144,13 @@ load helpers trap 'exit 0' 15;while :;do sleep 0.5;done" # Copy file from host into container, into a file named 'x' - # Note that the second has a trailing slash; this will trigger mkdir + # Note that the second has a trailing slash, implying a directory. + # Since that destination directory doesn't exist, the cp will fail run_podman cp --pause=false $srcdir/$rand_filename1 cpcontainer:/tmp/d1/x is "$output" "" "output from podman cp 1" - run_podman cp --pause=false $srcdir/$rand_filename2 cpcontainer:/tmp/d2/x/ - is "$output" "" "output from podman cp 3" + run_podman 125 cp --pause=false $srcdir/$rand_filename2 cpcontainer:/tmp/d2/x/ + is "$output" "Error: failed to get stat of dest path .*stat.* no such file or directory" "cp will not create nonexistent destination directory" run_podman cp --pause=false $srcdir/$rand_filename3 cpcontainer:/tmp/d3/x is "$output" "" "output from podman cp 3" @@ -161,10 +162,8 @@ load helpers run_podman exec cpcontainer cat /tmp/nonesuch1 is "$output" "$rand_content1" "cp creates destination file" - # In the second case, podman creates a directory nonesuch2, then - # creates a file with the same name as the input file. THIS IS WEIRD! - run_podman exec cpcontainer cat /tmp/nonesuch2/$rand_filename2 - is "$output" "$rand_content2" "cp creates destination dir and file" + # cp into nonexistent directory should not mkdir nonesuch2 directory + run_podman 1 exec cpcontainer test -e /tmp/nonesuch2 # In the third case, podman (correctly imo) creates a file named 'x' run_podman exec cpcontainer cat /tmp/d3/x |