예제 #1
0
 def test_get_container_ip_for_network(self, docker_client: ContainerClient,
                                       dummy_container, create_network):
     network_name = f"test-network-{short_uid()}"
     network_id = create_network(network_name)
     safe_run([
         "docker", "network", "connect", network_id,
         dummy_container.container_id
     ])
     docker_client.start_container(dummy_container.container_id)
     result_bridge_network = docker_client.get_container_ipv4_for_network(
         container_name_or_id=dummy_container.container_id,
         container_network="bridge").strip()
     assert is_ipv4_address(result_bridge_network)
     bridge_network = docker_client.inspect_network(
         "bridge")["IPAM"]["Config"][0]["Subnet"]
     assert ipaddress.IPv4Address(
         result_bridge_network) in ipaddress.IPv4Network(bridge_network)
     result_custom_network = docker_client.get_container_ipv4_for_network(
         container_name_or_id=dummy_container.container_id,
         container_network=network_name).strip()
     assert is_ipv4_address(result_custom_network)
     assert result_custom_network != result_bridge_network
     custom_network = docker_client.inspect_network(
         network_name)["IPAM"]["Config"][0]["Subnet"]
     assert ipaddress.IPv4Address(
         result_custom_network) in ipaddress.IPv4Network(custom_network)
예제 #2
0
 def has_docker(self) -> bool:
     """Check if system has docker available"""
     try:
         safe_run(self._docker_cmd() + ["ps"])
         return True
     except Exception:
         return False
예제 #3
0
 def test_run_container_automatic_pull(self, docker_client: ContainerClient):
     try:
         safe_run([config.DOCKER_CMD, "rmi", "alpine"])
     except CalledProcessError:
         pass
     message = "test message"
     stdout, _ = docker_client.run_container("alpine", command=["echo", message], remove=True)
     assert message == stdout.decode(config.DEFAULT_ENCODING).strip()
예제 #4
0
 def copy_into_container(
     self, container_name: str, local_path: str, container_path: str
 ) -> None:
     """Copy contents of the given local path into the container"""
     cmd = self._docker_cmd()
     cmd += ["cp", local_path, f"{container_name}:{container_path}"]
     LOG.debug("Copying into container with cmd: %s", cmd)
     safe_run(cmd)
예제 #5
0
 def test_get_container_entrypoint_not_pulled_image(
         self, docker_client: ContainerClient):
     try:
         docker_client.get_image_cmd("alpine", pull=False)
         safe_run([config.DOCKER_CMD, "rmi", "alpine"])
     except ContainerException:
         pass
     entrypoint = docker_client.get_image_entrypoint("alpine")
     assert "" == entrypoint
예제 #6
0
 def test_get_container_command_not_pulled_image(
         self, docker_client: ContainerClient):
     try:
         docker_client.get_image_cmd("alpine", pull=False)
         safe_run([config.DOCKER_CMD, "rmi", "alpine"])
     except ContainerException:
         pass
     command = docker_client.get_image_cmd("alpine")
     assert ["/bin/sh"] == command
예제 #7
0
 def test_run_container_non_existent_image(self, docker_client: ContainerClient):
     try:
         safe_run([config.DOCKER_CMD, "rmi", "alpine"])
     except CalledProcessError:
         pass
     with pytest.raises(NoSuchImage):
         stdout, _ = docker_client.run_container(
             "localstack_non_existing_image_for_tests", command=["echo", "test"], remove=True
         )
예제 #8
0
 def pull_image(self, docker_image: str) -> None:
     cmd = self._docker_cmd()
     cmd += ["pull", docker_image]
     LOG.debug("Pulling image with cmd: %s", cmd)
     try:
         safe_run(cmd)
     except subprocess.CalledProcessError as e:
         raise ContainerException(
             "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
         )
예제 #9
0
 def test_pull_docker_image(self, docker_client: ContainerClient):
     try:
         docker_client.get_image_cmd("alpine", pull=False)
         safe_run([config.DOCKER_CMD, "rmi", "alpine"])
     except ContainerException:
         pass
     with pytest.raises(NoSuchImage):
         docker_client.get_image_cmd("alpine", pull=False)
     docker_client.pull_image("alpine")
     assert ["/bin/sh"] == docker_client.get_image_cmd("alpine", pull=False)
예제 #10
0
 def test_pull_docker_image_with_tag(self, docker_client: ContainerClient):
     try:
         docker_client.get_image_cmd("alpine")
         safe_run([config.DOCKER_CMD, "rmi", "alpine"])
     except ContainerException:
         pass
     with pytest.raises(NoSuchImage):
         docker_client.get_image_cmd("alpine")
     docker_client.pull_image("alpine:3.13")
     assert "/bin/sh" == docker_client.get_image_cmd("alpine:3.13").strip()
     assert "alpine:3.13" in docker_client.inspect_image(
         "alpine:3.13")["RepoTags"]
