@@ -10,6 +10,7 @@ from devplacepy import config, project_files, stealth
|
||||
from devplacepy.services.containers import store
|
||||
from devplacepy.services.containers.backend.base import (
|
||||
WORKSPACE_MOUNT,
|
||||
WORKSPACE_STATE_MOUNT,
|
||||
Mount,
|
||||
PortMapping,
|
||||
RunSpec,
|
||||
@@ -414,7 +415,7 @@ def pravda_env(instance: dict) -> dict:
|
||||
break
|
||||
slug = instance.get("ingress_slug") or ""
|
||||
ingress_url = (f"{base_url}/p/{slug}" if base_url else f"/p/{slug}") if slug else ""
|
||||
return {
|
||||
env = {
|
||||
"DEVPLACE_BASE_URL": base_url,
|
||||
"DEVPLACE_OPENAI_URL": f"{base_url}/openai/v1" if base_url else "",
|
||||
"DEVPLACE_API_KEY": api_key,
|
||||
@@ -423,6 +424,109 @@ def pravda_env(instance: dict) -> dict:
|
||||
"DEVPLACE_CONTAINER_UID": instance.get("uid") or "",
|
||||
"DEVPLACE_INGRESS_URL": ingress_url,
|
||||
}
|
||||
env.update(workspace_env(instance, base_url))
|
||||
return env
|
||||
|
||||
|
||||
def workspace_env(instance: dict, base_url: str) -> dict:
|
||||
from devplacepy import database
|
||||
from devplacepy.database import get_setting
|
||||
from devplacepy.services.containers.workspace import naming, quota
|
||||
|
||||
if not instance.get("is_workspace"):
|
||||
return {"DEVPLACE_WORKSPACE": ""}
|
||||
|
||||
project_slug = ""
|
||||
project_title = ""
|
||||
project_uid = instance.get("project_uid") or ""
|
||||
if project_uid:
|
||||
project = database.get_table("projects").find_one(uid=project_uid)
|
||||
if project:
|
||||
project_slug = project.get("slug") or project_uid
|
||||
project_title = project.get("title") or ""
|
||||
|
||||
owner_uid = instance.get("workspace_owner_uid") or ""
|
||||
owner_name = ""
|
||||
if owner_uid:
|
||||
owner = database.get_users_by_uids([owner_uid]).get(owner_uid)
|
||||
if owner:
|
||||
owner_name = owner.get("username") or ""
|
||||
|
||||
name = instance.get("tunnel_name") or ""
|
||||
domain = naming.domain()
|
||||
primary = naming.hostname_for(name) if name else ""
|
||||
workspace_url = (
|
||||
f"{base_url}/projects/{project_slug}/workspace"
|
||||
if base_url and project_slug
|
||||
else (f"/projects/{project_slug}/workspace" if project_slug else "")
|
||||
)
|
||||
limits = quota.resolve(owner_uid, instance)
|
||||
gallery = get_setting("workspace_extensions_gallery", "").strip()
|
||||
editor_port = int(instance.get("editor_port") or 0)
|
||||
|
||||
env = {
|
||||
"DEVPLACE_WORKSPACE": "1",
|
||||
"DEVPLACE_WORKSPACE_UID": instance.get("uid") or "",
|
||||
"DEVPLACE_WORKSPACE_URL": workspace_url,
|
||||
"DEVPLACE_WORKSPACE_OWNER": owner_name,
|
||||
"DEVPLACE_WORKSPACE_OWNER_UID": owner_uid,
|
||||
"DEVPLACE_PROJECT_SLUG": project_slug,
|
||||
"DEVPLACE_PROJECT_TITLE": project_title,
|
||||
"DEVPLACE_PROJECT_URL": (
|
||||
f"{base_url}/projects/{project_slug}"
|
||||
if base_url and project_slug
|
||||
else (f"/projects/{project_slug}" if project_slug else "")
|
||||
),
|
||||
"DEVPLACE_WORKSPACE_DIR": WORKSPACE_MOUNT,
|
||||
"DEVPLACE_WORKSPACE_STATE_DIR": WORKSPACE_STATE_MOUNT,
|
||||
"DEVPLACE_TUNNEL_NAME": name,
|
||||
"DEVPLACE_TUNNEL_DOMAIN": domain,
|
||||
"DEVPLACE_TUNNEL_URL": f"https://{primary}" if primary else "",
|
||||
"DEVPLACE_TUNNEL_PATTERN": naming.host_pattern(),
|
||||
"DEVPLACE_TUNNEL_PORT_PATTERN": naming.port_pattern(),
|
||||
"DEVPLACE_TUNNEL_MANIFEST": f"{WORKSPACE_MOUNT}/.devplace/tunnels.json",
|
||||
"DEVPLACE_TUNNEL_MAX": str(limits.max_tunnels),
|
||||
"VSCODE_PROXY_URI": naming.proxy_uri_template(name),
|
||||
"DEVPLACE_EDITOR": "code-server",
|
||||
"DEVPLACE_EDITOR_PORT": str(editor_port),
|
||||
"DEVPLACE_EDITOR_URL": (
|
||||
f"{workspace_url}" if workspace_url else ""
|
||||
),
|
||||
"VSCODE_CLI_DATA_DIR": f"{WORKSPACE_STATE_MOUNT}/cli",
|
||||
"DEVPLACE_QUOTA_DISK_MB": str(limits.disk_quota_mb),
|
||||
"DEVPLACE_QUOTA_DISK_USED_MB": str(
|
||||
int(instance.get("disk_bytes") or 0) // (1024 * 1024)
|
||||
),
|
||||
"DEVPLACE_QUOTA_EGRESS_MB": str(limits.egress_quota_mb),
|
||||
"DEVPLACE_IDLE_STOP_MINUTES": str(limits.idle_stop_minutes),
|
||||
"DEVPLACE_RETENTION_DAYS": str(limits.retention_days),
|
||||
"DEVPLACE_CPU_LIMIT": str(instance.get("cpu_limit") or ""),
|
||||
"DEVPLACE_MEM_LIMIT": str(instance.get("mem_limit") or ""),
|
||||
}
|
||||
if gallery:
|
||||
env["EXTENSIONS_GALLERY"] = gallery
|
||||
return {key: ("" if value is None else str(value)) for key, value in env.items()}
|
||||
|
||||
|
||||
EDITOR_DEFAULT_PORT = 8443
|
||||
|
||||
|
||||
def editor_command(instance: dict) -> list[str]:
|
||||
port = int(instance.get("editor_port") or EDITOR_DEFAULT_PORT)
|
||||
return [
|
||||
"code-server",
|
||||
"--bind-addr",
|
||||
f"0.0.0.0:{port}",
|
||||
"--auth",
|
||||
"none",
|
||||
"--disable-telemetry",
|
||||
"--disable-update-check",
|
||||
"--user-data-dir",
|
||||
f"{WORKSPACE_STATE_MOUNT}/data",
|
||||
"--extensions-dir",
|
||||
f"{WORKSPACE_STATE_MOUNT}/extensions",
|
||||
WORKSPACE_MOUNT,
|
||||
]
|
||||
|
||||
|
||||
def run_spec_for(instance: dict, image_tag: str) -> RunSpec:
|
||||
@@ -432,6 +536,10 @@ def run_spec_for(instance: dict, image_tag: str) -> RunSpec:
|
||||
for p in json.loads(instance.get("ports_json") or "[]")
|
||||
]
|
||||
mounts = [Mount(instance["workspace_dir"], WORKSPACE_MOUNT, "rw")]
|
||||
if instance.get("is_workspace"):
|
||||
state_dir = config.WORKSPACE_STATE_DIR / instance["uid"]
|
||||
state_dir.mkdir(parents=True, exist_ok=True)
|
||||
mounts.append(Mount(str(state_dir), WORKSPACE_STATE_MOUNT, "rw"))
|
||||
for extra in json.loads(instance.get("volumes_json") or "[]"):
|
||||
if isinstance(extra, dict) and extra.get("host") and extra.get("container"):
|
||||
mounts.append(
|
||||
@@ -439,7 +547,9 @@ def run_spec_for(instance: dict, image_tag: str) -> RunSpec:
|
||||
)
|
||||
language = (instance.get("boot_language") or "none").strip().lower()
|
||||
boot = (instance.get("boot_command") or "").strip()
|
||||
if language in BOOT_SCRIPT_FILES and (instance.get("boot_script") or "").strip():
|
||||
if instance.get("is_workspace") and int(instance.get("editor_port") or 0):
|
||||
command = editor_command(instance)
|
||||
elif language in BOOT_SCRIPT_FILES and (instance.get("boot_script") or "").strip():
|
||||
script_path = f"{WORKSPACE_MOUNT}/{BOOT_SCRIPT_FILES[language]}"
|
||||
command = [BOOT_SCRIPT_RUNNERS[language], script_path]
|
||||
elif boot:
|
||||
|
||||
Reference in New Issue
Block a user