dayhoff-tools 1.3.27__tar.gz → 1.3.29__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/PKG-INFO +1 -1
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/cli/engine_commands.py +57 -4
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/pyproject.toml +1 -1
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/README.md +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/__init__.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/chemistry/standardizer.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/chemistry/utils.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/cli/__init__.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/cli/cloud_commands.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/cli/main.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/cli/swarm_commands.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/cli/utility_commands.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/deployment/base.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/deployment/deploy_aws.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/deployment/deploy_gcp.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/deployment/deploy_utils.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/deployment/job_runner.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/deployment/processors.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/deployment/swarm.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/embedders.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/fasta.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/file_ops.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/h5.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/intake/gcp.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/intake/gtdb.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/intake/kegg.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/intake/mmseqs.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/intake/structure.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/intake/uniprot.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/logs.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/sqlite.py +0 -0
- {dayhoff_tools-1.3.27 → dayhoff_tools-1.3.29}/dayhoff_tools/warehouse.py +0 -0
@@ -15,7 +15,7 @@ from botocore.exceptions import ClientError, NoCredentialsError
|
|
15
15
|
from rich import box
|
16
16
|
from rich.console import Console
|
17
17
|
from rich.panel import Panel
|
18
|
-
from rich.progress import Progress, SpinnerColumn, TextColumn
|
18
|
+
from rich.progress import Progress, SpinnerColumn, TextColumn, TimeElapsedColumn
|
19
19
|
from rich.prompt import Confirm, IntPrompt, Prompt
|
20
20
|
from rich.table import Table
|
21
21
|
import re
|
@@ -1314,6 +1314,40 @@ def create_ami(
|
|
1314
1314
|
)
|
1315
1315
|
console.print(f" Excluding volume at {device_name}")
|
1316
1316
|
|
1317
|
+
# --- Check & detach attached studios --------------------------------------------------
|
1318
|
+
# If any user studios are still attached we must detach them before the instance reboots
|
1319
|
+
# for snapshot consistency; otherwise Studio-Manager metadata becomes stale.
|
1320
|
+
|
1321
|
+
attached_resp = make_api_request("GET", f"/engines/{engine['instance_id']}/studios")
|
1322
|
+
attached_studios = attached_resp.json().get("studios", []) if attached_resp.status_code == 200 else []
|
1323
|
+
|
1324
|
+
if attached_studios:
|
1325
|
+
console.print(f"[yellow]⚠ {len(attached_studios)} studio(s) attached to this engine.[/yellow]")
|
1326
|
+
for s in attached_studios:
|
1327
|
+
console.print(f" • {s['user']} ({s['studio_id']})")
|
1328
|
+
|
1329
|
+
if not Confirm.ask("Detach all studios before AMI creation?"):
|
1330
|
+
console.print("AMI creation cancelled.")
|
1331
|
+
return
|
1332
|
+
|
1333
|
+
console.print("Detaching studios…")
|
1334
|
+
for s in attached_studios:
|
1335
|
+
resp = make_api_request("POST", f"/studios/{s['studio_id']}/detach")
|
1336
|
+
if resp.status_code != 200:
|
1337
|
+
console.print(f"[red]❌ Failed to detach {s['studio_id']} – aborting.[/red]")
|
1338
|
+
return
|
1339
|
+
|
1340
|
+
# Wait briefly for volumes to become available (max 2 min)
|
1341
|
+
import time, boto3
|
1342
|
+
ec2_wait = boto3.client("ec2", region_name="us-east-1")
|
1343
|
+
vol_ids = [s['studio_id'] for s in attached_studios]
|
1344
|
+
console.print("Waiting for volumes to detach…")
|
1345
|
+
waiter = ec2_wait.get_waiter("volume_available")
|
1346
|
+
try:
|
1347
|
+
waiter.wait(VolumeIds=vol_ids, WaiterConfig={"Delay": 5, "MaxAttempts": 24})
|
1348
|
+
except Exception:
|
1349
|
+
console.print("[yellow]Proceeding even though some volumes may still be detaching.[/yellow]")
|
1350
|
+
|
1317
1351
|
# Create the AMI
|
1318
1352
|
with Progress(
|
1319
1353
|
SpinnerColumn(),
|
@@ -1594,9 +1628,28 @@ def attach_studio(
|
|
1594
1628
|
raise typer.Exit(1)
|
1595
1629
|
console.print("[green]✓ Engine started[/green]")
|
1596
1630
|
console.print("Waiting for engine to be ready...")
|
1597
|
-
|
1598
|
-
|
1599
|
-
|
1631
|
+
# Wait until the engine is fully running & marked ready (max 5 min)
|
1632
|
+
console.print("Waiting for engine to be ready (this can take a couple of minutes)…")
|
1633
|
+
# Progress classes already imported at module level – do not re-import to avoid UnboundLocalError
|
1634
|
+
|
1635
|
+
with Progress(SpinnerColumn(), TimeElapsedColumn(), TextColumn("[progress.description]{task.description}"), transient=True) as prog:
|
1636
|
+
prog.add_task("Awaiting engine readiness…", total=None)
|
1637
|
+
max_attempts = 30 # 30 × 10 s ≈ 5 min
|
1638
|
+
for _ in range(max_attempts):
|
1639
|
+
time.sleep(10)
|
1640
|
+
|
1641
|
+
status_resp = make_api_request("GET", f"/engines/{engine['instance_id']}")
|
1642
|
+
if status_resp.status_code != 200:
|
1643
|
+
continue
|
1644
|
+
|
1645
|
+
detailed = status_resp.json().get("engine", {})
|
1646
|
+
state_ok = detailed.get("state", "").lower() == "running"
|
1647
|
+
ready_ok = detailed.get("ready") is True
|
1648
|
+
|
1649
|
+
if state_ok and ready_ok:
|
1650
|
+
break
|
1651
|
+
else:
|
1652
|
+
console.print("[yellow]Engine is still starting up. If attachment fails, wait a little longer and retry.[/yellow]")
|
1600
1653
|
else:
|
1601
1654
|
raise typer.Exit(1)
|
1602
1655
|
|
@@ -5,7 +5,7 @@ build-backend = "poetry.core.masonry.api"
|
|
5
5
|
|
6
6
|
[project]
|
7
7
|
name = "dayhoff-tools"
|
8
|
-
version = "1.3.
|
8
|
+
version = "1.3.29"
|
9
9
|
description = "Common tools for all the repos at Dayhoff Labs"
|
10
10
|
authors = [
|
11
11
|
{name = "Daniel Martin-Alarcon", email = "dma@dayhofflabs.com"}
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|