예제 #11
0
 def test_docker_image_names(self, docker_client: ContainerClient):
     try:
         safe_run([config.DOCKER_CMD, "rmi", "alpine"])
     except CalledProcessError:
         pass
     assert "alpine:latest" not in docker_client.get_docker_image_names()
     assert "alpine" not in docker_client.get_docker_image_names()
     docker_client.pull_image("alpine")
     assert "alpine:latest" in docker_client.get_docker_image_names()
     assert "alpine:latest" not in docker_client.get_docker_image_names(include_tags=False)
     assert "alpine" in docker_client.get_docker_image_names(include_tags=False)
     assert "alpine" in docker_client.get_docker_image_names()
     assert "alpine" not in docker_client.get_docker_image_names(strip_latest=False)
예제 #12
0
 def stop_container(self, container_name: str) -> None:
     """Stops container with given name"""
     cmd = self._docker_cmd()
     cmd += ["stop", "-t0", container_name]
     LOG.debug("Stopping container with cmd %s", cmd)
     try:
         safe_run(cmd)
     except subprocess.CalledProcessError as e:
         if "No such container" in e.stdout.decode(config.DEFAULT_ENCODING):
             raise NoSuchContainer(container_name, stdout=e.stdout, stderr=e.stderr)
         else:
             raise ContainerException(
                 "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
             )
예제 #13
0
 def test_get_network_multiple_networks(self,
                                        docker_client: ContainerClient,
                                        dummy_container, create_network):
     network_name = f"test-network-{short_uid()}"
     network_id = create_network(network_name)
     safe_run([
         "docker", "network", "connect", network_id,
         dummy_container.container_id
     ])
     docker_client.start_container(dummy_container.container_id)
     networks = docker_client.get_networks(dummy_container.container_id)
     assert network_name in networks
     assert "bridge" in networks
     assert len(networks) == 2
예제 #14
0
    def list_containers(self, filter: Union[List[str], str, None] = None) -> List[dict]:
        """List all containers matching the given filters

        Returns a list of dicts with keys id, image, name, labels, status
        """
        filter = [filter] if isinstance(filter, str) else filter
        cmd = self._docker_cmd()
        cmd += ["ps", "-a"]
        options = []
        if filter:
            options += [y for filter_item in filter for y in ["--filter", filter_item]]
        cmd += options
        cmd.append("--format")
        cmd.append(
            '{"id":"{{ .ID }}","image":"{{ .Image }}","name":"{{ .Names }}",'
            '"labels":"{{ .Labels }}","status":"{{ .State }}"}'
        )
        try:
            cmd_result = safe_run(cmd).strip()
        except subprocess.CalledProcessError as e:
            raise ContainerException(
                "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
            )
        container_list = []
        if cmd_result:
            container_list = [json.loads(line) for line in cmd_result.splitlines()]
        return container_list
예제 #15
0
 def _run_async_cmd(
     self, cmd: List[str], stdin: bytes, container_name: str, image_name=None
 ) -> Tuple[bytes, bytes]:
     kwargs = {
         "inherit_env": True,
         "asynchronous": True,
         "stderr": subprocess.PIPE,
         "outfile": subprocess.PIPE,
     }
     if stdin:
         kwargs["stdin"] = True
     try:
         process = safe_run(cmd, **kwargs)
         stdout, stderr = process.communicate(input=stdin)
         if process.returncode != 0:
             raise subprocess.CalledProcessError(
                 process.returncode,
                 cmd,
                 stdout,
                 stderr,
             )
         else:
             return stdout, stderr
     except subprocess.CalledProcessError as e:
         stderr_str = e.stderr.decode(config.DEFAULT_ENCODING)
         if "Unable to find image" in stderr_str:
             raise NoSuchImage(image_name or "", stdout=e.stdout, stderr=e.stderr)
         if "No such container" in stderr_str:
             raise NoSuchContainer(container_name, stdout=e.stdout, stderr=e.stderr)
         raise ContainerException(
             "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
         )
예제 #16
0
 def remove_container(self, container_name: str, force=True) -> None:
     """Removes container with given name"""
     cmd = self._docker_cmd() + ["rm"]
     if force:
         cmd.append("-f")
     cmd.append(container_name)
     LOG.debug("Removing container with cmd %s", cmd)
     try:
         safe_run(cmd)
     except subprocess.CalledProcessError as e:
         if "No such container" in e.stdout.decode(config.DEFAULT_ENCODING):
             raise NoSuchContainer(container_name, stdout=e.stdout, stderr=e.stderr)
         else:
             raise ContainerException(
                 "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
             )
