From b665cc8653c7e565b39e23fa7cf70931c097c1bc Mon Sep 17 00:00:00 2001 From: marko-kraemer Date: Sun, 17 Aug 2025 20:08:20 -0700 Subject: [PATCH] daytona archival script --- backend/pyproject.toml | 1 + backend/sandbox/sandbox.py | 2 +- .../scripts/archive_stopped_sandboxes.py | 187 ++++++++++++++++++ backend/uv.lock | 30 ++- 4 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 backend/utils/scripts/archive_stopped_sandboxes.py diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 88b02e77..641da0bf 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -69,6 +69,7 @@ dependencies = [ "beautifulsoup4>=4.12.0", "cssutils>=2.9.0", "fastapi-sso>=0.9.0", + "daytona>=0.21.6", ] [project.urls] diff --git a/backend/sandbox/sandbox.py b/backend/sandbox/sandbox.py index b9070cc2..d43c4ebd 100644 --- a/backend/sandbox/sandbox.py +++ b/backend/sandbox/sandbox.py @@ -9,7 +9,7 @@ load_dotenv() logger.debug("Initializing Daytona sandbox configuration") daytona_config = DaytonaConfig( api_key=config.DAYTONA_API_KEY, - api_url=config.DAYTONA_SERVER_URL, # Use api_url instead of server_url (deprecated) + api_url=config.DAYTONA_SERVER_URL, target=config.DAYTONA_TARGET, ) diff --git a/backend/utils/scripts/archive_stopped_sandboxes.py b/backend/utils/scripts/archive_stopped_sandboxes.py new file mode 100644 index 00000000..d976e09a --- /dev/null +++ b/backend/utils/scripts/archive_stopped_sandboxes.py @@ -0,0 +1,187 @@ +#!/usr/bin/env python3 +""" +Simple script to archive all Daytona sandboxes with "STOPPED" state. + +Usage: + python archive_stopped_sandboxes.py [--dry-run] +""" + +import sys +import argparse +import json +import re +from datetime import datetime +from utils.config import config + +try: + from daytona import Daytona +except ImportError: + print("Error: Daytona Python SDK not found. Please install it with: pip install daytona") + sys.exit(1) + +def save_raw_list_as_json(raw_list, filename=None): + """Save raw list output as JSON file.""" + if filename is None: + timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") + filename = f"raw_sandboxes_{timestamp}.json" + + print(f"Saving raw list output to {filename}") + + try: + with open(filename, 'w') as f: + json.dump(raw_list, f, indent=2, default=str) + print(f"✓ Successfully saved raw list to {filename}") + return filename + except Exception as e: + print(f"✗ Failed to save JSON file: {e}") + return None + +def parse_sandbox_string(sandbox_str): + """Parse sandbox string representation to extract ID and state.""" + # Extract ID using regex + id_match = re.search(r"id='([^']+)'", sandbox_str) + sandbox_id = id_match.group(1) if id_match else None + + # Extract state using regex + state_match = re.search(r"state== '3.12'", @@ -539,6 +539,32 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a7/ec/bb273b7208c606890dc36540fe667d06ce840a6f62f9fae7e658fcdc90fb/cssutils-2.11.1-py3-none-any.whl", hash = "sha256:a67bfdfdff4f3867fab43698ec4897c1a828eca5973f4073321b3bccaf1199b1", size = 385747, upload-time = "2024-06-04T15:51:37.499Z" }, ] +[[package]] +name = "daytona" +version = "0.21.6" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aioboto3" }, + { name = "aiofiles" }, + { name = "aiohttp" }, + { name = "aiohttp-retry" }, + { name = "boto3" }, + { name = "daytona-api-client" }, + { name = "daytona-api-client-async" }, + { name = "deprecated" }, + { name = "environs" }, + { name = "httpx" }, + { name = "marshmallow" }, + { name = "pydantic" }, + { name = "python-dateutil" }, + { name = "toml" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/88/61/045b9a3f28490a69941a3c680d1042a93f3fd52a2a7f8aa4ba1d310829bd/daytona-0.21.6.tar.gz", hash = "sha256:0551db851d4992d08d92f2c3bc1dab5834f8df12b7a21f95a897643410aa04da", size = 87564, upload-time = "2025-07-02T20:34:14.176Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/f5/a4d773564ffb2f1af19e8c606d6d80454b298edd8f5b44322db37e5c1b85/daytona-0.21.6-py3-none-any.whl", hash = "sha256:6427e5aa08482c92e1d4e889109b266246806d662e1085da709962bef241ed40", size = 105876, upload-time = "2025-07-02T20:34:11.367Z" }, +] + [[package]] name = "daytona-api-client" version = "0.21.0" @@ -2586,6 +2612,7 @@ dependencies = [ { name = "croniter" }, { name = "cryptography" }, { name = "cssutils" }, + { name = "daytona" }, { name = "daytona-api-client" }, { name = "daytona-api-client-async" }, { name = "daytona-sdk" }, @@ -2653,6 +2680,7 @@ requires-dist = [ { name = "croniter", specifier = ">=1.4.0" }, { name = "cryptography", specifier = ">=41.0.0" }, { name = "cssutils", specifier = ">=2.9.0" }, + { name = "daytona", specifier = ">=0.21.6" }, { name = "daytona-api-client", specifier = "==0.21.0" }, { name = "daytona-api-client-async", specifier = "==0.21.0" }, { name = "daytona-sdk", specifier = "==0.21.0" },