docker.py 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. import docker
  2. from opendevin.core.logger import opendevin_logger as logger
  3. from .base import RuntimeBuilder
  4. class DockerRuntimeBuilder(RuntimeBuilder):
  5. def __init__(self, docker_client: docker.DockerClient):
  6. self.docker_client = docker_client
  7. def build(self, path: str, tags: list[str]) -> str:
  8. target_image_hash_name = tags[0]
  9. target_image_repo, target_image_hash_tag = target_image_hash_name.split(':')
  10. target_image_tag = tags[1].split(':')[1] if len(tags) > 1 else None
  11. try:
  12. build_logs = self.docker_client.api.build(
  13. path=path,
  14. tag=target_image_hash_name,
  15. rm=True,
  16. decode=True,
  17. )
  18. except docker.errors.BuildError as e:
  19. logger.error(f'Sandbox image build failed: {e}')
  20. raise RuntimeError(f'Sandbox image build failed: {e}')
  21. for log in build_logs:
  22. if 'stream' in log:
  23. print(log['stream'].strip())
  24. elif 'error' in log:
  25. logger.error(log['error'].strip())
  26. else:
  27. logger.info(str(log))
  28. logger.info(f'Image [{target_image_hash_name}] build finished.')
  29. assert (
  30. target_image_tag
  31. ), f'Expected target image tag [{target_image_tag}] is None'
  32. image = self.docker_client.images.get(target_image_hash_name)
  33. image.tag(target_image_repo, target_image_tag)
  34. logger.info(
  35. f'Re-tagged image [{target_image_hash_name}] with more generic tag [{target_image_tag}]'
  36. )
  37. # Check if the image is built successfully
  38. image = self.docker_client.images.get(target_image_hash_name)
  39. if image is None:
  40. raise RuntimeError(
  41. f'Build failed: Image {target_image_hash_name} not found'
  42. )
  43. tags_str = (
  44. f'{target_image_hash_tag}, {target_image_tag}'
  45. if target_image_tag
  46. else target_image_hash_tag
  47. )
  48. logger.info(
  49. f'Image {target_image_repo} with tags [{tags_str}] built successfully'
  50. )
  51. return target_image_hash_name
  52. def image_exists(self, image_name: str) -> bool:
  53. """Check if the image exists in the registry (try to pull it first) AND in the local store.
  54. Args:
  55. image_name (str): The Docker image to check (<image repo>:<image tag>)
  56. Returns:
  57. bool: Whether the Docker image exists in the registry and in the local store
  58. """
  59. # Try to pull the Docker image from the registry
  60. try:
  61. self.docker_client.images.pull(image_name)
  62. except Exception:
  63. logger.info(f'Cannot pull image {image_name} directly')
  64. images = self.docker_client.images.list()
  65. if images:
  66. for image in images:
  67. if image_name in image.tags:
  68. return True
  69. return False