Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/agent_env/artifact/artifacts/docker_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -275,12 +275,18 @@ def context_only(self) -> bool:
tag the image's build gives it."""
return bool(self.build_context_object_url) and not self.tar_gz_object_url and not names_registry(self.image_name)

def rebuilt_for(self, platform: str | None) -> bool:
"""Whether a VM sandbox of ``platform`` builds this image from its build context rather than load its tar.gz,
which is built for another platform: the image runs, though not byte for byte the one stored."""
return bool(self.tar_gz_object_url and self.build_context_object_url) and self.platform_problem(platform) is not None

def load_problem(self, *, on_this_machine: bool, platform: str | None = None) -> str | None:
"""Why a VM sandbox can't get this image, or None when it can: a tar.gz is loaded, an image with none is pulled
when its name names a registry, one that a VM ``on_this_machine`` or not reaches, and built from its build
context when it has only that; and a VM of ``platform`` runs only an image built for it."""
context when it has only that; and a VM of ``platform`` runs only an image built for it, or one it rebuilds
from the build context beside a tar.gz of another platform."""
if self.tar_gz_object_url or self.context_only:
return self.platform_problem(platform)
return None if self.rebuilt_for(platform) else self.platform_problem(platform)
if names_registry(self.image_name):
return pull_problem(self.image_name, on_this_machine=on_this_machine) or self.platform_problem(platform)
return (f"{self.id!r} v{self.version} has no tar.gz, and its image name {self.image_name!r} doesn't name a "
Expand Down
32 changes: 21 additions & 11 deletions src/agent_env/bundle/preflight.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,10 @@
themselves. One version is one of the two, so a run deploying it both ways is refused, as is one deploying it on a
provider that runs an image by name.

A gateway deploy on the local provider runs on infra envs the store may not hold yet: the gateway, the service-db its
local Postgres state runs from, and the website browser it adds for websites. The run builds those once its writes are
done (``agent_env.env.bootstrap``), so they're named here, and refused here when they can't be built.
A gateway deploy runs on infra envs the store may not hold yet: the gateway, the service-db its local Postgres state
runs from, and the website browser it adds for websites. In local stores the run builds those once its writes are done
(``agent_env.env.bootstrap``), for this machine's platform and with their build contexts, which a VM or Modal running
another platform builds them from; so they're named here, and refused here when they can't be built.
"""

from __future__ import annotations
Expand All @@ -39,7 +40,9 @@
InfraError,
default_env_id,
infra_to_build,
needs_docker,
put_command,
stores_are_local,
)
from agent_env.env.env import Env
from agent_env.env.envs._deployment import provider_or_class
Expand Down Expand Up @@ -154,11 +157,14 @@ def finish(self) -> Preflight:
self.run_problems.extend(e.problems)
contexts = self._contexts()
self._default_agent()
if self.docker_users and (reason := docker_unreachable()):
reason = docker_unreachable() if self.docker_users or infra else None
if reason and self.docker_users:
shown = ", ".join(self.docker_users[:_SHOWN_DOCKER_USERS])
more = len(self.docker_users) - _SHOWN_DOCKER_USERS
self.run_problems.append(f"the local sandbox provider runs containers for {shown}"
f"{f' and {more} more' if more > 0 else ''}, and {reason}")
elif reason: # infra the run builds for deploys elsewhere
self.run_problems.append(needs_docker(infra, reason))
problems = list(self.run_problems)
for problem, wheres in self.problems.items():
first, *others = wheres
Expand Down Expand Up @@ -191,10 +197,12 @@ def _env(self, where: str, step: DeployEnvTaskStep) -> None:
if any(link.ON_THIS_MACHINE for link in taking):
self.infra |= kinds
self.docker_users.append(where)
elif taking and stores_are_local():
self.infra |= kinds
Comment thread
greptile-apps[bot] marked this conversation as resolved.

def _gateway_elsewhere(self, env_id: str, env_provider: type, kinds: set[str], link: SandboxProvider) -> list[str]:
"""Why ``link``, a provider not on this machine, can't run env ``env_id``'s gateway deploy: its sandboxes, or
the infra envs of ``kinds`` it runs, which agent-env builds only for the local provider."""
the infra envs of ``kinds`` it runs."""
found = []
if problem := env_provider.sandbox_problem(link, websites=WEBSITE_BROWSER in kinds):
found.append(f"deploys env {env_id!r} on the {_shown(link)} sandbox provider, which {problem}; run it on a VM "
Expand Down Expand Up @@ -386,20 +394,22 @@ def _refusal(self, link: SandboxProvider, form: Accepts, image: _Image, *, vms_l
f"on a provider {builds}")

def _remote_infra(self, link: SandboxProvider, kinds: set[str]) -> list[str]:
"""Why ``link``, a provider not on this machine, can't run the infra envs of ``kinds``."""
"""Why ``link``, a provider not on this machine, can't run the infra envs of ``kinds``. One the run builds, in
local stores missing or built from other inputs, isn't checked: it's built anew, with its build context."""
built = {build.kind for build in infra_to_build(kinds)} if stores_are_local() else set()
found = []
for kind in sorted(kinds):
for kind in sorted(kinds - built):
env_id = default_env_id(kind)
try:
env = Env.get(env_id)
except NotFoundError:
found.append(f"deploys on the {_shown(link)} sandbox provider, which needs the {kind} env {env_id!r}, and "
"the store doesn't hold it; agent-env builds it only for the local sandbox provider, so put "
f"it in a store that provider can reach (`{put_command(kind)}`)")
found.append(f"deploys on the {_shown(link)} sandbox provider, which needs the {kind} env {env_id!r}, "
f"and the store doesn't hold it; agent-env builds infra envs only into local stores, so put "
f"it with `{put_command(kind)}`")
continue
artifacts = ([env.db_docker_image_artifact, env.db_web_docker_image_artifact,
env.db_mcp_docker_image_artifact] if isinstance(env, ServiceDBEnv) else [env.docker_image_artifact])
accepts = EnvironmentGatewayProvider.accepts(link, prepared=kind == GATEWAY)
accepts = EnvironmentGatewayProvider.accepts(link)
found += [refusal for image in artifacts
if (refusal := self._refusal(link, accepts, _Image(f"the {kind} env {env_id!r}'s image {image.id!r}",
image), vms_load=True))]
Expand Down
Loading
Loading