portacode 1.4.11.dev6__py3-none-any.whl → 1.4.11.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/WEBSOCKET_PROTOCOL.md +26 -0
- portacode/connection/handlers/__init__.py +2 -0
- portacode/connection/handlers/proxmox_infra.py +204 -69
- portacode/connection/terminal.py +2 -0
- {portacode-1.4.11.dev6.dist-info → portacode-1.4.11.dev7.dist-info}/METADATA +1 -1
- {portacode-1.4.11.dev6.dist-info → portacode-1.4.11.dev7.dist-info}/RECORD +11 -11
- {portacode-1.4.11.dev6.dist-info → portacode-1.4.11.dev7.dist-info}/WHEEL +0 -0
- {portacode-1.4.11.dev6.dist-info → portacode-1.4.11.dev7.dist-info}/entry_points.txt +0 -0
- {portacode-1.4.11.dev6.dist-info → portacode-1.4.11.dev7.dist-info}/licenses/LICENSE +0 -0
- {portacode-1.4.11.dev6.dist-info → portacode-1.4.11.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.11.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 4, 11, '
|
|
31
|
+
__version__ = version = '1.4.11.dev7'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 4, 11, 'dev7')
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
|
@@ -396,6 +396,32 @@ Sent intermittently while `create_proxmox_container` is executing so callers can
|
|
|
396
396
|
* `details` (object, optional): Contains `attempt` (if retries were needed) and `error_summary` when a step fails.
|
|
397
397
|
* `request_id` (string, optional): Mirrors the request ID from the incoming `create_proxmox_container` payload when available.
|
|
398
398
|
|
|
399
|
+
### `start_portacode_service`
|
|
400
|
+
|
|
401
|
+
Runs `sudo portacode service install` inside the container after the dashboard has created the corresponding Device record with the supplied public key.
|
|
402
|
+
|
|
403
|
+
**Payload Fields:**
|
|
404
|
+
|
|
405
|
+
* `ctid` (string, required): Container ID target.
|
|
406
|
+
* `step_index` (integer, required): Next step index to render inside `proxmox_container_progress`.
|
|
407
|
+
* `total_steps` (integer, required): The overall total number of steps (including lifecycle, bootstrap, and service installation).
|
|
408
|
+
|
|
409
|
+
**Responses:**
|
|
410
|
+
|
|
411
|
+
* Emits additional [`proxmox_container_progress`](#proxmox_container_progress-event) events to report the authentication and service-install steps.
|
|
412
|
+
* On success, emits a [`proxmox_service_started`](#proxmox_service_started-event).
|
|
413
|
+
* On failure, emits a generic [`error`](#error) event.
|
|
414
|
+
|
|
415
|
+
### `proxmox_service_started`
|
|
416
|
+
|
|
417
|
+
Indicates that `portacode service install` finished successfully inside a managed container.
|
|
418
|
+
|
|
419
|
+
**Event Fields:**
|
|
420
|
+
|
|
421
|
+
* `success` (boolean): True when the install succeeded.
|
|
422
|
+
* `message` (string): Success summary (e.g., `Portacode service install completed`).
|
|
423
|
+
* `ctid` (string): Container ID.
|
|
424
|
+
|
|
399
425
|
### `clock_sync_request`
|
|
400
426
|
|
|
401
427
|
Internal event that devices send to the gateway to request the authoritative server timestamp (used for adjusting `portacode.utils.ntp_clock`). The gateway responds immediately with [`clock_sync_response`](#clock_sync_response).
|
|
@@ -45,6 +45,7 @@ from .proxmox_infra import (
|
|
|
45
45
|
ConfigureProxmoxInfraHandler,
|
|
46
46
|
CreateProxmoxContainerHandler,
|
|
47
47
|
RevertProxmoxInfraHandler,
|
|
48
|
+
StartPortacodeServiceHandler,
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
__all__ = [
|
|
@@ -84,6 +85,7 @@ __all__ = [
|
|
|
84
85
|
"ProjectStateGitUnstageHandler",
|
|
85
86
|
"ProjectStateGitRevertHandler",
|
|
86
87
|
"ProjectStateGitCommitHandler",
|
|
88
|
+
"StartPortacodeServiceHandler",
|
|
87
89
|
"UpdatePortacodeHandler",
|
|
88
90
|
"RevertProxmoxInfraHandler",
|
|
89
91
|
]
|
|
@@ -6,6 +6,7 @@ import asyncio
|
|
|
6
6
|
import json
|
|
7
7
|
import logging
|
|
8
8
|
import os
|
|
9
|
+
import secrets
|
|
9
10
|
import shutil
|
|
10
11
|
import stat
|
|
11
12
|
import subprocess
|
|
@@ -43,6 +44,53 @@ UNIT_DIR = Path("/etc/systemd/system")
|
|
|
43
44
|
ProgressCallback = Callable[[int, int, Dict[str, Any], str, Optional[Dict[str, Any]]], None]
|
|
44
45
|
|
|
45
46
|
|
|
47
|
+
def _emit_progress_event(
|
|
48
|
+
handler: SyncHandler,
|
|
49
|
+
*,
|
|
50
|
+
step_index: int,
|
|
51
|
+
total_steps: int,
|
|
52
|
+
step_name: str,
|
|
53
|
+
step_label: str,
|
|
54
|
+
status: str,
|
|
55
|
+
message: str,
|
|
56
|
+
phase: str,
|
|
57
|
+
request_id: Optional[str],
|
|
58
|
+
details: Optional[Dict[str, Any]] = None,
|
|
59
|
+
) -> None:
|
|
60
|
+
loop = handler.context.get("event_loop")
|
|
61
|
+
if not loop or loop.is_closed():
|
|
62
|
+
logger.debug(
|
|
63
|
+
"progress event skipped (no event loop) step=%s status=%s",
|
|
64
|
+
step_name,
|
|
65
|
+
status,
|
|
66
|
+
)
|
|
67
|
+
return
|
|
68
|
+
|
|
69
|
+
payload: Dict[str, Any] = {
|
|
70
|
+
"event": "proxmox_container_progress",
|
|
71
|
+
"step_name": step_name,
|
|
72
|
+
"step_label": step_label,
|
|
73
|
+
"status": status,
|
|
74
|
+
"phase": phase,
|
|
75
|
+
"step_index": step_index,
|
|
76
|
+
"total_steps": total_steps,
|
|
77
|
+
"message": message,
|
|
78
|
+
}
|
|
79
|
+
if request_id:
|
|
80
|
+
payload["request_id"] = request_id
|
|
81
|
+
if details:
|
|
82
|
+
payload["details"] = details
|
|
83
|
+
|
|
84
|
+
future = asyncio.run_coroutine_threadsafe(handler.send_response(payload), loop)
|
|
85
|
+
future.add_done_callback(
|
|
86
|
+
lambda fut: logger.warning(
|
|
87
|
+
"Failed to emit progress event for %s: %s", step_name, fut.exception()
|
|
88
|
+
)
|
|
89
|
+
if fut.exception()
|
|
90
|
+
else None
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
46
94
|
def _call_subprocess(cmd: List[str], **kwargs: Any) -> subprocess.CompletedProcess[str]:
|
|
47
95
|
env = os.environ.copy()
|
|
48
96
|
env.setdefault("DEBIAN_FRONTEND", "noninteractive")
|
|
@@ -251,7 +299,9 @@ def _format_rootfs(storage: str, disk_gib: int, storage_type: str) -> str:
|
|
|
251
299
|
def _get_provisioning_user_info(message: Dict[str, Any]) -> Tuple[str, str, str]:
|
|
252
300
|
user = (message.get("username") or "svcuser").strip() if message else "svcuser"
|
|
253
301
|
user = user or "svcuser"
|
|
254
|
-
password = message.get("password")
|
|
302
|
+
password = message.get("password")
|
|
303
|
+
if not password:
|
|
304
|
+
password = secrets.token_urlsafe(10)
|
|
255
305
|
ssh_key = (message.get("ssh_key") or "").strip() if message else ""
|
|
256
306
|
return user, password, ssh_key
|
|
257
307
|
|
|
@@ -380,6 +430,13 @@ def _write_container_record(vmid: int, payload: Dict[str, Any]) -> None:
|
|
|
380
430
|
path.write_text(json.dumps(payload, indent=2), encoding="utf-8")
|
|
381
431
|
|
|
382
432
|
|
|
433
|
+
def _read_container_record(vmid: int) -> Dict[str, Any]:
|
|
434
|
+
path = CONTAINERS_DIR / f"ct-{vmid}.json"
|
|
435
|
+
if not path.exists():
|
|
436
|
+
raise FileNotFoundError(f"Container record {path} missing")
|
|
437
|
+
return json.loads(path.read_text(encoding="utf-8"))
|
|
438
|
+
|
|
439
|
+
|
|
383
440
|
def _build_container_payload(message: Dict[str, Any], config: Dict[str, Any]) -> Dict[str, Any]:
|
|
384
441
|
templates = config.get("templates") or []
|
|
385
442
|
default_template = templates[0] if templates else ""
|
|
@@ -428,10 +485,10 @@ def _connect_proxmox(config: Dict[str, Any]) -> Any:
|
|
|
428
485
|
)
|
|
429
486
|
|
|
430
487
|
|
|
431
|
-
def _run_pct(vmid: int, cmd: str) -> Dict[str, Any]:
|
|
488
|
+
def _run_pct(vmid: int, cmd: str, input_text: Optional[str] = None) -> Dict[str, Any]:
|
|
432
489
|
full = ["pct", "exec", str(vmid), "--", "bash", "-lc", cmd]
|
|
433
490
|
start = time.time()
|
|
434
|
-
proc = subprocess.run(full, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
|
491
|
+
proc = subprocess.run(full, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input_text)
|
|
435
492
|
return {
|
|
436
493
|
"cmd": cmd,
|
|
437
494
|
"returncode": proc.returncode,
|
|
@@ -560,6 +617,8 @@ def _run_setup_steps(
|
|
|
560
617
|
continue
|
|
561
618
|
|
|
562
619
|
attempts = 0
|
|
620
|
+
retry_on = step.get("retry_on", [])
|
|
621
|
+
max_attempts = step.get("retries", 0) + 1
|
|
563
622
|
while True:
|
|
564
623
|
attempts += 1
|
|
565
624
|
res = _run_pct(vmid, step["cmd"])
|
|
@@ -572,14 +631,21 @@ def _run_setup_steps(
|
|
|
572
631
|
if progress_callback:
|
|
573
632
|
progress_callback(step_index, computed_total, step, "completed", res)
|
|
574
633
|
break
|
|
634
|
+
|
|
635
|
+
will_retry = False
|
|
636
|
+
if attempts < max_attempts and retry_on:
|
|
637
|
+
stderr_stdout = (res.get("stderr", "") + res.get("stdout", ""))
|
|
638
|
+
if any(tok in stderr_stdout for tok in retry_on):
|
|
639
|
+
will_retry = True
|
|
640
|
+
|
|
575
641
|
if progress_callback:
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
if any(tok in (res.get("stderr", "") + res.get("stdout", "")) for tok in retry_on):
|
|
642
|
+
status = "retrying" if will_retry else "failed"
|
|
643
|
+
progress_callback(step_index, computed_total, step, status, res)
|
|
644
|
+
|
|
645
|
+
if will_retry:
|
|
581
646
|
time.sleep(step.get("retry_delay_s", 3))
|
|
582
647
|
continue
|
|
648
|
+
|
|
583
649
|
return results, False
|
|
584
650
|
return results, True
|
|
585
651
|
|
|
@@ -746,58 +812,12 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
746
812
|
def command_name(self) -> str:
|
|
747
813
|
return "create_proxmox_container"
|
|
748
814
|
|
|
749
|
-
def _emit_progress_event(
|
|
750
|
-
self,
|
|
751
|
-
*,
|
|
752
|
-
step_index: int,
|
|
753
|
-
total_steps: int,
|
|
754
|
-
step_name: str,
|
|
755
|
-
step_label: str,
|
|
756
|
-
status: str,
|
|
757
|
-
message: str,
|
|
758
|
-
phase: str,
|
|
759
|
-
request_id: Optional[str],
|
|
760
|
-
details: Optional[Dict[str, Any]] = None,
|
|
761
|
-
) -> None:
|
|
762
|
-
loop = self.context.get("event_loop")
|
|
763
|
-
if not loop or loop.is_closed():
|
|
764
|
-
logger.debug(
|
|
765
|
-
"progress event skipped (no event loop) step=%s status=%s",
|
|
766
|
-
step_name,
|
|
767
|
-
status,
|
|
768
|
-
)
|
|
769
|
-
return
|
|
770
|
-
|
|
771
|
-
payload: Dict[str, Any] = {
|
|
772
|
-
"event": "proxmox_container_progress",
|
|
773
|
-
"step_name": step_name,
|
|
774
|
-
"step_label": step_label,
|
|
775
|
-
"status": status,
|
|
776
|
-
"phase": phase,
|
|
777
|
-
"step_index": step_index,
|
|
778
|
-
"total_steps": total_steps,
|
|
779
|
-
"message": message,
|
|
780
|
-
}
|
|
781
|
-
if request_id:
|
|
782
|
-
payload["request_id"] = request_id
|
|
783
|
-
if details:
|
|
784
|
-
payload["details"] = details
|
|
785
|
-
|
|
786
|
-
future = asyncio.run_coroutine_threadsafe(self.send_response(payload), loop)
|
|
787
|
-
future.add_done_callback(
|
|
788
|
-
lambda fut: logger.warning(
|
|
789
|
-
"Failed to emit progress event for %s: %s", step_name, fut.exception()
|
|
790
|
-
)
|
|
791
|
-
if fut.exception()
|
|
792
|
-
else None
|
|
793
|
-
)
|
|
794
|
-
|
|
795
815
|
def execute(self, message: Dict[str, Any]) -> Dict[str, Any]:
|
|
796
816
|
logger.info("create_proxmox_container command received")
|
|
797
817
|
request_id = message.get("request_id")
|
|
798
818
|
bootstrap_user, bootstrap_password, bootstrap_ssh_key = _get_provisioning_user_info(message)
|
|
799
819
|
bootstrap_steps = _build_bootstrap_steps(bootstrap_user, bootstrap_password, bootstrap_ssh_key)
|
|
800
|
-
total_steps = 3 + len(bootstrap_steps)
|
|
820
|
+
total_steps = 3 + len(bootstrap_steps) + 2
|
|
801
821
|
current_step_index = 1
|
|
802
822
|
|
|
803
823
|
def _run_lifecycle_step(
|
|
@@ -809,7 +829,7 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
809
829
|
):
|
|
810
830
|
nonlocal current_step_index
|
|
811
831
|
step_index = current_step_index
|
|
812
|
-
|
|
832
|
+
_emit_progress_event(
|
|
813
833
|
step_index=step_index,
|
|
814
834
|
total_steps=total_steps,
|
|
815
835
|
step_name=step_name,
|
|
@@ -822,7 +842,7 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
822
842
|
try:
|
|
823
843
|
result = action()
|
|
824
844
|
except Exception as exc:
|
|
825
|
-
|
|
845
|
+
_emit_progress_event(
|
|
826
846
|
step_index=step_index,
|
|
827
847
|
total_steps=total_steps,
|
|
828
848
|
step_name=step_name,
|
|
@@ -834,7 +854,7 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
834
854
|
details={"error": str(exc)},
|
|
835
855
|
)
|
|
836
856
|
raise
|
|
837
|
-
|
|
857
|
+
_emit_progress_event(
|
|
838
858
|
step_index=step_index,
|
|
839
859
|
total_steps=total_steps,
|
|
840
860
|
step_name=step_name,
|
|
@@ -905,25 +925,33 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
905
925
|
_start_container_step,
|
|
906
926
|
)
|
|
907
927
|
|
|
908
|
-
def _bootstrap_progress_callback(
|
|
928
|
+
def _bootstrap_progress_callback(
|
|
929
|
+
step_index: int,
|
|
930
|
+
total: int,
|
|
931
|
+
step: Dict[str, Any],
|
|
932
|
+
status: str,
|
|
933
|
+
result: Optional[Dict[str, Any]],
|
|
934
|
+
):
|
|
909
935
|
label = step.get("display_name") or _friendly_step_label(step.get("name", "bootstrap"))
|
|
936
|
+
error_summary = (result or {}).get("error_summary") or (result or {}).get("error")
|
|
937
|
+
attempt = (result or {}).get("attempt")
|
|
910
938
|
if status == "in_progress":
|
|
911
939
|
message_text = f"{label} is running…"
|
|
912
940
|
elif status == "completed":
|
|
913
941
|
message_text = f"{label} completed."
|
|
942
|
+
elif status == "retrying":
|
|
943
|
+
attempt_desc = f" (attempt {attempt})" if attempt else ""
|
|
944
|
+
message_text = f"{label} failed{attempt_desc}; retrying…"
|
|
914
945
|
else:
|
|
915
|
-
summary = (result or {}).get("error_summary") or (result or {}).get("error")
|
|
916
946
|
message_text = f"{label} failed"
|
|
917
|
-
if
|
|
918
|
-
message_text += f": {
|
|
947
|
+
if error_summary:
|
|
948
|
+
message_text += f": {error_summary}"
|
|
919
949
|
details: Dict[str, Any] = {}
|
|
920
|
-
if
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
details["error_summary"] = summary_detail
|
|
926
|
-
self._emit_progress_event(
|
|
950
|
+
if attempt:
|
|
951
|
+
details["attempt"] = attempt
|
|
952
|
+
if error_summary:
|
|
953
|
+
details["error_summary"] = error_summary
|
|
954
|
+
_emit_progress_event(
|
|
927
955
|
step_index=step_index,
|
|
928
956
|
total_steps=total,
|
|
929
957
|
step_name=step.get("name", "bootstrap"),
|
|
@@ -945,6 +973,7 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
945
973
|
start_index=current_step_index,
|
|
946
974
|
total_steps=total_steps,
|
|
947
975
|
)
|
|
976
|
+
current_step_index += len(bootstrap_steps)
|
|
948
977
|
|
|
949
978
|
return {
|
|
950
979
|
"event": "proxmox_container_created",
|
|
@@ -965,6 +994,112 @@ class CreateProxmoxContainerHandler(SyncHandler):
|
|
|
965
994
|
}
|
|
966
995
|
|
|
967
996
|
|
|
997
|
+
class StartPortacodeServiceHandler(SyncHandler):
|
|
998
|
+
"""Start the Portacode service inside a newly created container."""
|
|
999
|
+
|
|
1000
|
+
@property
|
|
1001
|
+
def command_name(self) -> str:
|
|
1002
|
+
return "start_portacode_service"
|
|
1003
|
+
|
|
1004
|
+
def execute(self, message: Dict[str, Any]) -> Dict[str, Any]:
|
|
1005
|
+
ctid = message.get("ctid")
|
|
1006
|
+
if not ctid:
|
|
1007
|
+
raise ValueError("ctid is required")
|
|
1008
|
+
try:
|
|
1009
|
+
vmid = int(ctid)
|
|
1010
|
+
except ValueError:
|
|
1011
|
+
raise ValueError("ctid must be an integer")
|
|
1012
|
+
|
|
1013
|
+
record = _read_container_record(vmid)
|
|
1014
|
+
user = record.get("username")
|
|
1015
|
+
password = record.get("password")
|
|
1016
|
+
if not user or not password:
|
|
1017
|
+
raise RuntimeError("Container credentials unavailable")
|
|
1018
|
+
|
|
1019
|
+
start_index = int(message.get("step_index", 1))
|
|
1020
|
+
total_steps = int(message.get("total_steps", start_index + 2))
|
|
1021
|
+
request_id = message.get("request_id")
|
|
1022
|
+
|
|
1023
|
+
auth_step_name = "setup_device_authentication"
|
|
1024
|
+
auth_label = "Setting up device authentication"
|
|
1025
|
+
_emit_progress_event(
|
|
1026
|
+
self,
|
|
1027
|
+
step_index=start_index,
|
|
1028
|
+
total_steps=total_steps,
|
|
1029
|
+
step_name=auth_step_name,
|
|
1030
|
+
step_label=auth_label,
|
|
1031
|
+
status="in_progress",
|
|
1032
|
+
message="Notifying the server of the new device…",
|
|
1033
|
+
phase="service",
|
|
1034
|
+
request_id=request_id,
|
|
1035
|
+
)
|
|
1036
|
+
_emit_progress_event(
|
|
1037
|
+
self,
|
|
1038
|
+
step_index=start_index,
|
|
1039
|
+
total_steps=total_steps,
|
|
1040
|
+
step_name=auth_step_name,
|
|
1041
|
+
step_label=auth_label,
|
|
1042
|
+
status="completed",
|
|
1043
|
+
message="Authentication metadata recorded.",
|
|
1044
|
+
phase="service",
|
|
1045
|
+
request_id=request_id,
|
|
1046
|
+
)
|
|
1047
|
+
|
|
1048
|
+
install_step = start_index + 1
|
|
1049
|
+
install_label = "Launching Portacode service"
|
|
1050
|
+
_emit_progress_event(
|
|
1051
|
+
self,
|
|
1052
|
+
step_index=install_step,
|
|
1053
|
+
total_steps=total_steps,
|
|
1054
|
+
step_name="launch_portacode_service",
|
|
1055
|
+
step_label=install_label,
|
|
1056
|
+
status="in_progress",
|
|
1057
|
+
message="Running sudo portacode service install…",
|
|
1058
|
+
phase="service",
|
|
1059
|
+
request_id=request_id,
|
|
1060
|
+
)
|
|
1061
|
+
|
|
1062
|
+
cmd = f"su - {user} -c 'sudo -S portacode service install'"
|
|
1063
|
+
res = _run_pct(vmid, cmd, input_text=password + "\n")
|
|
1064
|
+
|
|
1065
|
+
if res["returncode"] != 0:
|
|
1066
|
+
_emit_progress_event(
|
|
1067
|
+
self,
|
|
1068
|
+
step_index=install_step,
|
|
1069
|
+
total_steps=total_steps,
|
|
1070
|
+
step_name="launch_portacode_service",
|
|
1071
|
+
step_label=install_label,
|
|
1072
|
+
status="failed",
|
|
1073
|
+
message=f"{install_label} failed: {res.get('stderr') or res.get('stdout')}",
|
|
1074
|
+
phase="service",
|
|
1075
|
+
request_id=request_id,
|
|
1076
|
+
details={
|
|
1077
|
+
"stderr": res.get("stderr"),
|
|
1078
|
+
"stdout": res.get("stdout"),
|
|
1079
|
+
},
|
|
1080
|
+
)
|
|
1081
|
+
raise RuntimeError(res.get("stderr") or res.get("stdout") or "Service install failed")
|
|
1082
|
+
|
|
1083
|
+
_emit_progress_event(
|
|
1084
|
+
self,
|
|
1085
|
+
step_index=install_step,
|
|
1086
|
+
total_steps=total_steps,
|
|
1087
|
+
step_name="launch_portacode_service",
|
|
1088
|
+
step_label=install_label,
|
|
1089
|
+
status="completed",
|
|
1090
|
+
message="Portacode service install finished.",
|
|
1091
|
+
phase="service",
|
|
1092
|
+
request_id=request_id,
|
|
1093
|
+
)
|
|
1094
|
+
|
|
1095
|
+
return {
|
|
1096
|
+
"event": "proxmox_service_started",
|
|
1097
|
+
"success": True,
|
|
1098
|
+
"message": "Portacode service install completed",
|
|
1099
|
+
"ctid": str(vmid),
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
|
|
968
1103
|
class ConfigureProxmoxInfraHandler(SyncHandler):
|
|
969
1104
|
@property
|
|
970
1105
|
def command_name(self) -> str:
|
portacode/connection/terminal.py
CHANGED
|
@@ -55,6 +55,7 @@ from .handlers import (
|
|
|
55
55
|
ConfigureProxmoxInfraHandler,
|
|
56
56
|
CreateProxmoxContainerHandler,
|
|
57
57
|
RevertProxmoxInfraHandler,
|
|
58
|
+
StartPortacodeServiceHandler,
|
|
58
59
|
)
|
|
59
60
|
from .handlers.project_aware_file_handlers import (
|
|
60
61
|
ProjectAwareFileWriteHandler,
|
|
@@ -478,6 +479,7 @@ class TerminalManager:
|
|
|
478
479
|
# System management handlers
|
|
479
480
|
self._command_registry.register(ConfigureProxmoxInfraHandler)
|
|
480
481
|
self._command_registry.register(CreateProxmoxContainerHandler)
|
|
482
|
+
self._command_registry.register(StartPortacodeServiceHandler)
|
|
481
483
|
self._command_registry.register(RevertProxmoxInfraHandler)
|
|
482
484
|
self._command_registry.register(UpdatePortacodeHandler)
|
|
483
485
|
|
|
@@ -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=rMZzV0VJav1wTlnbu-swqozHj1iDFuOjk8XIEpAzY8o,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
|
|
@@ -12,17 +12,17 @@ portacode/connection/README.md,sha256=f9rbuIEKa7cTm9C98rCiBbEtbiIXQU11esGSNhSMiJ
|
|
|
12
12
|
portacode/connection/__init__.py,sha256=atqcVGkViIEd7pRa6cP2do07RJOM0UWpbnz5zXjGktU,250
|
|
13
13
|
portacode/connection/client.py,sha256=jtLb9_YufqPkzi9t8VQH3iz_JEMisbtY6a8L9U5weiU,14181
|
|
14
14
|
portacode/connection/multiplex.py,sha256=L-TxqJ_ZEbfNEfu1cwxgJ5vUdyRzZjsMy2Kx1diiZys,5237
|
|
15
|
-
portacode/connection/terminal.py,sha256=
|
|
15
|
+
portacode/connection/terminal.py,sha256=07wxG_55JMy3yQ9TXCBldW9h43qCW3U8rv2yzGMx4FM,44757
|
|
16
16
|
portacode/connection/handlers/README.md,sha256=HsLZG1QK1JNm67HsgL6WoDg9nxzKXxwkc5fJPFJdX5g,12169
|
|
17
|
-
portacode/connection/handlers/WEBSOCKET_PROTOCOL.md,sha256=
|
|
18
|
-
portacode/connection/handlers/__init__.py,sha256=
|
|
17
|
+
portacode/connection/handlers/WEBSOCKET_PROTOCOL.md,sha256=Z5L0gJWoHxV7UonHqxHko_PXZd7Z1mbI6yWtmjxna-s,93951
|
|
18
|
+
portacode/connection/handlers/__init__.py,sha256=y-Aj5SXqc_QJt7i1xkl7kv381Fd2CIcUiG5gR1F8qkI,2711
|
|
19
19
|
portacode/connection/handlers/base.py,sha256=oENFb-Fcfzwk99Qx8gJQriEMiwSxwygwjOiuCH36hM4,10231
|
|
20
20
|
portacode/connection/handlers/chunked_content.py,sha256=h6hXRmxSeOgnIxoU8CkmvEf2Odv-ajPrpHIe_W3GKcA,9251
|
|
21
21
|
portacode/connection/handlers/diff_handlers.py,sha256=iYTIRCcpEQ03vIPKZCsMTE5aZbQw6sF04M3dM6rUV8Q,24477
|
|
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=KeYgb7IVdK_nSPJmrPp2W0HR0rlNCQ46DTLRQ63OF9Y,41117
|
|
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=AKh7IbwptlLYrbSw5f-DHigvlaKHsg9lDP-lkAUm8cE,10755
|
|
@@ -64,7 +64,7 @@ portacode/utils/__init__.py,sha256=NgBlWTuNJESfIYJzP_3adI1yJQJR0XJLRpSdVNaBAN0,3
|
|
|
64
64
|
portacode/utils/diff_apply.py,sha256=4Oi7ft3VUCKmiUE4VM-OeqO7Gk6H7PF3WnN4WHXtjxI,15157
|
|
65
65
|
portacode/utils/diff_renderer.py,sha256=S76StnQ2DLfsz4Gg0m07UwPfRp8270PuzbNaQq-rmYk,13850
|
|
66
66
|
portacode/utils/ntp_clock.py,sha256=VqCnWCTehCufE43W23oB-WUdAZGeCcLxkmIOPwInYHc,2499
|
|
67
|
-
portacode-1.4.11.
|
|
67
|
+
portacode-1.4.11.dev7.dist-info/licenses/LICENSE,sha256=2FGbCnUDgRYuQTkB1O1dUUpu5CVAjK1j4_p6ack9Z54,1066
|
|
68
68
|
test_modules/README.md,sha256=Do_agkm9WhSzueXjRAkV_xEj6Emy5zB3N3VKY5Roce8,9274
|
|
69
69
|
test_modules/__init__.py,sha256=1LcbHodIHsB0g-g4NGjSn6AMuCoGbymvXPYLOb6Z7F0,53
|
|
70
70
|
test_modules/test_device_online.py,sha256=QtYq0Dq9vME8Gp2O4fGSheqVf8LUtpsSKosXXk56gGM,1654
|
|
@@ -90,8 +90,8 @@ testing_framework/core/playwright_manager.py,sha256=Tw46qwxIhOFkS48C2IWIQHHNpEe-
|
|
|
90
90
|
testing_framework/core/runner.py,sha256=j2QwNJmAxVBmJvcbVS7DgPJUKPNzqfLmt_4NNdaKmZU,19297
|
|
91
91
|
testing_framework/core/shared_cli_manager.py,sha256=BESSNtyQb7BOlaOvZmm04T8Uezjms4KCBs2MzTxvzYQ,8790
|
|
92
92
|
testing_framework/core/test_discovery.py,sha256=2FZ9fJ8Dp5dloA-fkgXoJ_gCMC_nYPBnA3Hs2xlagzM,4928
|
|
93
|
-
portacode-1.4.11.
|
|
94
|
-
portacode-1.4.11.
|
|
95
|
-
portacode-1.4.11.
|
|
96
|
-
portacode-1.4.11.
|
|
97
|
-
portacode-1.4.11.
|
|
93
|
+
portacode-1.4.11.dev7.dist-info/METADATA,sha256=6A_o1zGxAkhlk0n-T3_tozO_7X-fdVO3n6RXjOCCBvs,13051
|
|
94
|
+
portacode-1.4.11.dev7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
95
|
+
portacode-1.4.11.dev7.dist-info/entry_points.txt,sha256=lLUUL-BM6_wwe44Xv0__5NQ1BnAz6jWjSMFvZdWW3zU,48
|
|
96
|
+
portacode-1.4.11.dev7.dist-info/top_level.txt,sha256=TGhTYUxfW8SyVZc_zGgzjzc24gGT7nSw8Qf73liVRKM,41
|
|
97
|
+
portacode-1.4.11.dev7.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|