dayhoff-tools 1.3.22__tar.gz → 1.3.24__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.22 → dayhoff_tools-1.3.24}/PKG-INFO +1 -1
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/cli/engine_commands.py +35 -83
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/pyproject.toml +1 -1
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/README.md +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/__init__.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/chemistry/standardizer.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/chemistry/utils.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/cli/__init__.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/cli/cloud_commands.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/cli/main.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/cli/swarm_commands.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/cli/utility_commands.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/deployment/base.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/deployment/deploy_aws.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/deployment/deploy_gcp.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/deployment/deploy_utils.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/deployment/job_runner.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/deployment/processors.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/deployment/swarm.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/embedders.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/fasta.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/file_ops.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/h5.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/intake/gcp.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/intake/gtdb.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/intake/kegg.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/intake/mmseqs.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/intake/structure.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/intake/uniprot.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/logs.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/sqlite.py +0 -0
- {dayhoff_tools-1.3.22 → dayhoff_tools-1.3.24}/dayhoff_tools/warehouse.py +0 -0
@@ -532,7 +532,6 @@ def list_engines(
|
|
532
532
|
table.add_column("Type")
|
533
533
|
table.add_column("User")
|
534
534
|
table.add_column("Status")
|
535
|
-
table.add_column("Stage")
|
536
535
|
table.add_column("Disk Usage")
|
537
536
|
table.add_column("Uptime/Since")
|
538
537
|
table.add_column("$/hour", justify="right")
|
@@ -555,15 +554,12 @@ def list_engines(
|
|
555
554
|
time_str = launch_time.strftime("%Y-%m-%d %H:%M")
|
556
555
|
disk_usage = "-"
|
557
556
|
|
558
|
-
stage_display = _colour_stage(stages_map.get(engine["instance_id"], "-"))
|
559
|
-
|
560
557
|
table.add_row(
|
561
558
|
engine["name"],
|
562
559
|
engine["instance_id"],
|
563
560
|
engine["engine_type"],
|
564
561
|
engine["user"],
|
565
562
|
format_status(engine["state"], engine.get("ready")),
|
566
|
-
stage_display,
|
567
563
|
disk_usage,
|
568
564
|
time_str,
|
569
565
|
f"${hourly_cost:.2f}",
|
@@ -831,7 +827,7 @@ def ssh_engine(
|
|
831
827
|
raise typer.Exit(1)
|
832
828
|
|
833
829
|
# Choose SSH user
|
834
|
-
ssh_user = "ec2-user" if admin else
|
830
|
+
ssh_user = "ec2-user" if admin else username
|
835
831
|
|
836
832
|
# Update SSH config
|
837
833
|
console.print(f"Updating SSH config for [cyan]{engine['name']}[/cyan] (user: {ssh_user})...")
|
@@ -908,7 +904,7 @@ def config_ssh(
|
|
908
904
|
if not clean:
|
909
905
|
for engine in running_engines:
|
910
906
|
# Determine ssh user based on --admin flag
|
911
|
-
ssh_user = 'ec2-user' if admin else
|
907
|
+
ssh_user = 'ec2-user' if admin else username
|
912
908
|
new_lines.extend(
|
913
909
|
[
|
914
910
|
"",
|
@@ -938,26 +934,31 @@ def config_ssh(
|
|
938
934
|
)
|
939
935
|
|
940
936
|
|
941
|
-
@engine_app.command("
|
942
|
-
def
|
937
|
+
@engine_app.command("coffee")
|
938
|
+
def coffee(
|
943
939
|
name_or_id: str = typer.Argument(help="Engine name or instance ID"),
|
944
|
-
duration: str = typer.Argument("4h", help="Duration (e.g., 2h, 30m,
|
940
|
+
duration: str = typer.Argument("4h", help="Duration (e.g., 2h, 30m, 2h30m)"),
|
941
|
+
cancel: bool = typer.Option(False, "--cancel", help="Cancel existing coffee lock instead of extending"),
|
945
942
|
):
|
946
|
-
"""
|
943
|
+
"""Pour ☕ for an engine: keeps it awake for the given duration (or cancel)."""
|
947
944
|
username = check_aws_sso()
|
948
945
|
|
949
946
|
# Parse duration
|
950
947
|
import re
|
951
948
|
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
949
|
+
if not cancel:
|
950
|
+
match = re.match(r"(?:(\d+)h)?(?:(\d+)m)?", duration)
|
951
|
+
if not match or (not match.group(1) and not match.group(2)):
|
952
|
+
console.print(f"[red]❌ Invalid duration format: {duration}[/red]")
|
953
|
+
console.print("Use format like: 4h, 30m, 2h30m")
|
954
|
+
raise typer.Exit(1)
|
957
955
|
|
958
|
-
|
959
|
-
|
960
|
-
|
956
|
+
hours = int(match.group(1) or 0)
|
957
|
+
minutes = int(match.group(2) or 0)
|
958
|
+
seconds_total = (hours * 60 + minutes) * 60
|
959
|
+
if seconds_total == 0:
|
960
|
+
console.print("[red]❌ Duration must be greater than zero[/red]")
|
961
|
+
raise typer.Exit(1)
|
961
962
|
|
962
963
|
# Get all engines to resolve name
|
963
964
|
response = make_api_request("GET", "/engines")
|
@@ -972,9 +973,10 @@ def keep_awake(
|
|
972
973
|
console.print(f"[red]❌ Engine is not running (state: {engine['state']})[/red]")
|
973
974
|
raise typer.Exit(1)
|
974
975
|
|
975
|
-
|
976
|
-
f"
|
977
|
-
|
976
|
+
if cancel:
|
977
|
+
console.print(f"Cancelling coffee for [cyan]{engine['name']}[/cyan]…")
|
978
|
+
else:
|
979
|
+
console.print(f"Pouring coffee for [cyan]{engine['name']}[/cyan] for {duration}…")
|
978
980
|
|
979
981
|
# Use SSM to run the engine keep-alive command
|
980
982
|
ssm = boto3.client("ssm", region_name="us-east-1")
|
@@ -983,7 +985,9 @@ def keep_awake(
|
|
983
985
|
InstanceIds=[engine["instance_id"]],
|
984
986
|
DocumentName="AWS-RunShellScript",
|
985
987
|
Parameters={
|
986
|
-
"commands": [
|
988
|
+
"commands": [
|
989
|
+
("engine-coffee --cancel" if cancel else f"engine-coffee {seconds_total}")
|
990
|
+
],
|
987
991
|
"executionTimeout": ["60"],
|
988
992
|
},
|
989
993
|
)
|
@@ -1001,75 +1005,23 @@ def keep_awake(
|
|
1001
1005
|
break
|
1002
1006
|
|
1003
1007
|
if result["Status"] == "Success":
|
1004
|
-
|
1008
|
+
if cancel:
|
1009
|
+
console.print("[green]✓ Coffee cancelled – auto-shutdown re-enabled[/green]")
|
1010
|
+
else:
|
1011
|
+
console.print(f"[green]✓ Coffee poured for {duration}[/green]")
|
1005
1012
|
console.print(
|
1006
1013
|
"\n[dim]Note: Detached Docker containers (except dev containers) will also keep the engine awake.[/dim]"
|
1007
1014
|
)
|
1008
1015
|
console.print(
|
1009
|
-
"[dim]Use
|
1010
|
-
)
|
1011
|
-
else:
|
1012
|
-
console.print(
|
1013
|
-
f"[red]❌ Failed to set keep-awake: {result.get('StatusDetails', 'Unknown error')}[/red]"
|
1014
|
-
)
|
1015
|
-
|
1016
|
-
except ClientError as e:
|
1017
|
-
console.print(f"[red]❌ Failed to set keep-awake: {e}[/red]")
|
1018
|
-
|
1019
|
-
|
1020
|
-
@engine_app.command("cancel-keep-awake")
|
1021
|
-
def cancel_keep_awake(
|
1022
|
-
name_or_id: str = typer.Argument(help="Engine name or instance ID"),
|
1023
|
-
):
|
1024
|
-
"""Cancel keep-awake and re-enable auto-shutdown."""
|
1025
|
-
username = check_aws_sso()
|
1026
|
-
|
1027
|
-
# Get all engines to resolve name
|
1028
|
-
response = make_api_request("GET", "/engines")
|
1029
|
-
if response.status_code != 200:
|
1030
|
-
console.print("[red]❌ Failed to fetch engines[/red]")
|
1031
|
-
raise typer.Exit(1)
|
1032
|
-
|
1033
|
-
engines = response.json().get("engines", [])
|
1034
|
-
engine = resolve_engine(name_or_id, engines)
|
1035
|
-
|
1036
|
-
console.print(f"Cancelling keep-awake for [cyan]{engine['name']}[/cyan]...")
|
1037
|
-
|
1038
|
-
# Use SSM to run the engine cancel command
|
1039
|
-
ssm = boto3.client("ssm", region_name="us-east-1")
|
1040
|
-
try:
|
1041
|
-
response = ssm.send_command(
|
1042
|
-
InstanceIds=[engine["instance_id"]],
|
1043
|
-
DocumentName="AWS-RunShellScript",
|
1044
|
-
Parameters={
|
1045
|
-
"commands": ["engine cancel"],
|
1046
|
-
"executionTimeout": ["60"],
|
1047
|
-
},
|
1048
|
-
)
|
1049
|
-
|
1050
|
-
command_id = response["Command"]["CommandId"]
|
1051
|
-
|
1052
|
-
# Wait for command to complete
|
1053
|
-
for _ in range(10):
|
1054
|
-
time.sleep(1)
|
1055
|
-
result = ssm.get_command_invocation(
|
1056
|
-
CommandId=command_id,
|
1057
|
-
InstanceId=engine["instance_id"],
|
1058
|
-
)
|
1059
|
-
if result["Status"] in ["Success", "Failed"]:
|
1060
|
-
break
|
1061
|
-
|
1062
|
-
if result["Status"] == "Success":
|
1063
|
-
console.print(
|
1064
|
-
"[green]✓ Keep-awake cancelled, auto-shutdown re-enabled[/green]"
|
1016
|
+
"[dim]Use coffee for nohup operations or other background tasks.[/dim]"
|
1065
1017
|
)
|
1066
1018
|
else:
|
1067
1019
|
console.print(
|
1068
|
-
f"[red]❌ Failed to
|
1020
|
+
f"[red]❌ Failed to manage coffee: {result.get('StatusDetails', 'Unknown error')}[/red]"
|
1069
1021
|
)
|
1070
1022
|
|
1071
1023
|
except ClientError as e:
|
1072
|
-
console.print(f"[red]❌ Failed to
|
1024
|
+
console.print(f"[red]❌ Failed to manage coffee: {e}[/red]")
|
1073
1025
|
|
1074
1026
|
|
1075
1027
|
@engine_app.command("resize")
|
@@ -1233,7 +1185,7 @@ def resize_engine(
|
|
1233
1185
|
raise typer.Exit(1)
|
1234
1186
|
|
1235
1187
|
|
1236
|
-
@engine_app.command("
|
1188
|
+
@engine_app.command("gami")
|
1237
1189
|
def create_ami(
|
1238
1190
|
name_or_id: str = typer.Argument(
|
1239
1191
|
help="Engine name or instance ID to create AMI from"
|
@@ -2011,7 +1963,7 @@ def resize_studio(
|
|
2011
1963
|
# ================= Idle timeout command =================
|
2012
1964
|
|
2013
1965
|
|
2014
|
-
@engine_app.command("idle
|
1966
|
+
@engine_app.command("idle")
|
2015
1967
|
def idle_timeout_cmd(
|
2016
1968
|
name_or_id: str = typer.Argument(help="Engine name or instance ID"),
|
2017
1969
|
set: Optional[str] = typer.Option(None, "--set", "-s", help="New timeout (e.g., 2h30m, 45m)")
|
@@ -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.24"
|
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
|