portacode 1.4.15.dev6__py3-none-any.whl → 1.4.15.dev7__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 +136 -36
- {portacode-1.4.15.dev6.dist-info → portacode-1.4.15.dev7.dist-info}/METADATA +1 -1
- {portacode-1.4.15.dev6.dist-info → portacode-1.4.15.dev7.dist-info}/RECORD +8 -8
- {portacode-1.4.15.dev6.dist-info → portacode-1.4.15.dev7.dist-info}/WHEEL +1 -1
- {portacode-1.4.15.dev6.dist-info → portacode-1.4.15.dev7.dist-info}/entry_points.txt +0 -0
- {portacode-1.4.15.dev6.dist-info → portacode-1.4.15.dev7.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.4.15.dev6.dist-info → portacode-1.4.15.dev7.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.15.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 4, 15, '
|
|
31
|
+
__version__ = version = '1.4.15.dev7'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 4, 15, 'dev7')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import asyncio
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
|
+
import math
|
|
8
9
|
import os
|
|
9
10
|
import secrets
|
|
10
11
|
import shlex
|
|
@@ -436,48 +437,119 @@ def _friendly_step_label(step_name: str) -> str:
|
|
|
436
437
|
return normalized.capitalize()
|
|
437
438
|
|
|
438
439
|
|
|
440
|
+
_PACKAGE_MANAGER_PROFILES: Dict[str, Dict[str, Any]] = {
|
|
441
|
+
"apt": {
|
|
442
|
+
"update_cmd": "apt-get update -y",
|
|
443
|
+
"update_step_name": "apt_update",
|
|
444
|
+
"install_cmd": "apt-get install -y python3 python3-pip sudo --fix-missing",
|
|
445
|
+
"install_step_name": "install_deps",
|
|
446
|
+
"update_retries": 4,
|
|
447
|
+
"install_retries": 5,
|
|
448
|
+
},
|
|
449
|
+
"dnf": {
|
|
450
|
+
"update_cmd": "dnf check-update || true",
|
|
451
|
+
"update_step_name": "dnf_update",
|
|
452
|
+
"install_cmd": "dnf install -y python3 python3-pip sudo",
|
|
453
|
+
"install_step_name": "install_deps",
|
|
454
|
+
"update_retries": 3,
|
|
455
|
+
"install_retries": 5,
|
|
456
|
+
},
|
|
457
|
+
"yum": {
|
|
458
|
+
"update_cmd": "yum makecache",
|
|
459
|
+
"update_step_name": "yum_update",
|
|
460
|
+
"install_cmd": "yum install -y python3 python3-pip sudo",
|
|
461
|
+
"install_step_name": "install_deps",
|
|
462
|
+
"update_retries": 3,
|
|
463
|
+
"install_retries": 5,
|
|
464
|
+
},
|
|
465
|
+
"apk": {
|
|
466
|
+
"update_cmd": "apk update",
|
|
467
|
+
"update_step_name": "apk_update",
|
|
468
|
+
"install_cmd": "apk add --no-cache python3 py3-pip sudo",
|
|
469
|
+
"install_step_name": "install_deps",
|
|
470
|
+
"update_retries": 3,
|
|
471
|
+
"install_retries": 5,
|
|
472
|
+
},
|
|
473
|
+
"pacman": {
|
|
474
|
+
"update_cmd": "pacman -Sy --noconfirm",
|
|
475
|
+
"update_step_name": "pacman_update",
|
|
476
|
+
"install_cmd": "pacman -S --noconfirm python python-pip sudo",
|
|
477
|
+
"install_step_name": "install_deps",
|
|
478
|
+
"update_retries": 3,
|
|
479
|
+
"install_retries": 5,
|
|
480
|
+
},
|
|
481
|
+
"zypper": {
|
|
482
|
+
"update_cmd": "zypper refresh",
|
|
483
|
+
"update_step_name": "zypper_update",
|
|
484
|
+
"install_cmd": "zypper install -y python3 python3-pip sudo",
|
|
485
|
+
"install_step_name": "install_deps",
|
|
486
|
+
"update_retries": 3,
|
|
487
|
+
"install_retries": 5,
|
|
488
|
+
},
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
_UPDATE_RETRY_ON = [
|
|
492
|
+
"Temporary failure resolving",
|
|
493
|
+
"Could not resolve",
|
|
494
|
+
"Failed to fetch",
|
|
495
|
+
]
|
|
496
|
+
|
|
497
|
+
_INSTALL_RETRY_ON = [
|
|
498
|
+
"lock-frontend",
|
|
499
|
+
"Unable to acquire the dpkg frontend lock",
|
|
500
|
+
"Temporary failure resolving",
|
|
501
|
+
"Could not resolve",
|
|
502
|
+
"Failed to fetch",
|
|
503
|
+
]
|
|
504
|
+
|
|
505
|
+
|
|
439
506
|
def _build_bootstrap_steps(
|
|
440
507
|
user: str,
|
|
441
508
|
password: str,
|
|
442
509
|
ssh_key: str,
|
|
443
510
|
include_portacode_connect: bool = True,
|
|
511
|
+
package_manager: str = "apt",
|
|
444
512
|
) -> List[Dict[str, Any]]:
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
"
|
|
453
|
-
"
|
|
454
|
-
"
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
"
|
|
464
|
-
"
|
|
465
|
-
"
|
|
466
|
-
"
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
513
|
+
profile = _PACKAGE_MANAGER_PROFILES.get(package_manager, _PACKAGE_MANAGER_PROFILES["apt"])
|
|
514
|
+
steps: List[Dict[str, Any]] = []
|
|
515
|
+
update_cmd = profile.get("update_cmd")
|
|
516
|
+
if update_cmd:
|
|
517
|
+
steps.append(
|
|
518
|
+
{
|
|
519
|
+
"name": profile.get("update_step_name", "package_update"),
|
|
520
|
+
"cmd": update_cmd,
|
|
521
|
+
"retries": profile.get("update_retries", 3),
|
|
522
|
+
"retry_delay_s": 5,
|
|
523
|
+
"retry_on": _UPDATE_RETRY_ON,
|
|
524
|
+
}
|
|
525
|
+
)
|
|
526
|
+
install_cmd = profile.get("install_cmd")
|
|
527
|
+
if install_cmd:
|
|
528
|
+
steps.append(
|
|
529
|
+
{
|
|
530
|
+
"name": profile.get("install_step_name", "install_deps"),
|
|
531
|
+
"cmd": install_cmd,
|
|
532
|
+
"retries": profile.get("install_retries", 5),
|
|
533
|
+
"retry_delay_s": 5,
|
|
534
|
+
"retry_on": _INSTALL_RETRY_ON,
|
|
535
|
+
}
|
|
536
|
+
)
|
|
537
|
+
steps.extend(
|
|
538
|
+
[
|
|
539
|
+
{"name": "user_exists", "cmd": f"id -u {user} >/dev/null 2>&1 || adduser --disabled-password --gecos '' {user}", "retries": 0},
|
|
540
|
+
{"name": "add_sudo", "cmd": f"usermod -aG sudo {user}", "retries": 0},
|
|
541
|
+
]
|
|
542
|
+
)
|
|
473
543
|
if password:
|
|
474
544
|
steps.append({"name": "set_password", "cmd": f"echo '{user}:{password}' | chpasswd", "retries": 0})
|
|
475
545
|
if ssh_key:
|
|
476
|
-
steps.append(
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
546
|
+
steps.append(
|
|
547
|
+
{
|
|
548
|
+
"name": "add_ssh_key",
|
|
549
|
+
"cmd": f"install -d -m 700 /home/{user}/.ssh && echo '{ssh_key}' >> /home/{user}/.ssh/authorized_keys && chown -R {user}:{user} /home/{user}/.ssh",
|
|
550
|
+
"retries": 0,
|
|
551
|
+
}
|
|
552
|
+
)
|
|
481
553
|
steps.extend(
|
|
482
554
|
[
|
|
483
555
|
{"name": "pip_upgrade", "cmd": "python3 -m pip install --upgrade pip", "retries": 0},
|
|
@@ -489,6 +561,24 @@ def _build_bootstrap_steps(
|
|
|
489
561
|
return steps
|
|
490
562
|
|
|
491
563
|
|
|
564
|
+
def _detect_package_manager(vmid: int) -> str:
|
|
565
|
+
candidates = [
|
|
566
|
+
("apt", "apt-get"),
|
|
567
|
+
("dnf", "dnf"),
|
|
568
|
+
("yum", "yum"),
|
|
569
|
+
("apk", "apk"),
|
|
570
|
+
("pacman", "pacman"),
|
|
571
|
+
("zypper", "zypper"),
|
|
572
|
+
]
|
|
573
|
+
for name, binary in candidates:
|
|
574
|
+
res = _run_pct(vmid, f"command -v {binary} >/dev/null 2>&1")
|
|
575
|
+
if res.get("returncode") == 0:
|
|
576
|
+
logger.debug("Detected package manager %s inside container %s", name, vmid)
|
|
577
|
+
return name
|
|
578
|
+
logger.warning("Unable to detect package manager inside container %s; defaulting to apt", vmid)
|
|
579
|
+
return "apt"
|
|
580
|
+
|
|
581
|
+
|
|
492
582
|
def _get_storage_type(storages: Iterable[Dict[str, Any]], storage_name: str) -> str:
|
|
493
583
|
for entry in storages:
|
|
494
584
|
if entry.get("storage") == storage_name:
|
|
@@ -966,7 +1056,16 @@ def _bootstrap_portacode(
|
|
|
966
1056
|
total_steps: Optional[int] = None,
|
|
967
1057
|
default_public_key: Optional[str] = None,
|
|
968
1058
|
) -> Tuple[str, List[Dict[str, Any]]]:
|
|
969
|
-
|
|
1059
|
+
if steps is not None:
|
|
1060
|
+
actual_steps = steps
|
|
1061
|
+
else:
|
|
1062
|
+
package_manager = _detect_package_manager(vmid)
|
|
1063
|
+
actual_steps = _build_bootstrap_steps(
|
|
1064
|
+
user,
|
|
1065
|
+
password,
|
|
1066
|
+
ssh_key,
|
|
1067
|
+
package_manager=package_manager,
|
|
1068
|
+
)
|
|
970
1069
|
results, ok = _run_setup_steps(
|
|
971
1070
|
vmid,
|
|
972
1071
|
actual_steps,
|
|
@@ -1121,7 +1220,7 @@ def _instantiate_container(proxmox: Any, node: str, payload: Dict[str, Any]) ->
|
|
|
1121
1220
|
memory=int(payload["ram_mib"]),
|
|
1122
1221
|
swap=int(payload.get("swap_mb", 0)),
|
|
1123
1222
|
cores=max(int(payload.get("cores", 1)), 1),
|
|
1124
|
-
|
|
1223
|
+
cpulimit=float(payload.get("cpulimit", payload.get("cpus", 1))),
|
|
1125
1224
|
net0=payload["net0"],
|
|
1126
1225
|
unprivileged=int(payload.get("unprivileged", 1)),
|
|
1127
1226
|
description=payload.get("description", MANAGED_MARKER),
|
|
@@ -1235,7 +1334,8 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
1235
1334
|
proxmox = _connect_proxmox(config)
|
|
1236
1335
|
node = config.get("node") or DEFAULT_NODE_NAME
|
|
1237
1336
|
payload = _build_container_payload(message, config)
|
|
1238
|
-
payload["
|
|
1337
|
+
payload["cpulimit"] = float(payload["cpus"])
|
|
1338
|
+
payload["cores"] = int(max(math.ceil(payload["cpus"]), 1))
|
|
1239
1339
|
payload["memory"] = int(payload["ram_mib"])
|
|
1240
1340
|
payload["node"] = node
|
|
1241
1341
|
logger.debug(
|
|
@@ -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=Xx0Po1xBg9CoeugBu19tIDntOjkrKAyq9NOKq8YEY_w,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=GXPyDcdwgtTfQyw7msAARAmHGun-p8GJOdtV0LL5iuQ,65513
|
|
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.15.
|
|
68
|
+
portacode-1.4.15.dev7.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.15.
|
|
95
|
-
portacode-1.4.15.
|
|
96
|
-
portacode-1.4.15.
|
|
97
|
-
portacode-1.4.15.
|
|
98
|
-
portacode-1.4.15.
|
|
94
|
+
portacode-1.4.15.dev7.dist-info/METADATA,sha256=YHefdl_WhByeUv5ELxOcmpCdhID0lj04wJTl57e3O8A,13051
|
|
95
|
+
portacode-1.4.15.dev7.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
96
|
+
portacode-1.4.15.dev7.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
97
|
+
portacode-1.4.15.dev7.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
98
|
+
portacode-1.4.15.dev7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|