loader.py 8.7 KB

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