github.com/hanks177/podman/v4@v4.1.3-0.20220613032544-16d90015bc83/test/python/docker/compat/test_containers.py (about)

     1  """
     2  Integration tests for exercising docker-py against Podman Service.
     3  """
     4  import io
     5  import tarfile
     6  from typing import IO, List, Optional
     7  
     8  from docker import errors
     9  from docker.models.containers import Container
    10  from docker.models.images import Image
    11  from docker.models.volumes import Volume
    12  from docker.types import Mount
    13  
    14  # pylint: disable=no-name-in-module,import-error,wrong-import-order
    15  from test.python.docker.compat import common, constant
    16  
    17  
    18  # pylint: disable=missing-function-docstring
    19  class TestContainers(common.DockerTestCase):
    20      """TestCase for exercising containers."""
    21  
    22      def test_create_container(self):
    23          """Run a container with detach mode."""
    24          self.docker.containers.create(image="alpine", detach=True)
    25          self.assertEqual(len(self.docker.containers.list(all=True)), 2)
    26  
    27      def test_create_network(self):
    28          """Add network to a container."""
    29          self.docker.networks.create("testNetwork", driver="bridge")
    30          self.docker.containers.create(image="alpine", detach=True)
    31  
    32      def test_start_container(self):
    33          # Podman docs says it should give a 304 but returns with no response
    34          # # Start a already started container should return 304
    35          # response = self.docker.api.start(container=self.top_container_id)
    36          # self.assertEqual(error.exception.response.status_code, 304)
    37  
    38          # Create a new container and validate the count
    39          self.docker.containers.create(image=constant.ALPINE, name="container2")
    40          containers = self.docker.containers.list(all=True)
    41          self.assertEqual(len(containers), 2)
    42  
    43      def test_start_container_with_random_port_bind(self):
    44          container = self.docker.containers.create(
    45              image=constant.ALPINE,
    46              name="containerWithRandomBind",
    47              ports={"1234/tcp": None},
    48          )
    49          containers = self.docker.containers.list(all=True)
    50          self.assertTrue(container in containers)
    51  
    52      def test_stop_container(self):
    53          top = self.docker.containers.get(self.top_container_id)
    54          self.assertEqual(top.status, "running")
    55  
    56          # Stop a running container and validate the state
    57          top.stop()
    58          top.reload()
    59          self.assertIn(top.status, ("stopped", "exited"))
    60  
    61      def test_kill_container(self):
    62          top = self.docker.containers.get(self.top_container_id)
    63          self.assertEqual(top.status, "running")
    64  
    65          # Kill a running container and validate the state
    66          top.kill()
    67          top.reload()
    68          self.assertIn(top.status, ("stopped", "exited"))
    69  
    70      def test_restart_container(self):
    71          # Validate the container state
    72          top = self.docker.containers.get(self.top_container_id)
    73          top.stop()
    74          top.reload()
    75          self.assertIn(top.status, ("stopped", "exited"))
    76  
    77          # restart a running container and validate the state
    78          top.restart()
    79          top.reload()
    80          self.assertEqual(top.status, "running")
    81  
    82      def test_remove_container(self):
    83          # Remove container by ID with force
    84          top = self.docker.containers.get(self.top_container_id)
    85          top.remove(force=True)
    86          self.assertEqual(len(self.docker.containers.list()), 0)
    87  
    88      def test_remove_container_without_force(self):
    89          # Validate current container count
    90          self.assertEqual(len(self.docker.containers.list()), 1)
    91  
    92          # Remove running container should throw error
    93          top = self.docker.containers.get(self.top_container_id)
    94          with self.assertRaises(errors.APIError) as error:
    95              top.remove()
    96          self.assertEqual(error.exception.response.status_code, 500)
    97  
    98          # Remove container by ID without force
    99          top.stop()
   100          top.remove()
   101          self.assertEqual(len(self.docker.containers.list()), 0)
   102  
   103      def test_pause_container(self):
   104          # Validate the container state
   105          top = self.docker.containers.get(self.top_container_id)
   106          self.assertEqual(top.status, "running")
   107  
   108          # Pause a running container and validate the state
   109          top.pause()
   110          top.reload()
   111          self.assertEqual(top.status, "paused")
   112  
   113      def test_pause_stopped_container(self):
   114          # Stop the container
   115          top = self.docker.containers.get(self.top_container_id)
   116          top.stop()
   117  
   118          # Pause exited container should throw error
   119          with self.assertRaises(errors.APIError) as error:
   120              top.pause()
   121          self.assertEqual(error.exception.response.status_code, 500)
   122  
   123      def test_unpause_container(self):
   124          top = self.docker.containers.get(self.top_container_id)
   125  
   126          # Validate the container state
   127          top.pause()
   128          top.reload()
   129          self.assertEqual(top.status, "paused")
   130  
   131          # Pause a running container and validate the state
   132          top.unpause()
   133          top.reload()
   134          self.assertEqual(top.status, "running")
   135  
   136      def test_list_container(self):
   137          # Add container and validate the count
   138          self.docker.containers.create(image="alpine", detach=True)
   139          containers = self.docker.containers.list(all=True)
   140          self.assertEqual(len(containers), 2)
   141  
   142      def test_filters(self):
   143          self.skipTest("TODO Endpoint does not yet support filters")
   144  
   145          # List container with filter by id
   146          filters = {"id": self.top_container_id}
   147          ctnrs = self.docker.containers.list(all=True, filters=filters)
   148          self.assertEqual(len(ctnrs), 1)
   149  
   150          # List container with filter by name
   151          filters = {"name": "top"}
   152          ctnrs = self.docker.containers.list(all=True, filters=filters)
   153          self.assertEqual(len(ctnrs), 1)
   154  
   155      def test_copy_to_container(self):
   156          ctr: Optional[Container] = None
   157          vol: Optional[Volume] = None
   158          try:
   159              test_file_content = b"Hello World!"
   160              vol = self.docker.volumes.create("test-volume")
   161              ctr = self.docker.containers.create(
   162                  image="alpine",
   163                  detach=True,
   164                  command="top",
   165                  volumes=["test-volume:/test-volume-read-only:ro"],
   166              )
   167              ctr.start()
   168  
   169              buff: IO[bytes] = io.BytesIO()
   170              with tarfile.open(fileobj=buff, mode="w:") as file:
   171                  info: tarfile.TarInfo = tarfile.TarInfo()
   172                  info.uid = 1042
   173                  info.gid = 1043
   174                  info.name = "a.txt"
   175                  info.path = "a.txt"
   176                  info.mode = 0o644
   177                  info.type = tarfile.REGTYPE
   178                  info.size = len(test_file_content)
   179                  file.addfile(info, fileobj=io.BytesIO(test_file_content))
   180  
   181              buff.seek(0)
   182              ctr.put_archive("/tmp/", buff)
   183              ret, out = ctr.exec_run(["stat", "-c", "%u:%g", "/tmp/a.txt"])
   184  
   185              self.assertEqual(ret, 0)
   186              self.assertEqual(out.rstrip(), b"1042:1043", "UID/GID of copied file")
   187  
   188              ret, out = ctr.exec_run(["cat", "/tmp/a.txt"])
   189              self.assertEqual(ret, 0)
   190              self.assertEqual(out.rstrip(), test_file_content, "Content of copied file")
   191  
   192              buff.seek(0)
   193              with self.assertRaises(errors.APIError):
   194                  ctr.put_archive("/test-volume-read-only/", buff)
   195          finally:
   196              if ctr is not None:
   197                  ctr.stop()
   198                  ctr.remove()
   199              if vol is not None:
   200                  vol.remove(force=True)
   201  
   202      def test_mount_preexisting_dir(self):
   203          dockerfile = (
   204              b"FROM quay.io/libpod/alpine:latest\n"
   205              b"USER root\n"
   206              b"RUN mkdir -p /workspace\n"
   207              b"RUN chown 1042:1043 /workspace"
   208          )
   209          img: Image
   210          img, out = self.docker.images.build(fileobj=io.BytesIO(dockerfile))
   211          ctr: Container = self.docker.containers.create(
   212              image=img.id,
   213              detach=True,
   214              command="top",
   215              volumes=["test_mount_preexisting_dir_vol:/workspace"],
   216          )
   217          ctr.start()
   218          _, out = ctr.exec_run(["stat", "-c", "%u:%g", "/workspace"])
   219          self.assertEqual(out.rstrip(), b"1042:1043", "UID/GID set in dockerfile")
   220  
   221      def test_non_existant_workdir(self):
   222          dockerfile = (
   223              b"FROM quay.io/libpod/alpine:latest\n"
   224              b"USER root\n"
   225              b"WORKDIR /workspace/scratch\n"
   226              b"RUN touch test"
   227          )
   228          img: Image
   229          img, _ = self.docker.images.build(fileobj=io.BytesIO(dockerfile))
   230          ctr: Container = self.docker.containers.create(
   231              image=img.id,
   232              detach=True,
   233              command="top",
   234              volumes=["test_non_existant_workdir:/workspace"],
   235          )
   236          ctr.start()
   237          ret, _ = ctr.exec_run(["stat", "/workspace/scratch/test"])
   238          self.assertEqual(ret, 0, "Working directory created if it doesn't exist")
   239  
   240      def test_mount_rw_by_default(self):
   241          ctr: Optional[Container] = None
   242          vol: Optional[Volume] = None
   243  
   244          try:
   245              vol = self.docker.volumes.create("test-volume")
   246              ctr = self.docker.containers.create(
   247                  image="alpine",
   248                  detach=True,
   249                  command="top",
   250                  mounts=[
   251                      Mount(target="/vol-mnt", source="test-volume", type="volume", read_only=False)
   252                  ],
   253              )
   254              ctr_inspect = self.docker.api.inspect_container(ctr.id)
   255              binds: List[str] = ctr_inspect["HostConfig"]["Binds"]
   256              self.assertEqual(len(binds), 1)
   257              self.assertEqual(binds[0], "test-volume:/vol-mnt:rw,rprivate,nosuid,nodev,rbind")
   258          finally:
   259              if ctr is not None:
   260                  ctr.remove()
   261              if vol is not None:
   262                  vol.remove(force=True)