예제 #17
0
 def test_pull_docker_image_with_hash(self, docker_client: ContainerClient):
     try:
         docker_client.get_image_cmd("alpine")
         safe_run([config.DOCKER_CMD, "rmi", "alpine"])
     except ContainerException:
         pass
     with pytest.raises(NoSuchImage):
         docker_client.get_image_cmd("alpine")
     docker_client.pull_image(
         "alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a"
     )
     assert ("/bin/sh" == docker_client.get_image_cmd(
         "alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a"
     ).strip())
     assert (
         "alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a"
         in docker_client.inspect_image(
             "alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a"
         )["RepoDigests"])
예제 #18
0
def create_network():
    """
    Uses the factory as fixture pattern to wrap the creation of networks as a factory that
    removes the networks after the fixture is cleaned up.
    """
    networks = list()

    def _create_network(network_name: str):
        network_id = safe_run([config.DOCKER_CMD, "network", "create", network_name]).strip()
        networks.append(network_id)
        return network_id

    yield _create_network

    for network in networks:
        try:
            LOG.debug("Removing network %s", network)
            safe_run([config.DOCKER_CMD, "network", "remove", network])
        except CalledProcessError:
            pass
예제 #19
0
 def get_container_logs(self, container_name_or_id: str, safe=False) -> str:
     cmd = self._docker_cmd()
     cmd += ["logs", container_name_or_id]
     try:
         return safe_run(cmd)
     except subprocess.CalledProcessError as e:
         if not safe:
             return ""
         if "No such container" in e.stdout.decode(config.DEFAULT_ENCODING):
             raise NoSuchContainer(container_name_or_id, stdout=e.stdout, stderr=e.stderr)
         else:
             raise ContainerException(
                 "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
             )
예제 #20
0
 def create_container(self, image_name: str, **kwargs) -> str:
     cmd = self._build_run_create_cmd("create", image_name, **kwargs)
     LOG.debug("Create container with cmd: %s", cmd)
     try:
         container_id = safe_run(cmd)
         # Note: strip off Docker warning messages like "DNS setting (--dns=127.0.0.1) may fail in containers"
         container_id = container_id.strip().split("\n")[-1]
         return container_id.strip()
     except subprocess.CalledProcessError as e:
         if "Unable to find image" in e.stdout.decode(config.DEFAULT_ENCODING):
             raise NoSuchImage(image_name, stdout=e.stdout, stderr=e.stderr)
         raise ContainerException(
             "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
         )
예제 #21
0
    def get_image_cmd(self, docker_image: str) -> str:
        """Get the command for the given image"""
        cmd = self._docker_cmd()
        cmd += [
            "image",
            "inspect",
            '--format="{{ .Config.Cmd }}"',
            docker_image,
        ]

        try:
            run_result = safe_run(cmd)
        except subprocess.CalledProcessError as e:
            if "No such image" in e.stdout.decode(config.DEFAULT_ENCODING):
                raise NoSuchImage(docker_image, stdout=e.stdout, stderr=e.stderr)
            else:
                raise ContainerException(
                    "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
                )

        entry_point = run_result.strip('"[]\n\r ')
        return entry_point
예제 #22
0
    def get_container_status(self, container_name: str) -> DockerContainerStatus:
        """Returns the status of the container with the given name"""
        cmd = self._docker_cmd()
        cmd += [
            "ps",
            "-a",
            "--filter",
            f"name={container_name}",
            "--format",
            "{{ .Status }} - {{ .Names }}",
        ]
        cmd_result = safe_run(cmd)

        # filter empty / invalid lines from docker ps output
        cmd_result = next((line for line in cmd_result.splitlines() if container_name in line), "")
        container_status = cmd_result.strip().lower()
        if len(container_status) == 0:
            return DockerContainerStatus.NON_EXISTENT
        elif container_status.startswith("up "):
            return DockerContainerStatus.UP
        else:
            return DockerContainerStatus.DOWN
예제 #23
0
    def get_network(self, container_name: str) -> str:
        """Returns the network mode of the container with the given name"""
        LOG.debug("Getting container network: %s", container_name)
        cmd = self._docker_cmd()
        cmd += [
            "inspect",
            container_name,
            "--format",
            "{{ .HostConfig.NetworkMode }}",
        ]

        try:
            cmd_result = safe_run(cmd)
        except subprocess.CalledProcessError as e:
            if "No such container" in e.stdout.decode(config.DEFAULT_ENCODING):
                raise NoSuchContainer(container_name, stdout=e.stdout, stderr=e.stderr)
            else:
                raise ContainerException(
                    "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
                )

        container_network = cmd_result.strip()
        return container_network
예제 #24
0
 def try_install():
     safe_run([plugin_binary, "install", "-b", plugin])
예제 #25
0
 def try_install():
     output = safe_run([plugin_binary, "install", "-b", plugin])
     LOG.debug("Plugin installation output: %s", output)
예제 #26
0
 def _create_network(network_name: str):
     network_id = safe_run(
         [config.DOCKER_CMD, "network", "create", network_name]).strip()
     networks.append(network_id)
     return network_id