portacode 1.4.17.dev1__py3-none-any.whl → 1.4.17.dev3__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 +66 -29
- {portacode-1.4.17.dev1.dist-info → portacode-1.4.17.dev3.dist-info}/METADATA +1 -1
- {portacode-1.4.17.dev1.dist-info → portacode-1.4.17.dev3.dist-info}/RECORD +8 -8
- {portacode-1.4.17.dev1.dist-info → portacode-1.4.17.dev3.dist-info}/WHEEL +0 -0
- {portacode-1.4.17.dev1.dist-info → portacode-1.4.17.dev3.dist-info}/entry_points.txt +0 -0
- {portacode-1.4.17.dev1.dist-info → portacode-1.4.17.dev3.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.4.17.dev1.dist-info → portacode-1.4.17.dev3.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.dev3'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 4, 17, 'dev3')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -49,6 +49,7 @@ _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
51
|
_CAPACITY_LOCK = threading.Lock()
|
|
52
|
+
_PENDING_ALLOCATIONS = {"ram_mib": 0.0, "disk_gib": 0.0, "cpu_share": 0.0}
|
|
52
53
|
TEMPLATES_REFRESH_INTERVAL_S = 300
|
|
53
54
|
|
|
54
55
|
ProgressCallback = Callable[[int, int, Dict[str, Any], str, Optional[Dict[str, Any]]], None]
|
|
@@ -421,7 +422,14 @@ def _to_mib(value: Any) -> float:
|
|
|
421
422
|
|
|
422
423
|
|
|
423
424
|
def _pick_container_ram_mib(kind: str, cfg: Dict[str, Any], entry: Dict[str, Any]) -> float:
|
|
424
|
-
|
|
425
|
+
"""
|
|
426
|
+
Proxmox config `memory` is already MiB for both LXC and QEMU.
|
|
427
|
+
Fall back to list fields (bytes) only when it is absent/zero.
|
|
428
|
+
"""
|
|
429
|
+
mem_cfg = _safe_float(cfg.get("memory"))
|
|
430
|
+
if mem_cfg:
|
|
431
|
+
return mem_cfg
|
|
432
|
+
for candidate in (entry.get("maxmem"), entry.get("mem")):
|
|
425
433
|
ram = _to_mib(candidate)
|
|
426
434
|
if ram:
|
|
427
435
|
return ram
|
|
@@ -721,6 +729,13 @@ def _build_full_container_summary(records: List[Dict[str, Any]], config: Dict[st
|
|
|
721
729
|
"template": record.get("template") if record else None,
|
|
722
730
|
"created_at": record.get("created_at") if record else None,
|
|
723
731
|
}
|
|
732
|
+
# Fallback to recorded specs if live probing returned zeros (e.g., just-created CT).
|
|
733
|
+
if not merged["ram_mib"] and record:
|
|
734
|
+
merged["ram_mib"] = record.get("ram_mib") or merged["ram_mib"]
|
|
735
|
+
if not merged["disk_gib"] and record:
|
|
736
|
+
merged["disk_gib"] = record.get("disk_gib") or merged["disk_gib"]
|
|
737
|
+
if not merged["cpu_share"] and record:
|
|
738
|
+
merged["cpu_share"] = record.get("cpus") or merged["cpu_share"]
|
|
724
739
|
managed_entries.append(merged)
|
|
725
740
|
else:
|
|
726
741
|
unmanaged_entries.append(base_entry)
|
|
@@ -783,20 +798,24 @@ def _compute_free_resources(summary: Dict[str, Any]) -> Dict[str, float]:
|
|
|
783
798
|
free_ram = None
|
|
784
799
|
free_disk = None
|
|
785
800
|
free_cpu = None
|
|
801
|
+
with _CAPACITY_LOCK:
|
|
802
|
+
pending_ram = float(_PENDING_ALLOCATIONS["ram_mib"])
|
|
803
|
+
pending_disk = float(_PENDING_ALLOCATIONS["disk_gib"])
|
|
804
|
+
pending_cpu = float(_PENDING_ALLOCATIONS["cpu_share"])
|
|
786
805
|
host_ram = summary.get("host_total_ram_mib")
|
|
787
806
|
alloc_ram = summary.get("allocated_ram_mib")
|
|
788
807
|
if host_ram is not None and alloc_ram is not None:
|
|
789
|
-
free_ram = max(float(host_ram) - float(alloc_ram), 0.0)
|
|
808
|
+
free_ram = max(float(host_ram) - float(alloc_ram) - pending_ram, 0.0)
|
|
790
809
|
|
|
791
810
|
host_disk = summary.get("host_total_disk_gib")
|
|
792
811
|
alloc_disk = summary.get("allocated_disk_gib")
|
|
793
812
|
if host_disk is not None and alloc_disk is not None:
|
|
794
|
-
free_disk = max(float(host_disk) - float(alloc_disk), 0.0)
|
|
813
|
+
free_disk = max(float(host_disk) - float(alloc_disk) - pending_disk, 0.0)
|
|
795
814
|
|
|
796
815
|
host_cpu = summary.get("host_total_cpu_cores")
|
|
797
816
|
alloc_cpu = summary.get("allocated_cpu_share")
|
|
798
817
|
if host_cpu is not None and alloc_cpu is not None:
|
|
799
|
-
free_cpu = max(float(host_cpu) - float(alloc_cpu), 0.0)
|
|
818
|
+
free_cpu = max(float(host_cpu) - float(alloc_cpu) - pending_cpu, 0.0)
|
|
800
819
|
|
|
801
820
|
return {
|
|
802
821
|
"ram_mib": free_ram,
|
|
@@ -1155,21 +1174,30 @@ def _start_container(proxmox: Any, node: str, vmid: int) -> Tuple[Dict[str, Any]
|
|
|
1155
1174
|
return status, 0.0
|
|
1156
1175
|
|
|
1157
1176
|
# Validate capacity using the same math as the dashboard and serialize allocation.
|
|
1177
|
+
summary = _get_managed_containers_summary(force=True)
|
|
1178
|
+
cfg = proxmox.nodes(node).lxc(vmid).config.get()
|
|
1179
|
+
payload = {
|
|
1180
|
+
"ram_mib": _to_mib(cfg.get("memory")),
|
|
1181
|
+
"disk_gib": _pick_container_disk_gib("lxc", cfg, {"rootfs": cfg.get("rootfs")}),
|
|
1182
|
+
"cpus": _pick_container_cpu_share("lxc", cfg, {}),
|
|
1183
|
+
}
|
|
1158
1184
|
with _CAPACITY_LOCK:
|
|
1159
|
-
summary = _get_managed_containers_summary(force=True)
|
|
1160
|
-
cfg = proxmox.nodes(node).lxc(vmid).config.get()
|
|
1161
|
-
payload = {
|
|
1162
|
-
"ram_mib": _to_mib(cfg.get("memory")),
|
|
1163
|
-
"disk_gib": _pick_container_disk_gib("lxc", cfg, {"rootfs": cfg.get("rootfs")}),
|
|
1164
|
-
"cpus": _pick_container_cpu_share("lxc", cfg, {}),
|
|
1165
|
-
}
|
|
1166
1185
|
try:
|
|
1167
1186
|
_assert_capacity_for_payload(payload, summary)
|
|
1168
1187
|
except RuntimeError as exc:
|
|
1169
1188
|
raise RuntimeError(f"Not enough resources to start container {vmid}: {exc}") from exc
|
|
1189
|
+
_PENDING_ALLOCATIONS["ram_mib"] += float(payload["ram_mib"] or 0)
|
|
1190
|
+
_PENDING_ALLOCATIONS["disk_gib"] += float(payload["disk_gib"] or 0)
|
|
1191
|
+
_PENDING_ALLOCATIONS["cpu_share"] += float(payload["cpus"] or 0)
|
|
1170
1192
|
|
|
1171
|
-
|
|
1172
|
-
|
|
1193
|
+
try:
|
|
1194
|
+
upid = proxmox.nodes(node).lxc(vmid).status.start.post()
|
|
1195
|
+
return _wait_for_task(proxmox, node, upid)
|
|
1196
|
+
finally:
|
|
1197
|
+
with _CAPACITY_LOCK:
|
|
1198
|
+
_PENDING_ALLOCATIONS["ram_mib"] -= float(payload["ram_mib"] or 0)
|
|
1199
|
+
_PENDING_ALLOCATIONS["disk_gib"] -= float(payload["disk_gib"] or 0)
|
|
1200
|
+
_PENDING_ALLOCATIONS["cpu_share"] -= float(payload["cpus"] or 0)
|
|
1173
1201
|
|
|
1174
1202
|
|
|
1175
1203
|
def _stop_container(proxmox: Any, node: str, vmid: int) -> Tuple[Dict[str, Any], float]:
|
|
@@ -1896,22 +1924,31 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
1896
1924
|
_validate_environment,
|
|
1897
1925
|
)
|
|
1898
1926
|
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1927
|
+
def _create_container():
|
|
1928
|
+
proxmox = _connect_proxmox(config)
|
|
1929
|
+
node = config.get("node") or DEFAULT_NODE_NAME
|
|
1930
|
+
payload = _build_container_payload(message, config)
|
|
1931
|
+
payload["cpulimit"] = float(payload["cpus"])
|
|
1932
|
+
payload["cores"] = int(max(math.ceil(payload["cpus"]), 1))
|
|
1933
|
+
payload["memory"] = int(payload["ram_mib"])
|
|
1934
|
+
payload["node"] = node
|
|
1935
|
+
# Validate against current free resources (same math as dashboard charts) and place a short-lived reservation.
|
|
1936
|
+
summary = _get_managed_containers_summary(force=True)
|
|
1937
|
+
with _CAPACITY_LOCK:
|
|
1938
|
+
try:
|
|
1939
|
+
_assert_capacity_for_payload(payload, summary)
|
|
1940
|
+
except RuntimeError as exc:
|
|
1941
|
+
raise RuntimeError(f"Not enough resources to create the container safely: {exc}") from exc
|
|
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)
|
|
1945
|
+
try:
|
|
1946
|
+
vmid, _ = _instantiate_container(proxmox, node, payload)
|
|
1947
|
+
finally:
|
|
1948
|
+
with _CAPACITY_LOCK:
|
|
1949
|
+
_PENDING_ALLOCATIONS["ram_mib"] -= float(payload["ram_mib"] or 0)
|
|
1950
|
+
_PENDING_ALLOCATIONS["disk_gib"] -= float(payload["disk_gib"] or 0)
|
|
1951
|
+
_PENDING_ALLOCATIONS["cpu_share"] -= float(payload["cpus"] or 0)
|
|
1915
1952
|
logger.debug(
|
|
1916
1953
|
"Provisioning container node=%s template=%s ram=%s cpu=%s storage=%s",
|
|
1917
1954
|
node,
|
|
@@ -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=16HDRPCTtR6orWusoLn2afHMuqIOPfcRoxTVdLzEYl0,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=Tuugl7DRJ_oejKQO96A722N4Jt5S-RBkz73LIWDeKEc,89543
|
|
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.dev3.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.dev3.dist-info/METADATA,sha256=2SfZxixbECm7f6jilfpD9-8Oal2HIpqK0T07xnxEVa4,13051
|
|
95
|
+
portacode-1.4.17.dev3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
96
|
+
portacode-1.4.17.dev3.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
97
|
+
portacode-1.4.17.dev3.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
98
|
+
portacode-1.4.17.dev3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|