コード例 #1
0
 def exec_in_container(
     self,
     container_name_or_id: str,
     command: Union[List[str], str],
     interactive=False,
     detach=False,
     env_vars: Optional[Dict[str, Optional[str]]] = None,
     stdin: Optional[bytes] = None,
     user: Optional[str] = None,
     workdir: Optional[str] = None,
 ) -> Tuple[bytes, bytes]:
     LOG.debug("Executing command in container %s: %s",
               container_name_or_id, command)
     try:
         container: Container = self.client().containers.get(
             container_name_or_id)
         result = container.exec_run(
             cmd=command,
             environment=env_vars,
             user=user,
             detach=detach,
             stdin=interactive and bool(stdin),
             socket=interactive and bool(stdin),
             stdout=True,
             stderr=True,
             demux=True,
             workdir=workdir,
         )
         tty = False
         if interactive and stdin:  # result is a socket
             sock = result[1]
             sock = sock._sock if hasattr(sock, "_sock") else sock
             with sock:
                 try:
                     sock.sendall(stdin)
                     sock.shutdown(socket.SHUT_WR)
                     stdout, stderr = self._read_from_sock(sock, tty)
                     return stdout, stderr
                 except socket.timeout:
                     pass
         else:
             if detach:
                 return b"", b""
             return_code = result[0]
             if isinstance(result[1], bytes):
                 stdout = result[1]
                 stderr = b""
             else:
                 stdout, stderr = result[1]
             if return_code != 0:
                 raise ContainerException(
                     "Exec command returned with exit code %s" %
                     return_code, stdout, stderr)
             return stdout, stderr
     except ContainerError:
         raise NoSuchContainer(container_name_or_id)
     except APIError:
         raise ContainerException()
コード例 #2
0
 def inspect_network(self, network_name: str) -> Dict[str, Union[Dict, str]]:
     try:
         return self.client().networks.get(network_name).attrs
     except NotFound:
         raise NoSuchNetwork(network_name)
     except APIError as e:
         raise ContainerException() from e
コード例 #3
0
 def connect_container_to_network(self,
                                  network_name: str,
                                  container_name_or_id: str,
                                  aliases: Optional[List] = None) -> None:
     LOG.debug(
         "Connecting container '%s' to network '%s' with aliases '%s'",
         container_name_or_id,
         network_name,
         aliases,
     )
     cmd = self._docker_cmd()
     cmd += ["network", "connect"]
     if aliases:
         cmd += ["--alias", ",".join(aliases)]
     cmd += [network_name, container_name_or_id]
     try:
         run(cmd)
     except subprocess.CalledProcessError as e:
         stdout_str = to_str(e.stdout)
         if re.match(r".*network (.*) not found.*", stdout_str):
             raise NoSuchNetwork(network_name=network_name)
         elif "No such container" in stdout_str:
             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)
コード例 #4
0
 def inspect_container(self, container_name_or_id: str) -> Dict[str, Union[Dict, str]]:
     try:
         return self.client().containers.get(container_name_or_id).attrs
     except NotFound:
         raise NoSuchContainer(container_name_or_id)
     except APIError as e:
         raise ContainerException() from e
コード例 #5
0
 def list_containers(self, filter: Union[List[str], str, None] = None, all=True) -> List[dict]:
     filter = [filter] if isinstance(filter, str) else filter
     cmd = self._docker_cmd()
     cmd.append("ps")
     if all:
         cmd.append("-a")
     options = []
     if filter:
         options += [y for filter_item in filter for y in ["--filter", filter_item]]
     cmd += options
     cmd.append("--format")
     cmd.append("{{json . }}")
     try:
         cmd_result = 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()]
     result = []
     for container in container_list:
         result.append(
             {
                 "id": container["ID"],
                 "image": container["Image"],
                 "name": container["Names"],
                 "status": container["State"],
                 "labels": container["Labels"],
             }
         )
     return result
