Beispiel #1
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)
Beispiel #2
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
         )
Beispiel #3
0
 def inspect_image(self, image_name: str, pull: bool = True) -> Dict[str, Union[Dict, str]]:
     try:
         return self._inspect_object(image_name)
     except NoSuchObject as e:
         if pull:
             self.pull_image(image_name)
             return self.inspect_image(image_name, pull=False)
         raise NoSuchImage(image_name=e.object_id)
Beispiel #4
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
Beispiel #5
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
Beispiel #6
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
Beispiel #7
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
Beispiel #8
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
Beispiel #9
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)
Beispiel #10
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)
Beispiel #11
0
 def push_image(self, docker_image: str) -> None:
     cmd = self._docker_cmd()
     cmd += ["push", docker_image]
     LOG.debug("Pushing image with cmd: %s", cmd)
     try:
         run(cmd)
     except subprocess.CalledProcessError as e:
         if "is denied" in to_str(e.stdout):
             raise AccessDenied(docker_image)
         if "does not exist" in to_str(e.stdout):
             raise NoSuchImage(docker_image)
         if "connection refused" in to_str(e.stdout):
             raise RegistryConnectionError(e.stdout)
         raise ContainerException(
             f"Docker process returned with errorcode {e.returncode}",
             e.stdout, e.stderr) from e
Beispiel #12
0
 def create_container(self, image_name: str, **kwargs) -> str:
     cmd, env_file = self._build_run_create_cmd("create", image_name, **kwargs)
     LOG.debug("Create container with cmd: %s", cmd)
     try:
         container_id = 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 to_str(e.stdout):
             raise NoSuchImage(image_name, stdout=e.stdout, stderr=e.stderr)
         raise ContainerException(
             "Docker process returned with errorcode %s" % e.returncode, e.stdout, e.stderr
         )
     finally:
         Util.rm_env_vars_file(env_file)
Beispiel #13
0
    def create_container(
        self,
        image_name: str,
        *,
        name: Optional[str] = None,
        entrypoint: Optional[str] = None,
        remove: bool = False,
        interactive: bool = False,
        tty: bool = False,
        detach: bool = False,
        command: Optional[Union[List[str], str]] = None,
        mount_volumes: Optional[List[SimpleVolumeBind]] = None,
        ports: Optional[PortMappings] = None,
        env_vars: Optional[Dict[str, str]] = None,
        user: Optional[str] = None,
        cap_add: Optional[List[str]] = None,
        cap_drop: Optional[List[str]] = None,
        security_opt: Optional[List[str]] = None,
        network: Optional[str] = None,
        dns: Optional[str] = None,
        additional_flags: Optional[str] = None,
        workdir: Optional[str] = None,
    ) -> str:
        LOG.debug("Creating container with attributes: %s", locals())
        extra_hosts = None
        if additional_flags:
            env_vars, ports, mount_volumes, extra_hosts, network = Util.parse_additional_flags(
                additional_flags, env_vars, ports, mount_volumes, network
            )
        try:
            kwargs = {}
            if cap_add:
                kwargs["cap_add"] = cap_add
            if cap_drop:
                kwargs["cap_drop"] = cap_drop
            if security_opt:
                kwargs["security_opt"] = security_opt
            if dns:
                kwargs["dns"] = [dns]
            if ports:
                kwargs["ports"] = ports.to_dict()
            if workdir:
                kwargs["working_dir"] = workdir
            mounts = None
            if mount_volumes:
                mounts = Util.convert_mount_list_to_dict(mount_volumes)

            def create_container():
                return self.client().containers.create(
                    image=image_name,
                    command=command,
                    auto_remove=remove,
                    name=name,
                    stdin_open=interactive,
                    tty=tty,
                    entrypoint=entrypoint,
                    environment=env_vars,
                    detach=detach,
                    user=user,
                    network=network,
                    volumes=mounts,
                    extra_hosts=extra_hosts,
                    **kwargs,
                )

            try:
                container = create_container()
            except ImageNotFound:
                self.pull_image(image_name)
                container = create_container()
            return container.id
        except ImageNotFound:
            raise NoSuchImage(image_name)
        except APIError as e:
            raise ContainerException() from e