portacode 1.4.17.dev0__py3-none-any.whl → 1.4.17.dev2__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.
- portacode/_version.py +2 -2
- portacode/connection/handlers/proxmox_infra.py +58 -25
- {portacode-1.4.17.dev0.dist-info → portacode-1.4.17.dev2.dist-info}/METADATA +1 -1
- {portacode-1.4.17.dev0.dist-info → portacode-1.4.17.dev2.dist-info}/RECORD +8 -8
- {portacode-1.4.17.dev0.dist-info → portacode-1.4.17.dev2.dist-info}/WHEEL +0 -0
- {portacode-1.4.17.dev0.dist-info → portacode-1.4.17.dev2.dist-info}/entry_points.txt +0 -0
- {portacode-1.4.17.dev0.dist-info → portacode-1.4.17.dev2.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.4.17.dev0.dist-info → portacode-1.4.17.dev2.dist-info}/top_level.txt +0 -0
portacode/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.4.17.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 4, 17, '
|
|
31
|
+
__version__ = version = '1.4.17.dev2'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 4, 17, 'dev2')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -48,6 +48,8 @@ UNIT_DIR = Path("/etc/systemd/system")
|
|
|
48
48
|
_MANAGED_CONTAINERS_CACHE_TTL_S = 30.0
|
|
49
49
|
_MANAGED_CONTAINERS_CACHE: Dict[str, Any] = {"timestamp": 0.0, "summary": None}
|
|
50
50
|
_MANAGED_CONTAINERS_CACHE_LOCK = threading.Lock()
|
|
51
|
+
_CAPACITY_LOCK = threading.Lock()
|
|
52
|
+
_PENDING_ALLOCATIONS = {"ram_mib": 0.0, "disk_gib": 0.0, "cpu_share": 0.0}
|
|
51
53
|
TEMPLATES_REFRESH_INTERVAL_S = 300
|
|
52
54
|
|
|
53
55
|
ProgressCallback = Callable[[int, int, Dict[str, Any], str, Optional[Dict[str, Any]]], None]
|
|
@@ -720,6 +722,13 @@ def _build_full_container_summary(records: List[Dict[str, Any]], config: Dict[st
|
|
|
720
722
|
"template": record.get("template") if record else None,
|
|
721
723
|
"created_at": record.get("created_at") if record else None,
|
|
722
724
|
}
|
|
725
|
+
# Fallback to recorded specs if live probing returned zeros (e.g., just-created CT).
|
|
726
|
+
if not merged["ram_mib"] and record:
|
|
727
|
+
merged["ram_mib"] = record.get("ram_mib") or merged["ram_mib"]
|
|
728
|
+
if not merged["disk_gib"] and record:
|
|
729
|
+
merged["disk_gib"] = record.get("disk_gib") or merged["disk_gib"]
|
|
730
|
+
if not merged["cpu_share"] and record:
|
|
731
|
+
merged["cpu_share"] = record.get("cpus") or merged["cpu_share"]
|
|
723
732
|
managed_entries.append(merged)
|
|
724
733
|
else:
|
|
725
734
|
unmanaged_entries.append(base_entry)
|
|
@@ -782,20 +791,24 @@ def _compute_free_resources(summary: Dict[str, Any]) -> Dict[str, float]:
|
|
|
782
791
|
free_ram = None
|
|
783
792
|
free_disk = None
|
|
784
793
|
free_cpu = None
|
|
794
|
+
with _CAPACITY_LOCK:
|
|
795
|
+
pending_ram = float(_PENDING_ALLOCATIONS["ram_mib"])
|
|
796
|
+
pending_disk = float(_PENDING_ALLOCATIONS["disk_gib"])
|
|
797
|
+
pending_cpu = float(_PENDING_ALLOCATIONS["cpu_share"])
|
|
785
798
|
host_ram = summary.get("host_total_ram_mib")
|
|
786
799
|
alloc_ram = summary.get("allocated_ram_mib")
|
|
787
800
|
if host_ram is not None and alloc_ram is not None:
|
|
788
|
-
free_ram = max(float(host_ram) - float(alloc_ram), 0.0)
|
|
801
|
+
free_ram = max(float(host_ram) - float(alloc_ram) - pending_ram, 0.0)
|
|
789
802
|
|
|
790
803
|
host_disk = summary.get("host_total_disk_gib")
|
|
791
804
|
alloc_disk = summary.get("allocated_disk_gib")
|
|
792
805
|
if host_disk is not None and alloc_disk is not None:
|
|
793
|
-
free_disk = max(float(host_disk) - float(alloc_disk), 0.0)
|
|
806
|
+
free_disk = max(float(host_disk) - float(alloc_disk) - pending_disk, 0.0)
|
|
794
807
|
|
|
795
808
|
host_cpu = summary.get("host_total_cpu_cores")
|
|
796
809
|
alloc_cpu = summary.get("allocated_cpu_share")
|
|
797
810
|
if host_cpu is not None and alloc_cpu is not None:
|
|
798
|
-
free_cpu = max(float(host_cpu) - float(alloc_cpu), 0.0)
|
|
811
|
+
free_cpu = max(float(host_cpu) - float(alloc_cpu) - pending_cpu, 0.0)
|
|
799
812
|
|
|
800
813
|
return {
|
|
801
814
|
"ram_mib": free_ram,
|
|
@@ -1153,7 +1166,7 @@ def _start_container(proxmox: Any, node: str, vmid: int) -> Tuple[Dict[str, Any]
|
|
|
1153
1166
|
logger.info("Container %s already running (%ss)", vmid, uptime)
|
|
1154
1167
|
return status, 0.0
|
|
1155
1168
|
|
|
1156
|
-
# Validate capacity using the same math as the dashboard.
|
|
1169
|
+
# Validate capacity using the same math as the dashboard and serialize allocation.
|
|
1157
1170
|
summary = _get_managed_containers_summary(force=True)
|
|
1158
1171
|
cfg = proxmox.nodes(node).lxc(vmid).config.get()
|
|
1159
1172
|
payload = {
|
|
@@ -1161,13 +1174,23 @@ def _start_container(proxmox: Any, node: str, vmid: int) -> Tuple[Dict[str, Any]
|
|
|
1161
1174
|
"disk_gib": _pick_container_disk_gib("lxc", cfg, {"rootfs": cfg.get("rootfs")}),
|
|
1162
1175
|
"cpus": _pick_container_cpu_share("lxc", cfg, {}),
|
|
1163
1176
|
}
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1177
|
+
with _CAPACITY_LOCK:
|
|
1178
|
+
try:
|
|
1179
|
+
_assert_capacity_for_payload(payload, summary)
|
|
1180
|
+
except RuntimeError as exc:
|
|
1181
|
+
raise RuntimeError(f"Not enough resources to start container {vmid}: {exc}") from exc
|
|
1182
|
+
_PENDING_ALLOCATIONS["ram_mib"] += float(payload["ram_mib"] or 0)
|
|
1183
|
+
_PENDING_ALLOCATIONS["disk_gib"] += float(payload["disk_gib"] or 0)
|
|
1184
|
+
_PENDING_ALLOCATIONS["cpu_share"] += float(payload["cpus"] or 0)
|
|
1168
1185
|
|
|
1169
|
-
|
|
1170
|
-
|
|
1186
|
+
try:
|
|
1187
|
+
upid = proxmox.nodes(node).lxc(vmid).status.start.post()
|
|
1188
|
+
return _wait_for_task(proxmox, node, upid)
|
|
1189
|
+
finally:
|
|
1190
|
+
with _CAPACITY_LOCK:
|
|
1191
|
+
_PENDING_ALLOCATIONS["ram_mib"] -= float(payload["ram_mib"] or 0)
|
|
1192
|
+
_PENDING_ALLOCATIONS["disk_gib"] -= float(payload["disk_gib"] or 0)
|
|
1193
|
+
_PENDING_ALLOCATIONS["cpu_share"] -= float(payload["cpus"] or 0)
|
|
1171
1194
|
|
|
1172
1195
|
|
|
1173
1196
|
def _stop_container(proxmox: Any, node: str, vmid: int) -> Tuple[Dict[str, Any], float]:
|
|
@@ -1894,20 +1917,31 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
1894
1917
|
_validate_environment,
|
|
1895
1918
|
)
|
|
1896
1919
|
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1920
|
+
def _create_container():
|
|
1921
|
+
proxmox = _connect_proxmox(config)
|
|
1922
|
+
node = config.get("node") or DEFAULT_NODE_NAME
|
|
1923
|
+
payload = _build_container_payload(message, config)
|
|
1924
|
+
payload["cpulimit"] = float(payload["cpus"])
|
|
1925
|
+
payload["cores"] = int(max(math.ceil(payload["cpus"]), 1))
|
|
1926
|
+
payload["memory"] = int(payload["ram_mib"])
|
|
1927
|
+
payload["node"] = node
|
|
1928
|
+
# Validate against current free resources (same math as dashboard charts) and place a short-lived reservation.
|
|
1929
|
+
summary = _get_managed_containers_summary(force=True)
|
|
1930
|
+
with _CAPACITY_LOCK:
|
|
1931
|
+
try:
|
|
1932
|
+
_assert_capacity_for_payload(payload, summary)
|
|
1933
|
+
except RuntimeError as exc:
|
|
1934
|
+
raise RuntimeError(f"Not enough resources to create the container safely: {exc}") from exc
|
|
1935
|
+
_PENDING_ALLOCATIONS["ram_mib"] += float(payload["ram_mib"] or 0)
|
|
1936
|
+
_PENDING_ALLOCATIONS["disk_gib"] += float(payload["disk_gib"] or 0)
|
|
1937
|
+
_PENDING_ALLOCATIONS["cpu_share"] += float(payload["cpus"] or 0)
|
|
1938
|
+
try:
|
|
1939
|
+
vmid, _ = _instantiate_container(proxmox, node, payload)
|
|
1940
|
+
finally:
|
|
1941
|
+
with _CAPACITY_LOCK:
|
|
1942
|
+
_PENDING_ALLOCATIONS["ram_mib"] -= float(payload["ram_mib"] or 0)
|
|
1943
|
+
_PENDING_ALLOCATIONS["disk_gib"] -= float(payload["disk_gib"] or 0)
|
|
1944
|
+
_PENDING_ALLOCATIONS["cpu_share"] -= float(payload["cpus"] or 0)
|
|
1911
1945
|
logger.debug(
|
|
1912
1946
|
"Provisioning container node=%s template=%s ram=%s cpu=%s storage=%s",
|
|
1913
1947
|
node,
|
|
@@ -1916,7 +1950,6 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
1916
1950
|
payload["cpus"],
|
|
1917
1951
|
payload["storage"],
|
|
1918
1952
|
)
|
|
1919
|
-
vmid, _ = _instantiate_container(proxmox, node, payload)
|
|
1920
1953
|
payload["vmid"] = vmid
|
|
1921
1954
|
payload["created_at"] = datetime.utcnow().isoformat() + "Z"
|
|
1922
1955
|
payload["status"] = "creating"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
portacode/README.md,sha256=4dKtpvR8LNgZPVz37GmkQCMWIr_u25Ao63iW56s7Ke4,775
|
|
2
2
|
portacode/__init__.py,sha256=oB3sV1wXr-um-RXio73UG8E5Xx6cF2ZVJveqjNmC-vQ,1086
|
|
3
3
|
portacode/__main__.py,sha256=jmHTGC1hzmo9iKJLv-SSYe9BSIbPPZ2IOpecI03PlTs,296
|
|
4
|
-
portacode/_version.py,sha256=
|
|
4
|
+
portacode/_version.py,sha256=tY1iaGi0436VvMeNiABna_erno3lFewWo4mlsbvOmsg,719
|
|
5
5
|
portacode/cli.py,sha256=mGLKoZ-T2FBF7IA9wUq0zyG0X9__-A1ao7gajjcVRH8,21828
|
|
6
6
|
portacode/data.py,sha256=5-s291bv8J354myaHm1Y7CQZTZyRzMU3TGe5U4hb-FA,1591
|
|
7
7
|
portacode/keypair.py,sha256=0OO4vHDcF1XMxCDqce61xFTlFwlTcmqe5HyGsXFEt7s,5838
|
|
@@ -22,7 +22,7 @@ portacode/connection/handlers/diff_handlers.py,sha256=iYTIRCcpEQ03vIPKZCsMTE5aZb
|
|
|
22
22
|
portacode/connection/handlers/file_handlers.py,sha256=nAJH8nXnX07xxD28ngLpgIUzcTuRwZBNpEGEKdRqohw,39507
|
|
23
23
|
portacode/connection/handlers/project_aware_file_handlers.py,sha256=AqgMnDqX2893T2NsrvUSCwjN5VKj4Pb2TN0S_SuboOE,9803
|
|
24
24
|
portacode/connection/handlers/project_state_handlers.py,sha256=v6ZefGW9i7n1aZLq2jOGumJIjYb6aHlPI4m1jkYewm8,1686
|
|
25
|
-
portacode/connection/handlers/proxmox_infra.py,sha256=
|
|
25
|
+
portacode/connection/handlers/proxmox_infra.py,sha256=_v-qj-7zupk6egmed1AN_6iEhpL2k5hVa0q6-iZyK2I,89330
|
|
26
26
|
portacode/connection/handlers/registry.py,sha256=qXGE60sYEWg6ZtVQzFcZ5YI2XWR6lMgw4hAL9x5qR1I,6181
|
|
27
27
|
portacode/connection/handlers/session.py,sha256=uNGfiO_1B9-_yjJKkpvmbiJhIl6b-UXlT86UTfd6WYE,42219
|
|
28
28
|
portacode/connection/handlers/system_handlers.py,sha256=fr12QpOr_Z8KYGUU-AYrTQwRPAcrLK85hvj3SEq1Kw8,14757
|
|
@@ -65,7 +65,7 @@ portacode/utils/__init__.py,sha256=NgBlWTuNJESfIYJzP_3adI1yJQJR0XJLRpSdVNaBAN0,3
|
|
|
65
65
|
portacode/utils/diff_apply.py,sha256=4Oi7ft3VUCKmiUE4VM-OeqO7Gk6H7PF3WnN4WHXtjxI,15157
|
|
66
66
|
portacode/utils/diff_renderer.py,sha256=S76StnQ2DLfsz4Gg0m07UwPfRp8270PuzbNaQq-rmYk,13850
|
|
67
67
|
portacode/utils/ntp_clock.py,sha256=VqCnWCTehCufE43W23oB-WUdAZGeCcLxkmIOPwInYHc,2499
|
|
68
|
-
portacode-1.4.17.
|
|
68
|
+
portacode-1.4.17.dev2.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
|
|
69
69
|
test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
|
|
70
70
|
test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
|
|
71
71
|
test_modules/test_device_online.py,sha256=QtYq0Dq9vME8Gp2O4fGSheqVf8LUtpsSKosXXk56gGM,1654
|
|
@@ -91,8 +91,8 @@ testing_framework/core/playwright_manager.py,sha256=Tw46qwxIhOFkS48C2IWIQHHNpEe-
|
|
|
91
91
|
testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
|
|
92
92
|
testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
|
|
93
93
|
testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
|
|
94
|
-
portacode-1.4.17.
|
|
95
|
-
portacode-1.4.17.
|
|
96
|
-
portacode-1.4.17.
|
|
97
|
-
portacode-1.4.17.
|
|
98
|
-
portacode-1.4.17.
|
|
94
|
+
portacode-1.4.17.dev2.dist-info/METADATA,sha256=dX2o0Oj7K-LojM-kwShhU7XEWqV-Lw30xCImcbfc-wU,13051
|
|
95
|
+
portacode-1.4.17.dev2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
96
|
+
portacode-1.4.17.dev2.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
97
|
+
portacode-1.4.17.dev2.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
98
|
+
portacode-1.4.17.dev2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|