dayhoff-tools 1.3.12__py3-none-any.whl → 1.3.14__py3-none-any.whl

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.
@@ -959,6 +959,9 @@ def resize_engine(
959
959
  online: bool = typer.Option(
960
960
  False, "--online", help="Resize while running (requires manual filesystem expansion)"
961
961
  ),
962
+ force: bool = typer.Option(
963
+ False, "--force", "-f", help="Force resize and detach all studios"
964
+ ),
962
965
  ):
963
966
  """Resize an engine's boot disk."""
964
967
  check_aws_sso()
@@ -1024,29 +1027,68 @@ def resize_engine(
1024
1027
  resize_response = make_api_request(
1025
1028
  "POST",
1026
1029
  f"/engines/{engine['instance_id']}/resize",
1027
- json_data={"size": size}
1030
+ json_data={"size": size, "detach_studios": force}
1028
1031
  )
1029
1032
 
1033
+ if resize_response.status_code == 409 and not force:
1034
+ # Engine has attached studios
1035
+ data = resize_response.json()
1036
+ attached_studios = data.get("attached_studios", [])
1037
+
1038
+ console.print("\n[yellow]⚠️ This engine has attached studios:[/yellow]")
1039
+ for studio in attached_studios:
1040
+ console.print(f" • {studio['user']} ({studio['studio_id']})")
1041
+
1042
+ if Confirm.ask("\nDetach all studios and resize the engine?"):
1043
+ resize_response = make_api_request(
1044
+ "POST",
1045
+ f"/engines/{engine['instance_id']}/resize",
1046
+ json_data={"size": size, "detach_studios": True}
1047
+ )
1048
+ else:
1049
+ console.print("Resize cancelled.")
1050
+ return
1051
+
1030
1052
  if resize_response.status_code != 200:
1031
1053
  error = resize_response.json().get("error", "Unknown error")
1032
1054
  console.print(f"[red]❌ Failed to resize engine: {error}[/red]")
1033
1055
  raise typer.Exit(1)
1034
1056
 
1035
- # Wait for volume modification to complete
1057
+ # Check if studios were detached
1058
+ data = resize_response.json()
1059
+ detached_studios = data.get("detached_studios", 0)
1060
+ if detached_studios > 0:
1061
+ console.print(f"[green]✓ Detached {detached_studios} studio(s) before resize[/green]")
1062
+
1063
+ # Wait for modification to complete
1036
1064
  console.print("Waiting for volume modification to complete...")
1037
1065
  while True:
1038
1066
  mod_state = ec2.describe_volumes_modifications(VolumeIds=[root_volume_id])
1039
1067
  if not mod_state["VolumesModifications"]:
1040
1068
  break # Modification complete
1041
- state = mod_state["VolumesModifications"][0]["ModificationState"]
1069
+
1070
+ modification = mod_state["VolumesModifications"][0]
1071
+ state = modification["ModificationState"]
1072
+ progress = modification.get("Progress", 0)
1073
+
1074
+ # Show progress updates only for the resize phase
1075
+ if state == "modifying":
1076
+ console.print(f"[yellow]Progress: {progress}%[/yellow]")
1077
+
1078
+ # Exit as soon as optimization starts (resize is complete)
1079
+ if state == "optimizing":
1080
+ console.print("[green]✓ Volume resized successfully[/green]")
1081
+ console.print("[dim]AWS is optimizing the volume in the background (no action needed).[/dim]")
1082
+ break
1083
+
1042
1084
  if state == "completed":
1085
+ console.print("[green]✓ Volume resized successfully[/green]")
1043
1086
  break
1044
1087
  elif state == "failed":
1045
1088
  console.print("[red]❌ Volume modification failed[/red]")
1046
1089
  raise typer.Exit(1)
1047
- time.sleep(5)
1048
-
1049
- console.print("[green]✓ Volume resized successfully[/green]")
1090
+
1091
+ time.sleep(2) # Check more frequently for better UX
1050
1092
 
1051
1093
  # If offline resize, start the instance back up
1052
1094
  if not online and engine["state"].lower() == "running":
@@ -1796,38 +1838,51 @@ def resize_studio(
1796
1838
  )
1797
1839
 
1798
1840
  if resize_response.status_code != 200:
1799
- # Add debugging to see the actual response
1800
- try:
1801
- error_body = resize_response.json()
1802
- error = error_body.get("error", "Unknown error")
1803
- console.print(f"[red]Debug: Full error response: {error_body}[/red]")
1804
- except Exception as e:
1805
- console.print(f"[red]Debug: Failed to parse error response: {e}[/red]")
1806
- console.print(f"[red]Debug: Raw response: {resize_response.text}[/red]")
1807
- error = "Unknown error"
1808
-
1841
+ error = resize_response.json().get("error", "Unknown error")
1809
1842
  console.print(f"[red]❌ Failed to resize studio: {error}[/red]")
1810
1843
  raise typer.Exit(1)
1811
1844
 
1812
1845
  # Wait for volume modification to complete
1813
1846
  ec2 = boto3.client("ec2", region_name="us-east-1")
1814
- console.print("Waiting for volume modification to complete...")
1847
+ console.print("Resizing volume...")
1848
+
1849
+ # Track progress
1850
+ last_progress = 0
1851
+
1815
1852
  while True:
1816
1853
  try:
1817
1854
  mod_state = ec2.describe_volumes_modifications(VolumeIds=[studio["studio_id"]])
1818
1855
  if not mod_state["VolumesModifications"]:
1819
1856
  break # Modification complete
1820
- state = mod_state["VolumesModifications"][0]["ModificationState"]
1857
+
1858
+ modification = mod_state["VolumesModifications"][0]
1859
+ state = modification["ModificationState"]
1860
+ progress = modification.get("Progress", 0)
1861
+
1862
+ # Show progress updates only for the resize phase
1863
+ if state == "modifying" and progress > last_progress:
1864
+ console.print(f"[yellow]Progress: {progress}%[/yellow]")
1865
+ last_progress = progress
1866
+
1867
+ # Exit as soon as optimization starts (resize is complete)
1868
+ if state == "optimizing":
1869
+ console.print(f"[green]✓ Studio resized successfully to {size}GB![/green]")
1870
+ console.print("[dim]AWS is optimizing the volume in the background (no action needed).[/dim]")
1871
+ break
1872
+
1821
1873
  if state == "completed":
1874
+ console.print(f"[green]✓ Studio resized successfully to {size}GB![/green]")
1822
1875
  break
1823
1876
  elif state == "failed":
1824
1877
  console.print("[red]❌ Volume modification failed[/red]")
1825
1878
  raise typer.Exit(1)
1826
- time.sleep(5)
1879
+
1880
+ time.sleep(2) # Check more frequently for better UX
1881
+
1827
1882
  except ClientError:
1828
1883
  # Modification might be complete
1884
+ console.print(f"[green]✓ Studio resized successfully to {size}GB![/green]")
1829
1885
  break
1830
1886
 
1831
- console.print(f"[green]✓ Studio resized successfully to {size}GB![/green]")
1832
1887
  console.print("\n[dim]The filesystem will be automatically expanded when you next attach the studio.[/dim]")
1833
1888
  console.print(f"To attach: [cyan]dh studio attach <engine-name>[/cyan]")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: dayhoff-tools
3
- Version: 1.3.12
3
+ Version: 1.3.14
4
4
  Summary: Common tools for all the repos at Dayhoff Labs
5
5
  Author: Daniel Martin-Alarcon
6
6
  Author-email: dma@dayhofflabs.com
@@ -3,7 +3,7 @@ dayhoff_tools/chemistry/standardizer.py,sha256=uMn7VwHnx02nc404eO6fRuS4rsl4dvSPf
3
3
  dayhoff_tools/chemistry/utils.py,sha256=jt-7JgF-GeeVC421acX-bobKbLU_X94KNOW24p_P-_M,2257
4
4
  dayhoff_tools/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
5
5
  dayhoff_tools/cli/cloud_commands.py,sha256=33qcWLmq-FwEXMdL3F0OHm-5Stlh2r65CldyEZgQ1no,40904
6
- dayhoff_tools/cli/engine_commands.py,sha256=475Y-LaZVyAh085vELkz5j8M3wAI45w2T2vZBTufGr0,66847
6
+ dayhoff_tools/cli/engine_commands.py,sha256=Oo_3I5gd8zP9esjUqwv2skL8Jz3KKd-DcYjCdV34FI8,69275
7
7
  dayhoff_tools/cli/main.py,sha256=rgeEHD9lJ8SBCR34BTLb7gVInHUUdmEBNXAJnq5yEU4,4795
8
8
  dayhoff_tools/cli/swarm_commands.py,sha256=5EyKj8yietvT5lfoz8Zx0iQvVaNgc3SJX1z2zQR6o6M,5614
9
9
  dayhoff_tools/cli/utility_commands.py,sha256=qs8vH9TBFHsOPC3X8cU3qZigM3dDn-2Ytq4o_F2WubU,27874
@@ -27,7 +27,7 @@ dayhoff_tools/intake/uniprot.py,sha256=BZYJQF63OtPcBBnQ7_P9gulxzJtqyorgyuDiPeOJq
27
27
  dayhoff_tools/logs.py,sha256=DKdeP0k0kliRcilwvX0mUB2eipO5BdWUeHwh-VnsICs,838
28
28
  dayhoff_tools/sqlite.py,sha256=jV55ikF8VpTfeQqqlHSbY8OgfyfHj8zgHNpZjBLos_E,18672
29
29
  dayhoff_tools/warehouse.py,sha256=8YbnQ--usrEgDQGfvpV4MrMji55A0rq2hZaOgFGh6ag,15896
30
- dayhoff_tools-1.3.12.dist-info/METADATA,sha256=si_BtctF0Fv-X8JV-8OoEB1ZoCiYEC21MobJkZ3z_JI,2825
31
- dayhoff_tools-1.3.12.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
- dayhoff_tools-1.3.12.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
- dayhoff_tools-1.3.12.dist-info/RECORD,,
30
+ dayhoff_tools-1.3.14.dist-info/METADATA,sha256=IkAuNoYuoRklhk6A6cgQl2x04MvK1AsirQixpV5rMs0,2825
31
+ dayhoff_tools-1.3.14.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
32
+ dayhoff_tools-1.3.14.dist-info/entry_points.txt,sha256=iAf4jteNqW3cJm6CO6czLxjW3vxYKsyGLZ8WGmxamSc,49
33
+ dayhoff_tools-1.3.14.dist-info/RECORD,,