loader.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  1. """Utilities for the agent."""
  2. from __future__ import annotations
  3. from typing import Any
  4. import wandb
  5. from wandb.apis.internal import Api
  6. from wandb.docker import is_docker_installed
  7. from wandb.sdk.launch.errors import LaunchError
  8. from .builder.abstract import AbstractBuilder
  9. from .environment.abstract import AbstractEnvironment
  10. from .registry.abstract import AbstractRegistry
  11. from .runner.abstract import AbstractRunner
  12. WANDB_RUNNERS = {
  13. "local-container",
  14. "local-process",
  15. "kubernetes",
  16. "vertex",
  17. "sagemaker",
  18. }
  19. def environment_from_config(config: dict[str, Any] | None) -> AbstractEnvironment:
  20. """Create an environment from a config.
  21. This helper function is used to create an environment from a config. The
  22. config should have a "type" key that specifies the type of environment to
  23. create. The remaining keys are passed to the environment's from_config
  24. method. If the config is None or empty, a LocalEnvironment is returned.
  25. Arguments:
  26. config (Dict[str, Any]): The config.
  27. Returns:
  28. Environment: The environment constructed.
  29. """
  30. if not config:
  31. from .environment.local_environment import LocalEnvironment
  32. return LocalEnvironment() # This is the default, dummy environment.
  33. env_type = config.get("type")
  34. if not env_type:
  35. raise LaunchError(
  36. "Could not create environment from config. Environment type not specified!"
  37. )
  38. if env_type == "local":
  39. from .environment.local_environment import LocalEnvironment
  40. return LocalEnvironment.from_config(config)
  41. if env_type == "aws":
  42. from .environment.aws_environment import AwsEnvironment
  43. return AwsEnvironment.from_config(config)
  44. if env_type == "gcp":
  45. from .environment.gcp_environment import GcpEnvironment
  46. return GcpEnvironment.from_config(config)
  47. if env_type == "azure":
  48. from .environment.azure_environment import AzureEnvironment
  49. return AzureEnvironment.from_config(config)
  50. raise LaunchError(
  51. f"Could not create environment from config. Invalid type: {env_type}"
  52. )
  53. def registry_from_config(
  54. config: dict[str, Any] | None, environment: AbstractEnvironment
  55. ) -> AbstractRegistry:
  56. """Create a registry from a config.
  57. This helper function is used to create a registry from a config. The
  58. config should have a "type" key that specifies the type of registry to
  59. create. The remaining keys are passed to the registry's from_config
  60. method. If the config is None or empty, a LocalRegistry is returned.
  61. Arguments:
  62. config (Dict[str, Any]): The registry config.
  63. environment (Environment): The environment of the registry.
  64. Returns:
  65. The registry if config is not None, otherwise None.
  66. Raises:
  67. LaunchError: If the registry is not configured correctly.
  68. """
  69. if not config:
  70. from .registry.local_registry import LocalRegistry
  71. return LocalRegistry() # This is the default, dummy registry.
  72. wandb.termwarn(
  73. "The `registry` block of the launch agent config is being deprecated. "
  74. "Please specify an image repository URI under the `builder.destination` "
  75. "key of your launch agent config. See "
  76. "https://docs.wandb.ai/platform/launch/setup-agent-advanced#agent-configuration "
  77. "for more information."
  78. )
  79. registry_type = config.get("type")
  80. if registry_type is None or registry_type == "local":
  81. from .registry.local_registry import LocalRegistry
  82. return LocalRegistry() # This is the default, dummy registry.
  83. if registry_type == "ecr":
  84. from .registry.elastic_container_registry import ElasticContainerRegistry
  85. return ElasticContainerRegistry.from_config(config)
  86. if registry_type == "gcr":
  87. from .registry.google_artifact_registry import GoogleArtifactRegistry
  88. return GoogleArtifactRegistry.from_config(config)
  89. if registry_type == "acr":
  90. from .registry.azure_container_registry import AzureContainerRegistry
  91. return AzureContainerRegistry.from_config(config)
  92. raise LaunchError(
  93. f"Could not create registry from config. Invalid registry type: {registry_type}"
  94. )
  95. def builder_from_config(
  96. config: dict[str, Any] | None,
  97. environment: AbstractEnvironment,
  98. registry: AbstractRegistry,
  99. ) -> AbstractBuilder:
  100. """Create a builder from a config.
  101. This helper function is used to create a builder from a config. The
  102. config should have a "type" key that specifies the type of builder to import
  103. and create. The remaining keys are passed to the builder's from_config
  104. method. If the config is None or empty, a default builder is returned.
  105. The default builder will be a DockerBuilder if we find a working docker cli
  106. on the system, otherwise it will be a NoOpBuilder.
  107. Arguments:
  108. config (Dict[str, Any]): The builder config.
  109. registry (Registry): The registry of the builder.
  110. Returns:
  111. The builder.
  112. Raises:
  113. LaunchError: If the builder is not configured correctly.
  114. """
  115. if not config:
  116. if is_docker_installed():
  117. from .builder.docker_builder import DockerBuilder
  118. return DockerBuilder.from_config(
  119. {}, environment, registry
  120. ) # This is the default builder.
  121. from .builder.noop import NoOpBuilder
  122. return NoOpBuilder.from_config({}, environment, registry)
  123. builder_type = config.get("type")
  124. if builder_type is None:
  125. raise LaunchError(
  126. "Could not create builder from config. Builder type not specified"
  127. )
  128. if builder_type == "docker":
  129. from .builder.docker_builder import DockerBuilder
  130. return DockerBuilder.from_config(config, environment, registry)
  131. if builder_type == "kaniko":
  132. from .builder.kaniko_builder import KanikoBuilder
  133. return KanikoBuilder.from_config(config, environment, registry)
  134. if builder_type == "noop":
  135. from .builder.noop import NoOpBuilder
  136. return NoOpBuilder.from_config(config, environment, registry)
  137. raise LaunchError(
  138. f"Could not create builder from config. Invalid builder type: {builder_type}"
  139. )
  140. def runner_from_config(
  141. runner_name: str,
  142. api: Api,
  143. runner_config: dict[str, Any],
  144. environment: AbstractEnvironment,
  145. registry: AbstractRegistry,
  146. ) -> AbstractRunner:
  147. """Create a runner from a config.
  148. This helper function is used to create a runner from a config. The
  149. config should have a "type" key that specifies the type of runner to import
  150. and create. The remaining keys are passed to the runner's from_config
  151. method. If the config is None or empty, a LocalContainerRunner is returned.
  152. Arguments:
  153. runner_name (str): The name of the backend.
  154. api (Api): The API.
  155. runner_config (Dict[str, Any]): The backend config.
  156. Returns:
  157. The runner.
  158. Raises:
  159. LaunchError: If the runner is not configured correctly.
  160. """
  161. if not runner_name or runner_name in ["local-container", "local"]:
  162. from .runner.local_container import LocalContainerRunner
  163. return LocalContainerRunner(api, runner_config, environment, registry)
  164. if runner_name == "local-process":
  165. from .runner.local_process import LocalProcessRunner
  166. return LocalProcessRunner(api, runner_config)
  167. if runner_name == "sagemaker":
  168. from .environment.aws_environment import AwsEnvironment
  169. if not isinstance(environment, AwsEnvironment):
  170. try:
  171. environment = AwsEnvironment.from_default()
  172. except LaunchError as e:
  173. raise LaunchError(
  174. "Could not create Sagemaker runner. "
  175. "Environment must be an instance of AwsEnvironment."
  176. ) from e
  177. from .runner.sagemaker_runner import SageMakerRunner
  178. return SageMakerRunner(api, runner_config, environment, registry)
  179. if runner_name in ["vertex", "gcp-vertex"]:
  180. from .environment.gcp_environment import GcpEnvironment
  181. if not isinstance(environment, GcpEnvironment):
  182. try:
  183. environment = GcpEnvironment.from_default()
  184. except LaunchError as e:
  185. raise LaunchError(
  186. "Could not create Vertex runner. "
  187. "Environment must be an instance of GcpEnvironment."
  188. ) from e
  189. from .runner.vertex_runner import VertexRunner
  190. return VertexRunner(api, runner_config, environment, registry)
  191. if runner_name == "kubernetes":
  192. from .runner.kubernetes_runner import KubernetesRunner
  193. return KubernetesRunner(api, runner_config, environment, registry)
  194. raise LaunchError(
  195. f"Could not create runner from config. Invalid runner name: {runner_name}"
  196. )