Skip to content
Open
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
46 changes: 30 additions & 16 deletions server/opensandbox_server/services/docker/docker_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -402,11 +402,18 @@ def _expire_sandbox(
except DockerException as exc:
logger.warning("Failed to remove expired sandbox %s: %s", sandbox_id, exc)

managed_volumes_raw = labels.get(SANDBOX_MANAGED_VOLUMES_LABEL, "[]")
try:
managed_volumes: list[str] = json.loads(managed_volumes_raw)
except (TypeError, json.JSONDecodeError):
managed_volumes = []

self._remove_expiration_tracking(sandbox_id)
# Ensure sidecar is also cleaned up on expiration
self._cleanup_egress_sidecar(sandbox_id)
self._cleanup_windows_oem_volume(sandbox_id, labels)
self._release_ossfs_mounts(mount_keys)
self._cleanup_managed_volumes(sandbox_id, managed_volumes)
self._metadata_store.delete(sandbox_id)

def _restore_existing_sandboxes(self) -> None:
Expand Down Expand Up @@ -814,21 +821,21 @@ def _provision_sandbox(
container_exposed_ports: Optional[list[str]] = exposed_ports

if request.network_policy:
if credential_proxy_enabled:
runtime_volume_name = f"opensandbox-runtime-{sandbox_id}"
with self._docker_operation(
"create credential proxy runtime volume", sandbox_id
):
self.docker_client.volumes.create(
name=runtime_volume_name,
labels={SANDBOX_MANAGED_VOLUMES_LABEL: "server"},
)
auto_created_volumes = list(auto_created_volumes or [])
auto_created_volumes.append(runtime_volume_name)
labels[SANDBOX_MANAGED_VOLUMES_LABEL] = json.dumps(
auto_created_volumes,
separators=(",", ":"),
runtime_volume_name = f"opensandbox-runtime-{sandbox_id}"
with self._docker_operation(
"create egress runtime volume", sandbox_id
):
self.docker_client.volumes.create(
name=runtime_volume_name,
labels={SANDBOX_MANAGED_VOLUMES_LABEL: "server"},
)
Comment thread
Pangjiping marked this conversation as resolved.
auto_created_volumes = list(auto_created_volumes or [])
auto_created_volumes.append(runtime_volume_name)
labels[SANDBOX_MANAGED_VOLUMES_LABEL] = json.dumps(
auto_created_volumes,
separators=(",", ":"),
)
if credential_proxy_enabled:
environment = [
entry
for entry in environment
Comment thread
Pangjiping marked this conversation as resolved.
Expand Down Expand Up @@ -891,9 +898,16 @@ def _provision_sandbox(

# Inject volume bind mounts into Docker host config
if runtime_volume_name:
volume_binds.append(
f"{runtime_volume_name}:{OPENSANDBOX_RUNTIME_MOUNT_PATH}:rw"
runtime_mount_suffix = f":{OPENSANDBOX_RUNTIME_MOUNT_PATH}:"
runtime_mount_end = f":{OPENSANDBOX_RUNTIME_MOUNT_PATH}"
has_runtime_mount = any(
runtime_mount_suffix in bind or bind.endswith(runtime_mount_end)
for bind in volume_binds
)
Comment thread
Pangjiping marked this conversation as resolved.
if not has_runtime_mount:
volume_binds.append(
f"{runtime_volume_name}:{OPENSANDBOX_RUNTIME_MOUNT_PATH}:rw"
)
if volume_binds:
host_config_kwargs["binds"] = volume_binds
if requested_windows_profile:
Expand Down
13 changes: 6 additions & 7 deletions server/opensandbox_server/services/k8s/egress_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,13 +112,12 @@ def apply_egress_to_spec(
"failureThreshold": 30,
},
}
if credential_proxy_enabled:
sidecar["volumeMounts"] = [
{
"name": OPENSANDBOX_RUNTIME_VOLUME_NAME,
"mountPath": OPENSANDBOX_RUNTIME_MOUNT_PATH,
}
]
sidecar["volumeMounts"] = [
{
"name": OPENSANDBOX_RUNTIME_VOLUME_NAME,
"mountPath": OPENSANDBOX_RUNTIME_MOUNT_PATH,
}
]
if egress_auth_token:
sidecar["readinessProbe"]["httpGet"]["httpHeaders"] = [
{"name": OPEN_SANDBOX_EGRESS_AUTH_HEADER, "value": egress_auth_token}
Expand Down
12 changes: 12 additions & 0 deletions server/tests/k8s/test_egress_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ def test_contains_egress_rules_environment_variable(self):
assert env_by_name[EGRESS_MODE_ENV] == EGRESS_MODE_DNS
assert OPENSANDBOX_EGRESS_MITMPROXY_TRANSPARENT not in env_by_name

def test_always_mounts_runtime_volume(self):
container = _egress_container(
"opensandbox/egress:v1.1.0",
NetworkPolicy(default_action="deny", egress=[]),
)
assert container["volumeMounts"] == [
{
"name": OPENSANDBOX_RUNTIME_VOLUME_NAME,
"mountPath": OPENSANDBOX_RUNTIME_MOUNT_PATH,
}
]

def test_contains_transparent_mitm_env_when_credential_proxy_enabled(self):
egress_image = "opensandbox/egress:v1.1.0"
network_policy = NetworkPolicy(
Expand Down
9 changes: 8 additions & 1 deletion server/tests/test_docker_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,14 @@ def host_cfg_side_effect(**kwargs):
assert f"{OPENSANDBOX_EGRESS_MITMPROXY_TRANSPARENT}=true" not in sidecar_env
forwarded_env = main_kwargs["environment"]
assert f"{OPENSANDBOX_EGRESS_MITMPROXY_TRANSPARENT}=true" not in forwarded_env
mock_client.volumes.create.assert_not_called()
sandbox_id = main_kwargs["labels"][SANDBOX_ID_LABEL]
runtime_volume = f"opensandbox-runtime-{sandbox_id}"
mock_client.volumes.create.assert_called_once_with(
name=runtime_volume,
labels={SANDBOX_MANAGED_VOLUMES_LABEL: "server"},
)
sidecar_binds = sidecar_kwargs["host_config"].get("binds", [])
assert f"{runtime_volume}:{OPENSANDBOX_RUNTIME_MOUNT_PATH}:rw" in sidecar_binds


@pytest.mark.asyncio
Expand Down
Loading