예제 #1
0
    def run(self,
            service_instance: DockerServiceInstance,
            rm=True,
            detach=True):
        if not isinstance(service_instance, DockerServiceInstance):
            raise TypeError(
                'ServiceInstance should be of type DockerServiceInstance instead of {}'
                .format(type(service_instance)))
        with create_docker_client(
                service_instance.target_host.get_host()) as client:
            if isinstance(service_instance.docker_image.registry,
                          RemoteDockerRegistry):
                client.login(
                    registry=service_instance.docker_image.registry.host,
                    username=service_instance.docker_image.registry.username,
                    password=service_instance.docker_image.registry.password)

            import docker.errors  # FIXME
            try:
                # always detach from container and just stream logs if detach=False
                container = client.containers.run(
                    service_instance.docker_image.get_image_uri(),
                    name=service_instance.name,
                    auto_remove=rm,
                    ports=service_instance.ports_mapping,
                    detach=True)
                if not detach:
                    try:
                        # infinite loop of logs while container running or if everything ok
                        for log in self.logs(container, stream=True):
                            logger.debug(log)

                        if not self._is_service_running(
                                client, service_instance):
                            raise DockerRunnerException(
                                "The container died unexpectedly.")

                    except KeyboardInterrupt:
                        logger.info('Interrupted. Stopping the container')
                        container.stop()

                else:
                    if not self._is_service_running(client, service_instance):
                        if not rm:
                            for log in self.logs(container,
                                                 stdout=False,
                                                 stderr=True):
                                raise DockerRunnerException(
                                    "The container died unexpectedly.", log)
                        else:
                            # Can't get logs from removed container
                            raise DockerRunnerException(
                                "The container died unexpectedly. Try to run the container "
                                "with detach=False or rm=False args to get more info."
                            )
                return container
            except docker.errors.ContainerError as e:
                if e.stderr:
                    print(e.stderr.decode(), file=sys.stderr)
                raise
예제 #2
0
 def _build_image(self, context_dir):
     tag = '{}:{}'.format(self.name, self.tag)
     logger.debug('Building docker image %s from %s...', tag, context_dir)
     with create_docker_client() as client:
         if not self.force_overwrite:
             try:
                 client.images.get(tag)
                 raise ValueError(
                     f'Image {tag} already exists. Change name or set force_overwrite=True.'
                 )
             except errors.ImageNotFound:
                 pass
         else:
             try:
                 client.images.remove(
                     tag)  # to avoid spawning dangling images
             except errors.ImageNotFound:
                 pass
         try:
             _, logs = client.images.build(path=context_dir, tag=tag)
             logger.info('Build successful')
             _print_docker_logs(logs)
         except errors.BuildError as e:
             _print_docker_logs(e.build_log)
             raise
예제 #3
0
파일: docker.py 프로젝트: koskotG/ebonite
def login_to_registry(client: docker.DockerClient, registry: DockerRegistry):
    """
    Logs in to Docker registry (if it is remote).

    Corresponding credentials should be specified as environment variables per registry:
    e.g., if registry host is "168.32.25.1:5000" then
    "168_32_25_1_5000_USERNAME" and "168_32_25_1_5000_PASSWORD" variables should be specified

    :param client: Docker client instance
    :param registry: Docker registry descriptor
    :return: nothing
    """
    if isinstance(registry, RemoteDockerRegistry):
        host_for_env = registry.host.replace('.', '_').replace(':', '_')
        username_var = f'{host_for_env}_username'.upper()
        username = os.getenv(username_var)
        password_var = f'{host_for_env}_password'.upper()
        password = os.getenv(password_var)

        if username and password:
            client.login(registry=registry.host,
                         username=username,
                         password=password)
            logger.info('Logged in to remote registry at host %s',
                        registry.host)
        else:
            logger.warning(
                'Skipped logging in to remote registry at host %s because no credentials given. '
                +
                'You could specify credentials as %s and %s environment variables.',
                registry.host, username_var, password_var)
