github.com/containers/podman/v5@v5.1.0-rc1/test/system/060-mount.bats (about)

     1  #!/usr/bin/env bats
     2  
     3  load helpers
     4  
     5  @test "podman mount - basic test" {
     6      # Only works with root (FIXME: does it work with rootless + vfs?)
     7      skip_if_rootless "mount does not work rootless"
     8      skip_if_remote "mounting remote is meaningless"
     9  
    10      f_path=/tmp/tmpfile_$(random_string 8)
    11      f_content=$(random_string 30)
    12  
    13      c_name=mount_test_$(random_string 5)
    14      run_podman run --name $c_name $IMAGE \
    15                 sh -c "echo $f_content > $f_path"
    16  
    17      run_podman mount $c_name
    18      mount_path=$output
    19  
    20      test -d $mount_path
    21      test -e "$mount_path/$f_path"
    22      is $(< "$mount_path/$f_path") "$f_content" "contents of file, as read via fs"
    23  
    24      # Make sure that 'podman mount' (no args) returns the expected path
    25      run_podman mount --notruncate
    26      # FIXME: is it worth the effort to validate the CID ($1) ?
    27      reported_mountpoint=$(echo "$output" | awk '{print $2}')
    28      is "$reported_mountpoint" "$mount_path" "mountpoint reported by 'podman mount'"
    29  
    30      # umount, and make sure files are gone
    31      run_podman umount $c_name
    32      if [[ -e "$mount_path/$f_path" ]]; then
    33          # With vfs, umount is a NOP: the path always exists as long as the
    34          # container exists. But with overlay, umount should truly remove.
    35          if [[ "$(podman_storage_driver)" != "vfs" ]]; then
    36              die "Mounted file exists even after umount: $mount_path/$f_path"
    37          fi
    38      fi
    39  
    40      # Remove the container. Now even with vfs the file must be gone.
    41      run_podman rm $c_name
    42      if [[ -e "$mount_path/$f_path" ]]; then
    43          die "Mounted file exists even after container rm: $mount_path/$f_path"
    44      fi
    45  }
    46  
    47  
    48  @test "podman image mount" {
    49      skip_if_remote "mounting remote is meaningless"
    50      skip_if_rootless "too hard to test rootless"
    51  
    52      # Start with clean slate
    53      run_podman image umount -a
    54  
    55      # Get full image ID, to verify umount
    56      run_podman image inspect --format '{{.ID}}' $IMAGE
    57      iid="$output"
    58  
    59      # Mount, and make sure the mount point exists
    60      run_podman image mount $IMAGE
    61      mount_path="$output"
    62  
    63      test -d $mount_path
    64  
    65      # Image is custom-built and has a file containing the YMD tag. Check it.
    66      testimage_file="/home/podman/testimage-id"
    67      test -e "$mount_path$testimage_file"
    68      is $(< "$mount_path$testimage_file") "$PODMAN_TEST_IMAGE_TAG"  \
    69         "Contents of $testimage_file in image"
    70  
    71      # 'image mount', no args, tells us what's mounted
    72      run_podman image mount
    73      is "$output" "$IMAGE *$mount_path" "podman image mount with no args"
    74  
    75      # Clean up, and make sure nothing is mounted any more
    76      run_podman image umount -f $IMAGE
    77      is "$output" "$iid" "podman image umount: image ID of what was umounted"
    78  
    79      run_podman image umount $IMAGE
    80      is "$output" "" "podman image umount: does not re-umount"
    81  
    82      run_podman 125 image umount no-such-image
    83      is "$output" "Error: no-such-image: image not known" \
    84         "error message from image umount no-such-image"
    85  
    86      # Tests for mount -a. This may mount more than one image! (E.g. systemd)
    87      run_podman image mount -a
    88      is "$output" "$IMAGE .*$mount_path"
    89  
    90      run_podman image umount -a
    91      assert "$output" =~ "$iid" "Test image is unmounted"
    92  
    93      run_podman image mount
    94      is "$output" "" "podman image mount, no args, after umount"
    95  }
    96  
    97  @test "podman run --mount ro=false " {
    98      local volpath=/path/in/container
    99      local stdopts="type=volume,destination=$volpath"
   100  
   101      # Variations on a theme (not by Paganini). All of these should fail.
   102      for varopt in readonly readonly=true ro=true ro rw=false;do
   103          run_podman 1 run --rm -q --mount $stdopts,$varopt $IMAGE touch $volpath/a
   104          is "$output" "touch: $volpath/a: Read-only file system" "with $varopt"
   105      done
   106  
   107      # All of these should pass
   108      for varopt in rw rw=true ro=false readonly=false;do
   109          run_podman run --rm -q --mount $stdopts,$varopt $IMAGE touch $volpath/a
   110      done
   111  }
   112  
   113  @test "podman run --mount image" {
   114      skip_if_rootless "too hard to test rootless"
   115  
   116      # Run a container with an image mount
   117      run_podman run --rm --mount type=image,src=$IMAGE,dst=/image-mount $IMAGE diff /etc/os-release /image-mount/etc/os-release
   118  
   119      # Make sure the mount is read-only
   120      run_podman 1 run --rm --mount type=image,src=$IMAGE,dst=/image-mount $IMAGE touch /image-mount/read-only
   121      is "$output" "touch: /image-mount/read-only: Read-only file system"
   122  
   123      # Make sure that rw,readwrite work
   124      run_podman run --rm --mount type=image,src=$IMAGE,dst=/image-mount,rw=true $IMAGE touch /image-mount/readwrite
   125      run_podman run --rm --mount type=image,src=$IMAGE,dst=/image-mount,readwrite=true $IMAGE touch /image-mount/readwrite
   126  
   127      skip_if_remote "mounting remote is meaningless"
   128  
   129      # The mount should be cleaned up during container removal as no other entity mounted the image
   130      run_podman image umount $IMAGE
   131      is "$output" "" "image mount should have been cleaned up during container removal"
   132  
   133      # Now make sure that the image mount is not cleaned up during container removal when another entity mounted the image
   134      run_podman image mount $IMAGE
   135      run_podman run --rm --mount type=image,src=$IMAGE,dst=/image-mount $IMAGE diff /etc/os-release /image-mount/etc/os-release
   136  
   137      run_podman image inspect --format '{{.ID}}' $IMAGE
   138      iid="$output"
   139  
   140      run_podman image umount $IMAGE
   141      is "$output" "$iid" "podman image umount: image ID of what was umounted"
   142  
   143      run_podman image umount $IMAGE
   144      is "$output" "" "image mount should have been cleaned up via 'image umount'"
   145  
   146      # Run a container in the background (source is the ID instead of name)
   147      run_podman run -d --mount type=image,src=$iid,dst=/image-mount,readwrite=true $IMAGE sleep infinity
   148      cid="$output"
   149  
   150      # Unmount the image
   151      run_podman image umount $IMAGE
   152      is "$output" "$iid" "podman image umount: image ID of what was umounted"
   153      run_podman image umount $IMAGE
   154      is "$output" "" "image mount should have been cleaned up via 'image umount'"
   155  
   156      # Make sure that the mount in the container is unaffected
   157      run_podman exec $cid diff /etc/os-release /image-mount/etc/os-release
   158      run_podman exec $cid find /image-mount/etc/
   159  
   160      # Clean up
   161      run_podman rm -t 0 -f $cid
   162  }
   163  
   164  @test "podman run --mount image inspection" {
   165      skip_if_rootless "too hard to test rootless"
   166  
   167      # Run a container in the background
   168      run_podman run -d --mount type=image,src=$IMAGE,dst=/image-mount,rw=true $IMAGE sleep infinity
   169      cid="$output"
   170  
   171      run_podman inspect --format "{{(index .Mounts 0).Type}}" $cid
   172      is "$output" "image" "inspect data includes image mount type"
   173  
   174      run_podman inspect --format "{{(index .Mounts 0).Source}}" $cid
   175      is "$output" "$IMAGE" "inspect data includes image mount source"
   176  
   177      run_podman inspect --format "{{(index .Mounts 0).Destination}}" $cid
   178      is "$output" "/image-mount" "inspect data includes image mount source"
   179  
   180      run_podman inspect --format "{{(index .Mounts 0).RW}}" $cid
   181      is "$output" "true" "inspect data includes image mount source"
   182  
   183      run_podman rm -t 0 -f $cid
   184  }
   185  
   186  @test "podman mount containers.conf" {
   187      skip_if_remote "remote does not support CONTAINERS_CONF*"
   188  
   189      dest=/$(random_string 30)
   190      tmpfile1=$PODMAN_TMPDIR/volume-test1
   191      random1=$(random_string 30)
   192      echo $random1 > $tmpfile1
   193  
   194      tmpfile2=$PODMAN_TMPDIR/volume-test2
   195      random2=$(random_string 30)
   196      echo $random2 > $tmpfile2
   197      bogus=$(random_string 10)
   198  
   199      mountStr1=type=bind,src=$tmpfile1,destination=$dest,ro,Z
   200      mountStr2=type=bind,src=$tmpfile2,destination=$dest,ro,Z
   201      containersconf=$PODMAN_TMPDIR/containers.conf
   202      cat >$containersconf <<EOF
   203  [containers]
   204  mounts=[ "$mountStr1", ]
   205  EOF
   206      badcontainersconf=$PODMAN_TMPDIR/badcontainers.conf
   207      cat >$badcontainersconf <<EOF
   208  [containers]
   209  mounts=[ "type=$bogus,src=$tmpfile2,destination=$dest,ro", ]
   210  EOF
   211  
   212      run_podman 1 run $IMAGE cat $dest
   213      is "$output" "cat: can't open '$dest': No such file or directory" "$dest does not exist"
   214  
   215      CONTAINERS_CONF_OVERRIDE="$containersconf" run_podman run $IMAGE cat $dest
   216      is "$output" "$random1" "file should contain $random1"
   217  
   218      CONTAINERS_CONF_OVERRIDE="$containersconf" run_podman run --mount $mountStr2 $IMAGE cat $dest
   219      is "$output" "$random2" "overridden file should contain $random2"
   220  
   221      CONTAINERS_CONF_OVERRIDE="$containersconf" run_podman 125 run --mount $mountStr1 --mount $mountStr2 $IMAGE cat $dest
   222      is "$output" "Error: $dest: duplicate mount destination" "Should through duplicate destination error for $dest"
   223  
   224      CONTAINERS_CONF_OVERRIDE="$badcontainersconf" run_podman 125 run $IMAGE cat $dest
   225      is "$output" "Error: parsing containers.conf mounts: invalid filesystem type \"$bogus\"" "containers.conf should fail with bad mounts entry"
   226  
   227      run_podman rm --all --force -t 0
   228  }
   229  
   230  @test "podman mount external container - basic test" {
   231      # Only works with root (FIXME: does it work with rootless + vfs?)
   232      skip_if_rootless "mount does not work rootless"
   233      skip_if_remote "mounting remote is meaningless"
   234  
   235      # Create a container that podman does not know about
   236      external_cid=$(buildah from $IMAGE)
   237  
   238      run_podman mount $external_cid
   239      mount_path=$output
   240  
   241      # Test image will always have this file, and will always have the tag
   242      test -d $mount_path
   243      is $(< "$mount_path/home/podman/testimage-id") "$PODMAN_TEST_IMAGE_TAG"  \
   244         "Contents of well-known file in image"
   245  
   246      # Make sure that 'podman mount' (no args) returns the expected path
   247      run_podman mount --notruncate
   248  
   249      reported_mountpoint=$(echo "$output" | awk '{print $2}')
   250      is "$reported_mountpoint" "$mount_path" "mountpoint reported by 'podman mount'"
   251  
   252      # umount, and make sure mountpoint no longer exists
   253      run_podman umount $external_cid
   254      if findmnt "$mount_path" >/dev/null ; then
   255          die "'podman umount' did not umount $mount_path"
   256      fi
   257      buildah rm $external_cid
   258  }
   259  
   260  @test "podman volume globs" {
   261      v1a=v1_$(random_string)
   262      v1b=v1_$(random_string)
   263      v2=v2_$(random_string)
   264      vol1a=${PODMAN_TMPDIR}/$v1a
   265      vol1b=${PODMAN_TMPDIR}/$v1b
   266      vol2=${PODMAN_TMPDIR}/$v2
   267      touch $vol1a $vol1b $vol2
   268  
   269      # if volumes source and dest match then pass
   270      run_podman run --rm --mount type=glob,src=${PODMAN_TMPDIR}/v1\*,ro $IMAGE ls $vol1a $vol1b
   271      run_podman 1 run --rm --mount source=${PODMAN_TMPDIR}/v1\*,type=glob,ro $IMAGE ls $vol2
   272      is "$output" ".*No such file or directory" "$vol2 should not be mounted in the container"
   273  
   274      run_podman 125 run --rm --mount source=${PODMAN_TMPDIR}/v3\*,type=glob,ro $IMAGE ls $vol2
   275      is "$output" "Error: no file paths matching glob \"${PODMAN_TMPDIR}/v3\*\"" "Glob does not match so should throw error"
   276  
   277      run_podman 1 run --rm --mount source=${PODMAN_TMPDIR}/v2\*,type=glob,ro,Z $IMAGE touch $vol2
   278      is "$output" "touch: $vol2: Read-only file system" "Mount should be read-only"
   279  
   280      run_podman run --rm --mount source=${PODMAN_TMPDIR}/v2\*,type=glob,ro=false,Z $IMAGE touch $vol2
   281  
   282      run_podman run --rm --mount type=glob,src=${PODMAN_TMPDIR}/v1\*,destination=/non/existing/directory,ro $IMAGE ls /non/existing/directory
   283      is "$output" ".*$v1a" "podman images --inspect should include $v1a"
   284      is "$output" ".*$v1b" "podman images --inspect should include $v1b"
   285  
   286      run_podman create --rm --mount type=glob,src=${PODMAN_TMPDIR}/v1\*,ro $IMAGE ls $vol1a $vol1b
   287      cid=$output
   288      run_podman container inspect $output
   289      is "$output" ".*$vol1a" "podman images --inspect should include $vol1a"
   290      is "$output" ".*$vol1b" "podman images --inspect should include $vol1b"
   291  
   292      run_podman 125 run --rm --mount type=bind,source=${PODMAN_TMPDIR}/v2\*,ro=false $IMAGE touch $vol2
   293      is "$output" "Error: must set volume destination" "Bind mounts require destination"
   294  
   295      run_podman 125 run --rm --mount type=bind,source=${PODMAN_TMPDIR}/v2\*,destination=/tmp/foobar,ro=false $IMAGE touch $vol2
   296      is "$output" "Error: statfs ${PODMAN_TMPDIR}/v2*: no such file or directory" "Bind mount should not interpret glob and must use as is"
   297  
   298      mkdir $PODMAN_TMPDIR/foo1 $PODMAN_TMPDIR/foo2 $PODMAN_TMPDIR/foo3
   299      touch $PODMAN_TMPDIR/foo1/bar $PODMAN_TMPDIR/foo2/bar $PODMAN_TMPDIR/foo3/bar
   300      touch $PODMAN_TMPDIR/foo1/bar1 $PODMAN_TMPDIR/foo2/bar2 $PODMAN_TMPDIR/foo3/bar3
   301      run_podman 125 run --rm --mount type=glob,source=${PODMAN_TMPDIR}/foo?/bar,destination=/tmp $IMAGE ls -l /tmp
   302      is "$output" "Error: /tmp/bar: duplicate mount destination" "Should report conflict on destination directory"
   303      run_podman run --rm --mount type=glob,source=${PODMAN_TMPDIR}/foo?/bar?,destination=/tmp,ro $IMAGE ls /tmp
   304      is "$output" "bar1.*bar2.*bar3" "Should match multiple source files on single destination directory"
   305  }
   306  
   307  @test "podman mount noswap memory mounts" {
   308      # tmpfs+noswap new in kernel 6.x, mid-2023; likely not in RHEL for a while
   309      if ! is_rootless; then
   310          testmount=$PODMAN_TMPDIR/testmount
   311          mkdir $testmount
   312          run mount -t tmpfs -o noswap none $testmount
   313          if [[ $status -ne 0 ]]; then
   314              if [[ $output =~ "bad option" ]]; then
   315                  skip "requires kernel with tmpfs + noswap support"
   316              fi
   317              die "Could not test for tmpfs + noswap support: $output"
   318          else
   319              umount $testmount
   320          fi
   321      fi
   322  
   323      # if volumes source and dest match then pass
   324      run_podman run --rm --mount type=ramfs,destination=${PODMAN_TMPDIR} $IMAGE stat -f -c "%T" ${PODMAN_TMPDIR}
   325      is "$output" "ramfs" "ramfs mounted"
   326  
   327      if is_rootless; then
   328          run_podman 125 run --rm --mount type=tmpfs,destination=${PODMAN_TMPDIR},noswap  $IMAGE stat -f -c "%T" ${PODMAN_TMPDIR}
   329          is "$output" "Error: the 'noswap' option is only allowed with rootful tmpfs mounts: must provide an argument for option" "noswap not supported in rootless mode"
   330      else
   331          run_podman run --rm --mount type=tmpfs,destination=${PODMAN_TMPDIR},noswap  $IMAGE sh -c "mount| grep ${PODMAN_TMPDIR}"
   332          is "$output" ".*noswap" "tmpfs noswap mounted"
   333      fi
   334  }
   335  
   336  @test "podman mount no-dereference" {
   337      # Test how bind and glob-mounts behave with respect to relative (rel) and
   338      # absolute (abs) symlinks.
   339  
   340      if [ $(podman_runtime) != "crun" ]; then
   341          # Requires crun >= 1.11.0
   342          skip "only crun supports the no-dereference (copy-symlink) mount option"
   343      fi
   344  
   345      # Contents of the file 'data' inside the container image.
   346      declare -A datacontent=(
   347          [img]="data file inside the IMAGE - $(random_string 15)"
   348      )
   349  
   350      # Purpose of the image is so "link -> data" can point to an existing
   351      # file whether or not "data" is mounted.
   352      dockerfile=$PODMAN_TMPDIR/Dockerfile
   353      cat >$dockerfile <<EOF
   354  FROM $IMAGE
   355  RUN mkdir /mountroot && echo ${datacontent[img]} > /mountroot/data
   356  EOF
   357  
   358      img="localhost/preserve:symlinks"
   359      run_podman build -t $img -f $dockerfile
   360  
   361      # Each test is set up in exactly the same way:
   362      #
   363      #    <tmpdir>/
   364      #    ├── mountdir/     <----- this is always the source dir
   365      #    │   ├── data
   366      #    │   └── link -> ?????
   367      #    └── otherdir/
   368      #        └── data
   369      #
   370      # The test is run in a container that has its own /mountroot/data file,
   371      # so in some situations 'link -> data' will get the container's
   372      # data file, in others it'll be the host's, and in others, ENOENT.
   373      #
   374      # There are four options for 'link': -> data in mountdir (same dir)
   375      # or otherdir, and, relative or absolute. Then, for each of those
   376      # permutations, run with and without no-dereference. (With no-dereference,
   377      # only the first of these options is valid, link->data. The other three
   378      # appear in the container as link->path-not-in-container)
   379      #
   380      # Finally, the table below defines a number of variations of mount
   381      # type (bind, glob); mount source (just the link, a glob, or entire
   382      # directory); and mount destination. These are the variations that
   383      # introduce complexity, hence the special cases in the innermost loop.
   384      #
   385      # Table format:
   386      #
   387      #    mount type | mount source | mount destination | what_is_data | enoents
   388      #
   389      # The what_is_data column indicates whether the file "data" in the
   390      # container will be the image's copy ("img") or the one from the host
   391      # ("in", referring to the source directory). "-" means N/A, no data file.
   392      #
   393      # The enoent column is a space-separated list of patterns to search for
   394      # in the test description. When these match, "link" will point to a
   395      # path that does not exist in the directory, and we should expect cat
   396      # to result in ENOENT.
   397      #
   398      tests="
   399  bind | /link | /mountroot/link       | img
   400  bind | /link | /i/do/not/exist/link  | -    | relative.*no-dereference
   401  bind | /     | /mountroot/           | in   | absolute out
   402  glob | /lin* | /mountroot/           | img
   403  glob | /*    | /mountroot/           | in
   404  "
   405  
   406      defer-assertion-failures
   407  
   408      while read mount_type mount_source mount_dest what_is_data enoents; do
   409          # link pointing inside the same directory, or outside
   410          for in_out in "in" "out"; do
   411              # relative symlink or absolute
   412              for rel_abs in "relative" "absolute"; do
   413                  # Generate fresh new content for each data file (the in & out ones)
   414                  datacontent[in]="data file in the SAME DIRECTORY - $(random_string 15)"
   415                  datacontent[out]="data file OUTSIDE the tree - $(random_string 15)"
   416  
   417                  # Populate data files in and out our tree
   418                  local condition="${rel_abs:0:3}-${in_out}"
   419                  local sourcedir="$PODMAN_TMPDIR/$condition"
   420                  rm -rf $sourcedir $PODMAN_TMPDIR/outside-the-tree
   421                  mkdir  $sourcedir $PODMAN_TMPDIR/outside-the-tree
   422                  echo "${datacontent[in]}"  > "$sourcedir/data"
   423                  echo "${datacontent[out]}" > "$PODMAN_TMPDIR/outside-the-tree/data"
   424  
   425                  # Create the symlink itself (in the in-dir of course)
   426                  local target
   427                  case "$condition" in
   428                      rel-in)  target="data" ;;
   429                      rel-out) target="../outside-the-tree/data" ;;
   430                      abs-in)  target="$sourcedir/data" ;;
   431                      abs-out) target="$PODMAN_TMPDIR/outside-the-tree/data" ;;
   432                      *)       die "Internal error, invalid condition '$condition'" ;;
   433                  esac
   434                  ln -s $target "$sourcedir/link"
   435  
   436                  # Absolute path to 'link' inside the container. What we stat & cat.
   437                  local containerpath="$mount_dest"
   438                  if [[ ! $containerpath =~ /link$ ]]; then
   439                      containerpath="${containerpath}link"
   440                  fi
   441  
   442                  # Now test with no args (mounts link CONTENT) and --no-dereference
   443                  # (mounts symlink AS A SYMLINK)
   444                  for mount_opts in "" ",no-dereference"; do
   445                      local description="$mount_type mount $mount_source -> $mount_dest ($in_out), $rel_abs $mount_opts"
   446  
   447                      # Expected exit status. Almost always success.
   448                      local exit_code=0
   449  
   450                      # Without --no-dereference, we always expect exactly the same,
   451                      # because podman mounts "link" as a data file...
   452                      local expect_stat="$containerpath"
   453                      local expect_cat="${datacontent[$in_out]}"
   454                      # ...except when bind-mounting link's parent directory: "link"
   455                      # is mounted as a link, and host's "data" file overrides the image
   456                      if [[ $mount_source = '/' ]]; then
   457                          expect_stat="'$containerpath' -> '$target'"
   458                      fi
   459  
   460                      # With --no-dereference...
   461                      if [[ -n "$mount_opts" ]]; then
   462                          # stat() is always the same (symlink and its target)  ....
   463                          expect_stat="'$containerpath' -> '$target'"
   464  
   465                          # ...and the only valid case for cat is same-dir relative:
   466                          if [[ "$condition" = "rel-in" ]]; then
   467                              expect_cat="${datacontent[$what_is_data]}"
   468                          else
   469                              # All others are ENOENT, because link -> nonexistent-path
   470                              exit_code=1
   471                          fi
   472                      fi
   473  
   474                      for ex in $enoents; do
   475                          if grep -q -w -E "$ex" <<<"$description"; then
   476                              exit_code=1
   477                          fi
   478                      done
   479                      if [[ $exit_code -eq 1 ]]; then
   480                          expect_cat="cat: can't open '$containerpath': No such file or directory"
   481                      fi
   482  
   483                      run_podman $exit_code run \
   484                                 --mount type=$mount_type,src="$sourcedir$mount_source",dst="$mount_dest$mount_opts" \
   485                                 --rm --privileged $img sh -c "stat -c '%N' $containerpath; cat $containerpath"
   486                      assert "${lines[0]}" = "$expect_stat" "$description -- stat $containerpath"
   487                      assert "${lines[1]}" = "$expect_cat"  "$description -- cat $containerpath"
   488                  done
   489              done
   490          done
   491      done < <(parse_table "$tests")
   492  
   493      immediate-assertion-failures
   494  
   495      # Make sure that links are preserved across starts and stops
   496      local workdir=$PODMAN_TMPDIR/test-restart
   497      mkdir $workdir
   498      local datafile="data-$(random_string 5)"
   499      local datafile_contents="What we expect to see, $(random_string 20)"
   500      echo "$datafile_contents" > $workdir/$datafile
   501      ln -s $datafile $workdir/link
   502  
   503      run_podman create --mount type=glob,src=$workdir/*,dst=/mountroot/,no-dereference --privileged $img sh -c "stat -c '%N' /mountroot/link; cat /mountroot/link"
   504      cid="$output"
   505      run_podman start -a $cid
   506      assert "${lines[0]}" = "'/mountroot/link' -> '$datafile'" "symlink is preserved, on start"
   507      assert "${lines[1]}" = "$datafile_contents"         "glob matches symlink and host 'data' file, on start"
   508      run_podman start -a $cid
   509      assert "${lines[0]}" = "'/mountroot/link' -> '$datafile'" "symlink is preserved, on restart"
   510      assert "${lines[1]}" = "$datafile_contents"         "glob matches symlink and host 'data' file, on restart"
   511      run_podman rm -f -t=0 $cid
   512  
   513      run_podman rmi -f $img
   514  }