コード例 #6
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": self.default_run_outfile or subprocess.PIPE,
     }
     if stdin:
         kwargs["stdin"] = True
     try:
         process = 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 = to_str(e.stderr)
         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
         )
コード例 #7
0
 def list_containers(self,
                     filter: Union[List[str], str, None] = None,
                     all=True) -> List[dict]:
     if filter:
         filter = [filter] if isinstance(filter, str) else filter
         filter = dict([f.split("=", 1) for f in filter])
     LOG.debug("Listing containers with filters: %s", filter)
     try:
         container_list = self.client().containers.list(filters=filter,
                                                        all=all)
         result = []
         for container in container_list:
             try:
                 result.append({
                     "id": container.id,
                     "image": container.image,
                     "name": container.name,
                     "status": container.status,
                     "labels": container.labels,
                 })
             except Exception as e:
                 LOG.error(f"Error checking container {container}: {e}")
         return result
     except APIError:
         raise ContainerException()
コード例 #8
0
 def push_image(self, docker_image: str) -> None:
     LOG.debug("Pushing Docker image: %s", docker_image)
     try:
         result = self.client().images.push(docker_image)
         # some SDK clients (e.g., 5.0.0) seem to return an error string, instead of raising
         if isinstance(result, (str, bytes)) and '"errorDetail"' in to_str(result):
             if "image does not exist locally" in to_str(result):
                 raise NoSuchImage(docker_image)
             if "is denied" in to_str(result):
                 raise AccessDenied(docker_image)
             if "connection refused" in to_str(result):
                 raise RegistryConnectionError(result)
             raise ContainerException(result)
     except ImageNotFound:
         raise NoSuchImage(docker_image)
     except APIError as e:
         raise ContainerException() from e
コード例 #9
0
 def stream_container_logs(self, container_name_or_id: str) -> CancellableStream:
     try:
         container = self.client().containers.get(container_name_or_id)
         return container.logs(stream=True, follow=True)
     except NotFound:
         raise NoSuchContainer(container_name_or_id)
     except APIError as e:
         raise ContainerException() from e
コード例 #10
0
 def tag_image(self, source_ref: str, target_name: str) -> None:
     try:
         LOG.debug("Tagging Docker image '%s' as '%s'", source_ref, target_name)
         image = self.client().images.get(source_ref)
         image.tag(target_name)
     except APIError as e:
         if e.status_code == 404:
             raise NoSuchImage(source_ref)
         raise ContainerException("Unable to tag Docker image") from e
コード例 #11
0
 def pull_image(self, docker_image: str) -> None:
     LOG.debug("Pulling Docker image: %s", docker_image)
     # some path in the docker image string indicates a custom repository
     try:
         self.client().images.pull(docker_image)
     except ImageNotFound:
         raise NoSuchImage(docker_image)
     except APIError as e:
         raise ContainerException() from e
コード例 #12
0
 def remove_image(self, image: str, force: bool = True):
     LOG.debug("Removing image %s %s", image, "(forced)" if force else "")
     try:
         self.client().images.remove(image=image, force=force)
     except ImageNotFound:
         if not force:
             raise NoSuchImage(image)
     except APIError as e:
         raise ContainerException() from e
コード例 #13
0
 def unpause_container(self, container_name: str) -> None:
     LOG.debug("Unpausing container: %s", container_name)
     try:
         container = self.client().containers.get(container_name)
         container.unpause()
     except NotFound:
         raise NoSuchContainer(container_name)
     except APIError as e:
         raise ContainerException() from e
コード例 #14
0
 def inspect_image(self, image_name: str, pull: bool = True) -> Dict[str, Union[Dict, str]]:
     try:
         return self.client().images.get(image_name).attrs
     except NotFound:
         if pull:
             self.pull_image(image_name)
             return self.inspect_image(image_name, pull=False)
         raise NoSuchImage(image_name)
     except APIError as e:
         raise ContainerException() from e
