portacode 1.4.16.dev8__py3-none-any.whl → 1.4.16.dev10__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 +149 -70
- {portacode-1.4.16.dev8.dist-info → portacode-1.4.16.dev10.dist-info}/METADATA +1 -1
- {portacode-1.4.16.dev8.dist-info → portacode-1.4.16.dev10.dist-info}/RECORD +8 -8
- {portacode-1.4.16.dev8.dist-info → portacode-1.4.16.dev10.dist-info}/WHEEL +0 -0
- {portacode-1.4.16.dev8.dist-info → portacode-1.4.16.dev10.dist-info}/entry_points.txt +0 -0
- {portacode-1.4.16.dev8.dist-info → portacode-1.4.16.dev10.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.4.16.dev8.dist-info → portacode-1.4.16.dev10.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.16.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 4, 16, '
|
|
31
|
+
__version__ = version = '1.4.16.dev10'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 4, 16, 'dev10')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -259,21 +259,157 @@ def _bytes_to_gib(value: Any) -> int:
|
|
|
259
259
|
return int(round(_normalize_bytes(value) / (1024**3)))
|
|
260
260
|
|
|
261
261
|
|
|
262
|
+
def _normalize_storage_name(name: Any) -> str:
|
|
263
|
+
if not name:
|
|
264
|
+
return ""
|
|
265
|
+
return str(name).strip().lower()
|
|
266
|
+
|
|
267
|
+
def _size_token_to_gib(token: str) -> float:
|
|
268
|
+
match = re.match(r"^\s*([0-9]+(?:\.[0-9]+)?)\s*([KMGTP])?([iI]?[bB])?\s*$", token)
|
|
269
|
+
if not match:
|
|
270
|
+
return 0.0
|
|
271
|
+
number = float(match.group(1))
|
|
272
|
+
unit = (match.group(2) or "").upper()
|
|
273
|
+
scale = {
|
|
274
|
+
"": 1,
|
|
275
|
+
"K": 1024 ** 1,
|
|
276
|
+
"M": 1024 ** 2,
|
|
277
|
+
"G": 1024 ** 3,
|
|
278
|
+
"T": 1024 ** 4,
|
|
279
|
+
"P": 1024 ** 5,
|
|
280
|
+
}.get(unit, 1)
|
|
281
|
+
return (number * scale) / 1024**3
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def _extract_size_gib(value: Any) -> float:
|
|
285
|
+
if not value:
|
|
286
|
+
return 0.0
|
|
287
|
+
text = str(value)
|
|
288
|
+
for part in text.split(","):
|
|
289
|
+
if "size=" in part:
|
|
290
|
+
token = part.split("=", 1)[1]
|
|
291
|
+
return _size_token_to_gib(token)
|
|
292
|
+
return _size_token_to_gib(text)
|
|
293
|
+
|
|
294
|
+
|
|
262
295
|
def _extract_storage(value: Any) -> str:
|
|
263
296
|
if not value:
|
|
264
297
|
return "unknown"
|
|
265
|
-
text = str(value)
|
|
266
|
-
if
|
|
267
|
-
return "unknown"
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
298
|
+
text = str(value)
|
|
299
|
+
if ":" in text:
|
|
300
|
+
return text.split(":", 1)[0].strip() or "unknown"
|
|
301
|
+
return text.strip() or "unknown"
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def _storage_from_lxc(cfg: Dict[str, Any], entry: Dict[str, Any]) -> str:
|
|
305
|
+
rootfs = cfg.get("rootfs") or entry.get("rootfs")
|
|
306
|
+
storage = _extract_storage(rootfs)
|
|
307
|
+
if storage != "unknown":
|
|
308
|
+
return storage
|
|
309
|
+
for idx in range(0, 10):
|
|
310
|
+
mp_value = cfg.get(f"mp{idx}")
|
|
311
|
+
storage = _extract_storage(mp_value)
|
|
312
|
+
if storage != "unknown":
|
|
313
|
+
return storage
|
|
314
|
+
return "unknown"
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def _storage_from_qemu(cfg: Dict[str, Any]) -> str:
|
|
318
|
+
preferred_keys: List[str] = []
|
|
319
|
+
for prefix in ("scsi", "virtio", "sata", "ide"):
|
|
320
|
+
preferred_keys.extend(f"{prefix}{idx}" for idx in range(0, 6))
|
|
321
|
+
seen: Set[str] = set()
|
|
322
|
+
for key in preferred_keys:
|
|
323
|
+
value = cfg.get(key)
|
|
324
|
+
if value is None:
|
|
325
|
+
continue
|
|
326
|
+
seen.add(key)
|
|
327
|
+
text = str(value)
|
|
328
|
+
if "media=cdrom" in text or "cloudinit" in text:
|
|
329
|
+
continue
|
|
330
|
+
storage = _extract_storage(text)
|
|
331
|
+
if storage != "unknown":
|
|
332
|
+
return storage
|
|
333
|
+
for key in sorted(cfg.keys()):
|
|
334
|
+
if key in seen:
|
|
335
|
+
continue
|
|
336
|
+
if not any(key.startswith(prefix) for prefix in ("scsi", "virtio", "sata", "ide")):
|
|
337
|
+
continue
|
|
338
|
+
value = cfg.get(key)
|
|
339
|
+
if value is None:
|
|
340
|
+
continue
|
|
341
|
+
text = str(value)
|
|
342
|
+
if "media=cdrom" in text or "cloudinit" in text:
|
|
343
|
+
continue
|
|
344
|
+
storage = _extract_storage(text)
|
|
345
|
+
if storage != "unknown":
|
|
346
|
+
return storage
|
|
347
|
+
for key in ("efidisk0", "tpmstate0"):
|
|
348
|
+
storage = _extract_storage(cfg.get(key))
|
|
349
|
+
if storage != "unknown":
|
|
350
|
+
return storage
|
|
351
|
+
return "unknown"
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def _primary_lxc_disk(cfg: Dict[str, Any], entry: Dict[str, Any]) -> str:
|
|
355
|
+
return str(cfg.get("rootfs") or entry.get("rootfs") or "")
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def _primary_qemu_disk(cfg: Dict[str, Any]) -> str:
|
|
359
|
+
preferred_keys: List[str] = []
|
|
360
|
+
for prefix in ("scsi", "virtio", "sata", "ide"):
|
|
361
|
+
preferred_keys.extend(f"{prefix}{idx}" for idx in range(0, 6))
|
|
362
|
+
seen: Set[str] = set()
|
|
363
|
+
for key in preferred_keys:
|
|
364
|
+
value = cfg.get(key)
|
|
365
|
+
if value is None:
|
|
366
|
+
continue
|
|
367
|
+
seen.add(key)
|
|
368
|
+
text = str(value)
|
|
369
|
+
if "media=cdrom" in text or "cloudinit" in text:
|
|
370
|
+
continue
|
|
371
|
+
return text
|
|
372
|
+
for key in sorted(cfg.keys()):
|
|
373
|
+
if key in seen:
|
|
374
|
+
continue
|
|
375
|
+
if not any(key.startswith(prefix) for prefix in ("scsi", "virtio", "sata", "ide")):
|
|
376
|
+
continue
|
|
377
|
+
value = cfg.get(key)
|
|
378
|
+
if value is None:
|
|
379
|
+
continue
|
|
380
|
+
text = str(value)
|
|
381
|
+
if "media=cdrom" in text or "cloudinit" in text:
|
|
382
|
+
continue
|
|
383
|
+
return text
|
|
384
|
+
return ""
|
|
271
385
|
|
|
272
386
|
|
|
273
|
-
def
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
387
|
+
def _pick_storage(kind: str, cfg: Dict[str, Any], entry: Dict[str, Any]) -> str:
|
|
388
|
+
storage = _extract_storage(cfg.get("storage") or entry.get("storage"))
|
|
389
|
+
if storage != "unknown":
|
|
390
|
+
return storage
|
|
391
|
+
if kind == "lxc":
|
|
392
|
+
return _storage_from_lxc(cfg, entry)
|
|
393
|
+
return _storage_from_qemu(cfg)
|
|
394
|
+
|
|
395
|
+
|
|
396
|
+
def _pick_disk_gib(kind: str, cfg: Dict[str, Any], entry: Dict[str, Any]) -> float:
|
|
397
|
+
if kind == "lxc":
|
|
398
|
+
size = _extract_size_gib(_primary_lxc_disk(cfg, entry))
|
|
399
|
+
if size:
|
|
400
|
+
return size
|
|
401
|
+
else:
|
|
402
|
+
size = _extract_size_gib(_primary_qemu_disk(cfg))
|
|
403
|
+
if size:
|
|
404
|
+
return size
|
|
405
|
+
for candidate in (entry.get("maxdisk"), entry.get("disk")):
|
|
406
|
+
if candidate in {None, 0}:
|
|
407
|
+
continue
|
|
408
|
+
return _normalize_bytes(candidate) / 1024**3
|
|
409
|
+
cfg_disk = cfg.get("disk")
|
|
410
|
+
if cfg_disk not in (None, 0):
|
|
411
|
+
return _normalize_bytes(cfg_disk) / 1024**3
|
|
412
|
+
return 0.0
|
|
277
413
|
|
|
278
414
|
|
|
279
415
|
def _parse_bool_flag(value: Any) -> bool:
|
|
@@ -475,44 +611,16 @@ def _extract_host_totals(node_status: Dict[str, Any] | None) -> Tuple[Optional[i
|
|
|
475
611
|
return host_ram, host_disk, host_cpu
|
|
476
612
|
|
|
477
613
|
|
|
478
|
-
def _parse_disk_reference(value: Any) -> Tuple[str | None, int]:
|
|
479
|
-
if not value:
|
|
480
|
-
return None, 0
|
|
481
|
-
text = str(value)
|
|
482
|
-
primary = text.split(",", 1)[0]
|
|
483
|
-
if ":" not in primary:
|
|
484
|
-
return primary.strip() or None, 0
|
|
485
|
-
storage_name, size_part = primary.split(":", 1)
|
|
486
|
-
storage_name = storage_name.strip() or None
|
|
487
|
-
size_text = size_part.strip()
|
|
488
|
-
if not size_text:
|
|
489
|
-
return storage_name, 0
|
|
490
|
-
unit = size_text[-1].upper()
|
|
491
|
-
number = size_text[:-1] if unit in {"G", "M"} else size_text
|
|
492
|
-
try:
|
|
493
|
-
value_num = float(number)
|
|
494
|
-
except ValueError:
|
|
495
|
-
return storage_name, 0
|
|
496
|
-
if unit == "M":
|
|
497
|
-
gib = value_num / 1024.0
|
|
498
|
-
else:
|
|
499
|
-
gib = value_num
|
|
500
|
-
return storage_name, int(round(gib))
|
|
501
|
-
|
|
502
|
-
|
|
503
614
|
def _build_unmanaged_container_entry(
|
|
504
615
|
ct: Dict[str, Any],
|
|
505
616
|
cfg: Dict[str, Any],
|
|
506
617
|
vmid: str,
|
|
507
618
|
default_storage: str | None,
|
|
508
619
|
*,
|
|
509
|
-
disk_gib_override: int | None = None,
|
|
510
|
-
storage_override: str | None = None,
|
|
511
620
|
entry_type: str = "lxc",
|
|
512
621
|
) -> Dict[str, Any]:
|
|
513
622
|
ram_mib = _to_int(cfg.get("memory")) or _bytes_to_mib(ct.get("maxmem"))
|
|
514
|
-
|
|
515
|
-
disk_gib = disk_gib_override if disk_gib_override is not None else _bytes_to_gib(disk_source)
|
|
623
|
+
disk_gib = int(round(_pick_disk_gib(entry_type, cfg, ct)))
|
|
516
624
|
cpu_share = _to_float(
|
|
517
625
|
cfg.get("cpulimit")
|
|
518
626
|
or cfg.get("cpus")
|
|
@@ -521,10 +629,7 @@ def _build_unmanaged_container_entry(
|
|
|
521
629
|
or ct.get("cpu")
|
|
522
630
|
)
|
|
523
631
|
hostname = ct.get("name") or cfg.get("hostname") or f"ct{vmid}"
|
|
524
|
-
|
|
525
|
-
storage_override or cfg.get("storage") or ct.get("storage") or ct.get("rootfs")
|
|
526
|
-
)
|
|
527
|
-
storage = _extract_storage(storage_source)
|
|
632
|
+
storage = _pick_storage(entry_type, cfg, ct)
|
|
528
633
|
status = (ct.get("status") or "unknown").lower()
|
|
529
634
|
reserved = _parse_bool_flag(cfg.get("onboot"))
|
|
530
635
|
storage_matches_default = _storage_matches_default(storage, default_storage)
|
|
@@ -563,33 +668,10 @@ def _get_storage_snapshot(proxmox: Any, node: str, storage_name: str | None) ->
|
|
|
563
668
|
}
|
|
564
669
|
|
|
565
670
|
|
|
566
|
-
def _extract_qemu_disk_info(cfg: Dict[str, Any]) -> Tuple[str | None, int]:
|
|
567
|
-
disk_keys = sorted(
|
|
568
|
-
key
|
|
569
|
-
for key in cfg.keys()
|
|
570
|
-
if (
|
|
571
|
-
key.startswith("ide")
|
|
572
|
-
or key.startswith("sata")
|
|
573
|
-
or key.startswith("scsi")
|
|
574
|
-
or key.startswith("virtio")
|
|
575
|
-
or key.startswith("efidisk")
|
|
576
|
-
or key.startswith("raid")
|
|
577
|
-
)
|
|
578
|
-
and cfg.get(key)
|
|
579
|
-
)
|
|
580
|
-
for key in disk_keys:
|
|
581
|
-
storage_name, size_gib = _parse_disk_reference(cfg.get(key))
|
|
582
|
-
if storage_name or size_gib:
|
|
583
|
-
return storage_name, size_gib
|
|
584
|
-
return None, 0
|
|
585
|
-
|
|
586
|
-
|
|
587
671
|
def _storage_matches_default(storage_name: Any, default_storage: str | None) -> bool:
|
|
588
672
|
if not default_storage:
|
|
589
673
|
return True
|
|
590
|
-
|
|
591
|
-
normalized_default = _normalize_storage_name(_extract_storage(default_storage))
|
|
592
|
-
return normalized_storage == normalized_default
|
|
674
|
+
return _normalize_storage_name(storage_name) == _normalize_storage_name(default_storage)
|
|
593
675
|
|
|
594
676
|
|
|
595
677
|
def _build_managed_containers_summary(
|
|
@@ -732,15 +814,12 @@ def _get_managed_containers_summary(force: bool = False) -> Dict[str, Any]:
|
|
|
732
814
|
description = (cfg.get("description") or "")
|
|
733
815
|
if MANAGED_MARKER in description:
|
|
734
816
|
continue
|
|
735
|
-
storage_name, disk_gib_override = _extract_qemu_disk_info(cfg)
|
|
736
817
|
unmanaged.append(
|
|
737
818
|
_build_unmanaged_container_entry(
|
|
738
819
|
vm,
|
|
739
820
|
cfg,
|
|
740
821
|
vmid_key,
|
|
741
822
|
default_storage,
|
|
742
|
-
disk_gib_override=disk_gib_override,
|
|
743
|
-
storage_override=storage_name,
|
|
744
823
|
entry_type="qemu",
|
|
745
824
|
)
|
|
746
825
|
)
|
|
@@ -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=xQIvOHyr77yXKzNXQJL1rE01nrJdvUnM7LX3jaSU684,721
|
|
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=5XUUzr24bs-QOMpuVPq071ZDAmhadKiMs2E-wO62kMw,86709
|
|
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.16.
|
|
68
|
+
portacode-1.4.16.dev10.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.16.
|
|
95
|
-
portacode-1.4.16.
|
|
96
|
-
portacode-1.4.16.
|
|
97
|
-
portacode-1.4.16.
|
|
98
|
-
portacode-1.4.16.
|
|
94
|
+
portacode-1.4.16.dev10.dist-info/METADATA,sha256=CYVCSXxYLiRseul0OVvOLRWWp2-Lv1u737bm-qT1hVk,13052
|
|
95
|
+
portacode-1.4.16.dev10.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
96
|
+
portacode-1.4.16.dev10.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
97
|
+
portacode-1.4.16.dev10.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
98
|
+
portacode-1.4.16.dev10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|