예제 #4
0
    def run(self,
            instance: DockerContainer,
            image: DockerImage,
            env: DockerEnv,
            rm=True,
            detach=True,
            **kwargs):
        if not (isinstance(instance, DockerContainer) and isinstance(
                image, DockerImage) and isinstance(env, DockerEnv)):
            raise TypeError(
                'DockerRunner works with DockerContainer, DockerImage and DockerHost only'
            )

        with env.daemon.client() as client:
            image.registry.login(client)

            try:
                # always detach from container and just stream logs if detach=False
                container = client.containers.run(image.uri,
                                                  name=instance.name,
                                                  auto_remove=rm,
                                                  ports=instance.port_mapping,
                                                  detach=True,
                                                  **instance.params,
                                                  **kwargs)
                instance.container_id = container.id
                if not detach:
                    try:
                        # infinite loop of logs while container running or if everything ok
                        for log in self._logs(container, stream=True):
                            logger.debug(log)

                        self._sleep()
                        if not self._is_service_running(client, instance.name):
                            raise DockerRunnerException(
                                "The container died unexpectedly.")

                    except KeyboardInterrupt:
                        logger.info('Interrupted. Stopping the container')
                        container.stop()

                else:
                    self._sleep(.5)
                    if not self._is_service_running(client, instance.name):
                        if not rm:
                            for log in self._logs(container,
                                                  stdout=False,
                                                  stderr=True):
                                raise DockerRunnerException(
                                    "The container died unexpectedly.", log)
                        else:
                            # Can't get logs from removed container
                            raise DockerRunnerException(
                                "The container died unexpectedly. Try to run the container "
                                "with detach=False or rm=False args to get more info."
                            )
            except docker.errors.ContainerError as e:
                if e.stderr:
                    print(e.stderr.decode(), file=sys.stderr)
                raise
예제 #5
0
    def _build_image(self, context_dir,
                     env: DockerEnv) -> docker.models.images.Image:
        tag = self.params.uri
        logger.debug('Building docker image %s from %s...', tag, context_dir)
        with env.daemon.client() as client:
            self.params.registry.login(client)

            if not self.force_overwrite:
                if self.params.exists(client):
                    raise ValueError(
                        f'Image {tag} already exists at {self.params.registry}. '
                        f'Change name or set force_overwrite=True.')

            else:
                self.params.delete(client)  # to avoid spawning dangling images
            try:
                image, logs = client.images.build(path=context_dir,
                                                  tag=tag,
                                                  rm=True)
                logger.info('Built docker image %s', tag)
                _print_docker_logs(logs)

                self.params.registry.push(client, tag)

                return image
            except errors.BuildError as e:
                _print_docker_logs(e.build_log, logging.ERROR)
                raise
예제 #6
0
파일: prebuild.py 프로젝트: zyfra/ebonite
def prebuild_image(prebuild_path,
                   name_template,
                   python_version,
                   *,
                   push=False):
    tag = name_template.format(python_version)
    if image_exists_at_dockerhub(tag):
        logger.info('Skipped building image %s: already exists', tag)
        return

    with tempfile.TemporaryDirectory() as tmpdir:
        context_dir = os.path.join(tmpdir, 'context')
        logger.info('Building image %s on %s ...', tag, context_dir)

        shutil.copytree(prebuild_path, context_dir)
        _generate_dockerfile(context_dir, python_version)

        try:
            with create_docker_client() as client:
                client.images.build(path=context_dir, tag=tag, rm=True)

            logger.info('Successfully built image %s', tag)
        except Exception as e:
            logger.error('Failed to build image %s: %s', tag, e)
            return

    if push:
        with create_docker_client() as client:
            DockerIORegistry().login(client)
            client.images.push(tag)
예제 #7
0
    def _build_image(self, context_dir):
        tag = self.params.get_uri()
        logger.debug('Building docker image %s from %s...', tag, context_dir)
        with create_docker_client() as client:
            login_to_registry(client, self.params.registry)

            if not self.force_overwrite:
                try:
                    client.images.get(tag)
                    raise ValueError(
                        f'Image {tag} already exists. Change name or set force_overwrite=True.'
                    )
                except errors.ImageNotFound:
                    pass
            else:
                try:
                    client.images.remove(
                        tag)  # to avoid spawning dangling images
                except errors.ImageNotFound:
                    pass
            try:
                _, logs = client.images.build(path=context_dir,
                                              tag=tag,
                                              rm=True)
                logger.info('Built image %s', tag)
                _print_docker_logs(logs)

                if isinstance(self.params.registry, RemoteDockerRegistry):
                    client.images.push(tag)
                    logger.info(
                        'Pushed image %s to remote registry at host %s', tag,
                        self.params.registry.host)

                return Image(tag, params=self.params)
            except errors.BuildError as e:
                _print_docker_logs(e.build_log, logging.ERROR)
                raise
예제 #8
0
 def push(self, client, tag):
     client.images.push(tag)
     logger.info('Pushed image %s to docker.io', tag)
예제 #9
0
 def push(self, client, tag):
     client.images.push(tag)
     logger.info('Pushed image %s to remote registry at host %s', tag,
                 self.host)