コード例 #15
0
 def get_docker_image_names(self, strip_latest=True, include_tags=True):
     try:
         images = self.client().images.list()
         image_names = [tag for image in images for tag in image.tags if image.tags]
         if not include_tags:
             image_names = list(map(lambda image_name: image_name.split(":")[0], image_names))
         if strip_latest:
             Util.append_without_latest(image_names)
         return image_names
     except APIError as e:
         raise ContainerException() from e
コード例 #16
0
 def stop_container(self, container_name: str, timeout: int = None) -> None:
     if timeout is None:
         timeout = self.STOP_TIMEOUT
     LOG.debug("Stopping container: %s", container_name)
     try:
         container = self.client().containers.get(container_name)
         container.stop(timeout=timeout)
     except NotFound:
         raise NoSuchContainer(container_name)
     except APIError as e:
         raise ContainerException() from e
コード例 #17
0
 def wait_for_result(*_):
     _exit_code = -1
     try:
         thread_started.set()
         start_waiting.wait()
         _exit_code = container.wait()["StatusCode"]
     except APIError as e:
         _exit_code = 1
         raise ContainerException(str(e))
     finally:
         result_queue.put(_exit_code)
コード例 #18
0
 def get_container_logs(self, container_name_or_id: str, safe=False) -> str:
     try:
         container = self.client().containers.get(container_name_or_id)
         return to_str(container.logs())
     except NotFound:
         if safe:
             return ""
         raise NoSuchContainer(container_name_or_id)
     except APIError as e:
         if safe:
             return ""
         raise ContainerException() from e
コード例 #19
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:
         run(cmd)
     except subprocess.CalledProcessError as e:
         if "pull access denied" in to_str(e.stdout):
             raise NoSuchImage(docker_image)
         raise ContainerException(
             "Docker process returned with errorcode %s" % e.returncode,
             e.stdout, e.stderr)
コード例 #20
0
 def tag_image(self, source_ref: str, target_name: str) -> None:
     cmd = self._docker_cmd()
     cmd += ["tag", source_ref, target_name]
     LOG.debug("Tagging Docker image %s as %s", source_ref, target_name)
     try:
         run(cmd)
     except subprocess.CalledProcessError as e:
         if "No such image" in to_str(e.stdout):
             raise NoSuchImage(source_ref)
         raise ContainerException(
             f"Docker process returned with error code {e.returncode}",
             e.stdout, e.stderr) from e
コード例 #21
0
 def build_image(self, dockerfile_path: str, image_name: str, context_path: str = None):
     cmd = self._docker_cmd()
     dockerfile_path = Util.resolve_dockerfile_path(dockerfile_path)
     context_path = context_path or os.path.dirname(dockerfile_path)
     cmd += ["build", "-t", image_name, "-f", dockerfile_path, context_path]
     LOG.debug("Building Docker image: %s", cmd)
     try:
         run(cmd)
     except subprocess.CalledProcessError as e:
         raise ContainerException(
             f"Docker build process returned with error code {e.returncode}", e.stdout, e.stderr
         ) from e
コード例 #22
0
 def copy_from_container(self, container_name: str, local_path: str,
                         container_path: str) -> None:
     cmd = self._docker_cmd()
     cmd += ["cp", f"{container_name}:{container_path}", local_path]
     LOG.debug("Copying from container with cmd: %s", cmd)
     try:
         run(cmd)
     except subprocess.CalledProcessError as e:
         if "No such container" in to_str(e.stdout):
             raise NoSuchContainer(container_name)
         raise ContainerException(
             "Docker process returned with errorcode %s" % e.returncode,
             e.stdout, e.stderr)
コード例 #23
0
 def unpause_container(self, container_name: str) -> None:
     cmd = self._docker_cmd()
     cmd += ["unpause", container_name]
     LOG.debug("Unpausing container with cmd %s", cmd)
     try:
         run(cmd)
     except subprocess.CalledProcessError as e:
         if "No such container" in to_str(e.stdout):
             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
             )
コード例 #24
0
 def remove_container(self, container_name: str, force=True, check_existence=False) -> None:
     LOG.debug("Removing container: %s", container_name)
     if check_existence and container_name not in self.get_running_container_names():
         LOG.debug("Aborting removing due to check_existence check")
         return
     try:
         container = self.client().containers.get(container_name)
         container.remove(force=force)
     except NotFound:
         if not force:
             raise NoSuchContainer(container_name)
     except APIError as e:
         raise ContainerException() from e
コード例 #25
0
 def build_image(self, dockerfile_path: str, image_name: str, context_path: str = None):
     try:
         dockerfile_path = Util.resolve_dockerfile_path(dockerfile_path)
         context_path = context_path or os.path.dirname(dockerfile_path)
         LOG.debug("Building Docker image %s from %s", image_name, dockerfile_path)
         self.client().images.build(
             path=context_path,
             dockerfile=dockerfile_path,
             tag=image_name,
             rm=True,
         )
     except APIError as e:
         raise ContainerException("Unable to build Docker image") from e
コード例 #26
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 run(cmd)
     except subprocess.CalledProcessError as e:
         if safe:
             return ""
         if "No such container" in to_str(e.stdout):
             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
             )
コード例 #27
0
 def copy_into_container(
     self, container_name: str, local_path: str, container_path: str
 ) -> None:  # TODO behave like https://docs.docker.com/engine/reference/commandline/cp/
     LOG.debug("Copying file %s into %s:%s", local_path, container_name, container_path)
     try:
         container = self.client().containers.get(container_name)
         target_exists, target_isdir = self._container_path_info(container, container_path)
         target_path = container_path if target_isdir else os.path.dirname(container_path)
         with Util.tar_path(local_path, container_path, is_dir=target_isdir) as tar:
             container.put_archive(target_path, tar)
     except NotFound:
         raise NoSuchContainer(container_name)
     except APIError as e:
         raise ContainerException() from e
コード例 #28
0
 def _inspect_object(self, object_name_or_id: str) -> Dict[str, Union[Dict, str]]:
     cmd = self._docker_cmd()
     cmd += ["inspect", "--format", "{{json .}}", object_name_or_id]
     try:
         cmd_result = run(cmd)
     except subprocess.CalledProcessError as e:
         if "No such object" in to_str(e.stdout):
             raise NoSuchObject(object_name_or_id, stdout=e.stdout, stderr=e.stderr)
         else:
             raise ContainerException(
                 "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
             )
     image_data = json.loads(cmd_result.strip())
     return image_data
コード例 #29
0
 def get_container_status(self, container_name: str) -> DockerContainerStatus:
     # LOG.debug("Getting container status for container: %s", container_name) #  too verbose
     try:
         container = self.client().containers.get(container_name)
         if container.status == "running":
             return DockerContainerStatus.UP
         elif container.status == "paused":
             return DockerContainerStatus.PAUSED
         else:
             return DockerContainerStatus.DOWN
     except NotFound:
         return DockerContainerStatus.NON_EXISTENT
     except APIError as e:
         raise ContainerException() from e
コード例 #30
0
 def remove_image(self, image: str, force: bool = True) -> None:
     cmd = self._docker_cmd()
     cmd += ["rmi", image]
     if force:
         cmd += ["--force"]
     LOG.debug("Removing image %s %s", image, "(forced)" if force else "")
     try:
         run(cmd)
     except subprocess.CalledProcessError as e:
         if "No such image" in to_str(e.stdout):
             raise NoSuchImage(image, stdout=e.stdout, stderr=e.stderr)
         else:
             raise ContainerException(
                 "Docker process returned with errorcode %s" % e.returncode,
                 e.stdout, e.stderr)