machineconfig 2.98__py3-none-any.whl → 3.1__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.
Potentially problematic release.
This version of machineconfig might be problematic. Click here for more details.
- machineconfig/__init__.py +16 -17
- machineconfig/cluster/sessions_managers/enhanced_command_runner.py +6 -6
- machineconfig/cluster/sessions_managers/wt_local.py +7 -7
- machineconfig/cluster/sessions_managers/wt_local_manager.py +8 -8
- machineconfig/cluster/sessions_managers/wt_remote.py +8 -8
- machineconfig/cluster/sessions_managers/wt_remote_manager.py +6 -6
- machineconfig/cluster/sessions_managers/zellij_local.py +156 -77
- machineconfig/cluster/sessions_managers/zellij_local_manager.py +18 -15
- machineconfig/cluster/sessions_managers/zellij_remote.py +14 -61
- machineconfig/cluster/sessions_managers/zellij_remote_manager.py +15 -12
- machineconfig/cluster/sessions_managers/zellij_utils/example_usage.py +9 -3
- machineconfig/cluster/sessions_managers/zellij_utils/layout_generator.py +2 -2
- machineconfig/cluster/sessions_managers/zellij_utils/monitoring_types.py +40 -67
- machineconfig/cluster/sessions_managers/zellij_utils/process_monitor.py +19 -17
- machineconfig/cluster/sessions_managers/zellij_utils/remote_executor.py +2 -2
- machineconfig/cluster/sessions_managers/zellij_utils/session_manager.py +1 -1
- machineconfig/jobs/python/python_ve_symlink.py +1 -1
- machineconfig/profile/create.py +7 -0
- machineconfig/scripts/linux/kill_process +1 -1
- machineconfig/scripts/python/ai/mcinit.py +2 -3
- machineconfig/scripts/python/cloud_mount.py +1 -1
- machineconfig/scripts/python/cloud_repo_sync.py +1 -0
- machineconfig/scripts/python/cloud_sync.py +1 -0
- machineconfig/scripts/python/croshell.py +1 -0
- machineconfig/scripts/python/devops.py +11 -0
- machineconfig/scripts/python/devops_add_identity.py +1 -0
- machineconfig/scripts/python/devops_add_ssh_key.py +1 -0
- machineconfig/scripts/python/devops_backup_retrieve.py +1 -0
- machineconfig/scripts/python/devops_devapps_install.py +4 -6
- machineconfig/scripts/python/devops_update_repos.py +21 -20
- machineconfig/scripts/python/fire_agents.py +17 -7
- machineconfig/scripts/python/fire_agents_help_launch.py +4 -3
- machineconfig/scripts/python/fire_agents_help_search.py +1 -2
- machineconfig/scripts/python/fire_agents_load_balancer.py +8 -10
- machineconfig/scripts/python/fire_jobs.py +1 -0
- machineconfig/scripts/python/helpers/cloud_helpers.py +1 -0
- machineconfig/scripts/python/mount_nfs.py +2 -0
- machineconfig/scripts/python/mount_nw_drive.py +1 -1
- machineconfig/scripts/python/mount_ssh.py +1 -0
- machineconfig/scripts/python/repos.py +0 -2
- machineconfig/scripts/python/repos_helper_record.py +43 -66
- machineconfig/scripts/python/repos_helper_update.py +3 -2
- machineconfig/scripts/python/start_slidev.py +1 -0
- machineconfig/scripts/python/start_terminals.py +1 -1
- machineconfig/setup_windows/wt_and_pwsh/set_wt_settings.py +1 -0
- machineconfig/utils/code.py +0 -1
- machineconfig/utils/notifications.py +2 -2
- machineconfig/utils/procs.py +10 -15
- machineconfig/utils/schemas/fire_agents/fire_agents_input.py +9 -4
- machineconfig/utils/schemas/layouts/layout_types.py +2 -0
- machineconfig/utils/schemas/repos/repos_types.py +0 -3
- machineconfig/utils/ssh.py +9 -11
- machineconfig/utils/utils2.py +1 -0
- machineconfig/utils/ve.py +0 -1
- {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/METADATA +1 -1
- {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/RECORD +59 -78
- {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/entry_points.txt +1 -0
- machineconfig/jobs/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_generic_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/jobs/python_linux_installers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/cloud_repo_sync.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_devapps_install.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/devops_update_repos.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/fire_agents.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/get_zellij_cmd.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos_helper_record.cpython-313.pyc +0 -0
- machineconfig/scripts/python/__pycache__/repos_helper_update.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/__init__.cpython-313.pyc +0 -0
- machineconfig/scripts/python/helpers/__pycache__/repo_sync_helpers.cpython-313.pyc +0 -0
- machineconfig/settings/linters/.ruff_cache/.gitignore +0 -2
- machineconfig/settings/linters/.ruff_cache/CACHEDIR.TAG +0 -1
- machineconfig/settings/shells/bash/.inputrc +0 -3
- {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/WHEEL +0 -0
- {machineconfig-2.98.dist-info → machineconfig-3.1.dist-info}/top_level.txt +0 -0
|
@@ -10,7 +10,7 @@ from typing import Optional, List
|
|
|
10
10
|
|
|
11
11
|
from rich.console import Console
|
|
12
12
|
|
|
13
|
-
from machineconfig.cluster.sessions_managers.zellij_utils.monitoring_types import SessionReport, GlobalSummary, StartResult, ActiveSessionInfo
|
|
13
|
+
from machineconfig.cluster.sessions_managers.zellij_utils.monitoring_types import SessionReport, GlobalSummary, StartResult, ActiveSessionInfo, StatusRow
|
|
14
14
|
from machineconfig.utils.utils5 import Scheduler
|
|
15
15
|
from machineconfig.cluster.sessions_managers.zellij_local import ZellijLayoutGenerator
|
|
16
16
|
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
@@ -36,7 +36,7 @@ class ZellijLocalManager:
|
|
|
36
36
|
session_name = layout_config["layoutName"].replace(" ", "_")
|
|
37
37
|
manager = ZellijLayoutGenerator()
|
|
38
38
|
full_session_name = f"{self.session_name_prefix}_{session_name}"
|
|
39
|
-
manager.create_zellij_layout(layout_config=layout_config, session_name=full_session_name)
|
|
39
|
+
manager.create_zellij_layout(layout_config=layout_config, output_dir=None, session_name=full_session_name)
|
|
40
40
|
self.managers.append(manager)
|
|
41
41
|
|
|
42
42
|
# Enhanced Rich logging for initialization
|
|
@@ -46,7 +46,7 @@ class ZellijLocalManager:
|
|
|
46
46
|
"""Get all managed session names."""
|
|
47
47
|
return [manager.session_name for manager in self.managers if manager.session_name is not None]
|
|
48
48
|
|
|
49
|
-
def start_all_sessions(self, poll_seconds: float
|
|
49
|
+
def start_all_sessions(self, poll_seconds: float, poll_interval: float) -> dict[str, StartResult]:
|
|
50
50
|
"""Start all zellij sessions with their layouts without blocking on the interactive TUI.
|
|
51
51
|
|
|
52
52
|
Rationale:
|
|
@@ -135,7 +135,7 @@ class ZellijLocalManager:
|
|
|
135
135
|
|
|
136
136
|
return results
|
|
137
137
|
|
|
138
|
-
def attach_to_session(self, session_name: Optional[str]
|
|
138
|
+
def attach_to_session(self, session_name: Optional[str]) -> str:
|
|
139
139
|
"""
|
|
140
140
|
Generate command to attach to a specific session or list attachment commands for all.
|
|
141
141
|
|
|
@@ -153,7 +153,7 @@ class ZellijLocalManager:
|
|
|
153
153
|
raise ValueError(f"Session '{session_name}' not found")
|
|
154
154
|
else:
|
|
155
155
|
# Return commands for all sessions
|
|
156
|
-
commands = []
|
|
156
|
+
commands: list[str] = []
|
|
157
157
|
for manager in self.managers:
|
|
158
158
|
commands.append(f"# Attach to session '{manager.session_name}':")
|
|
159
159
|
commands.append(f"zellij attach {manager.session_name}")
|
|
@@ -253,12 +253,13 @@ class ZellijLocalManager:
|
|
|
253
253
|
|
|
254
254
|
print("=" * 80)
|
|
255
255
|
|
|
256
|
-
def run_monitoring_routine(self, wait_ms: int
|
|
256
|
+
def run_monitoring_routine(self, wait_ms: int) -> None:
|
|
257
257
|
"""
|
|
258
258
|
Run a continuous monitoring routine that checks status periodically.
|
|
259
259
|
|
|
260
260
|
Args:
|
|
261
|
-
wait_ms: How long to wait between checks in milliseconds
|
|
261
|
+
wait_ms: How long to wait between checks in milliseconds
|
|
262
|
+
kill_sessions_on_completion: If True, kill all managed zellij sessions when monitoring stops
|
|
262
263
|
"""
|
|
263
264
|
|
|
264
265
|
def routine(scheduler: Scheduler):
|
|
@@ -270,7 +271,7 @@ class ZellijLocalManager:
|
|
|
270
271
|
all_status = self.check_all_sessions_status()
|
|
271
272
|
|
|
272
273
|
# Create DataFrame for easier viewing
|
|
273
|
-
status_data = []
|
|
274
|
+
status_data: list[StatusRow] = []
|
|
274
275
|
for session_name, status in all_status.items():
|
|
275
276
|
for tab_name, cmd_status in status["commands_status"].items():
|
|
276
277
|
status_data.append(
|
|
@@ -314,7 +315,7 @@ class ZellijLocalManager:
|
|
|
314
315
|
sched = Scheduler(routine=routine, wait_ms=wait_ms, logger=logger)
|
|
315
316
|
sched.run()
|
|
316
317
|
|
|
317
|
-
def save(self, session_id: Optional[str]
|
|
318
|
+
def save(self, session_id: Optional[str]) -> str:
|
|
318
319
|
"""Save the manager state to disk."""
|
|
319
320
|
if session_id is None:
|
|
320
321
|
session_id = str(uuid.uuid4())[:8]
|
|
@@ -360,8 +361,8 @@ class ZellijLocalManager:
|
|
|
360
361
|
if not config_file.exists():
|
|
361
362
|
raise FileNotFoundError(f"Configuration file not found: {config_file}")
|
|
362
363
|
|
|
363
|
-
|
|
364
|
-
|
|
364
|
+
text = config_file.read_text(encoding="utf-8")
|
|
365
|
+
session_layouts = json.loads(text)
|
|
365
366
|
|
|
366
367
|
# Create new instance
|
|
367
368
|
instance = cls(session_layouts=session_layouts)
|
|
@@ -374,8 +375,8 @@ class ZellijLocalManager:
|
|
|
374
375
|
|
|
375
376
|
for manager_file in manager_files:
|
|
376
377
|
try:
|
|
377
|
-
|
|
378
|
-
|
|
378
|
+
text = manager_file.read_text(encoding="utf-8")
|
|
379
|
+
manager_data = json.loads(text)
|
|
379
380
|
|
|
380
381
|
# Recreate the manager
|
|
381
382
|
manager = ZellijLayoutGenerator()
|
|
@@ -493,7 +494,7 @@ if __name__ == "__main__":
|
|
|
493
494
|
|
|
494
495
|
# Print attachment commands (without actually starting)
|
|
495
496
|
print("\n📎 Attachment commands:")
|
|
496
|
-
print(manager.attach_to_session())
|
|
497
|
+
print(manager.attach_to_session(None))
|
|
497
498
|
|
|
498
499
|
# Show current status
|
|
499
500
|
print("\n🔍 Current status:")
|
|
@@ -501,7 +502,7 @@ if __name__ == "__main__":
|
|
|
501
502
|
|
|
502
503
|
# Demonstrate save/load
|
|
503
504
|
print("\n💾 Demonstrating save/load...")
|
|
504
|
-
session_id = manager.save()
|
|
505
|
+
session_id = manager.save(None)
|
|
505
506
|
print(f"✅ Saved session: {session_id}")
|
|
506
507
|
|
|
507
508
|
# List saved sessions
|
|
@@ -515,6 +516,8 @@ if __name__ == "__main__":
|
|
|
515
516
|
# Show how to start monitoring (commented out to prevent infinite loop in demo)
|
|
516
517
|
print("\n⏰ To start monitoring, run:")
|
|
517
518
|
print("manager.run_monitoring_routine(wait_ms=30000) # 30 seconds")
|
|
519
|
+
print("# Or with session cleanup:")
|
|
520
|
+
print("manager.run_monitoring_routine(wait_ms=30000, kill_sessions_on_completion=True)")
|
|
518
521
|
|
|
519
522
|
except Exception as e:
|
|
520
523
|
print(f"❌ Error: {e}")
|
|
@@ -24,7 +24,7 @@ TMP_LAYOUT_DIR = Path.home().joinpath("tmp_results", "zellij_layouts", "layout_m
|
|
|
24
24
|
class ZellijRemoteLayoutGenerator:
|
|
25
25
|
def __init__(self, remote_name: str, session_name_prefix: str):
|
|
26
26
|
self.remote_name = remote_name
|
|
27
|
-
self.session_name = session_name_prefix + "_" + LayoutGenerator.generate_random_suffix()
|
|
27
|
+
self.session_name = session_name_prefix + "_" + LayoutGenerator.generate_random_suffix(8)
|
|
28
28
|
self.layout_config: Optional[LayoutConfig] = None
|
|
29
29
|
self.layout_path: Optional[str] = None
|
|
30
30
|
|
|
@@ -35,10 +35,7 @@ class ZellijRemoteLayoutGenerator:
|
|
|
35
35
|
self.session_manager = SessionManager(self.remote_executor, self.session_name, TMP_LAYOUT_DIR)
|
|
36
36
|
self.status_reporter = StatusReporter(self.process_monitor, self.session_manager)
|
|
37
37
|
|
|
38
|
-
def
|
|
39
|
-
return self.session_manager.copy_layout_to_remote(local_layout_file, random_suffix)
|
|
40
|
-
|
|
41
|
-
def create_zellij_layout(self, layout_config: LayoutConfig, output_dir: Optional[str] = None) -> str:
|
|
38
|
+
def create_zellij_layout(self, layout_config: LayoutConfig, output_dir: Optional[str]) -> str:
|
|
42
39
|
# Enhanced Rich logging for remote layout creation
|
|
43
40
|
tab_count = len(layout_config["layoutTabs"])
|
|
44
41
|
layout_name = layout_config["layoutName"]
|
|
@@ -56,63 +53,16 @@ class ZellijRemoteLayoutGenerator:
|
|
|
56
53
|
self.layout_path = self.layout_generator.create_layout_file(layout_config, output_path, self.session_name)
|
|
57
54
|
return self.layout_path
|
|
58
55
|
|
|
59
|
-
def get_layout_preview(self, layout_config: LayoutConfig) -> str:
|
|
60
|
-
return self.layout_generator.generate_layout_content(layout_config)
|
|
61
|
-
|
|
62
|
-
def check_command_status(self, tab_name: str, use_verification: bool = True) -> Dict[str, Any]:
|
|
63
|
-
if not self.layout_config:
|
|
64
|
-
return {"status": "error", "error": "No layout config available", "running": False}
|
|
65
|
-
return self.process_monitor.check_command_status(tab_name, self.layout_config, use_verification)
|
|
66
|
-
|
|
67
|
-
def check_all_commands_status(self) -> Dict[str, Dict[str, Any]]:
|
|
68
|
-
if not self.layout_config:
|
|
69
|
-
return {}
|
|
70
|
-
return self.process_monitor.check_all_commands_status(self.layout_config)
|
|
71
|
-
|
|
72
|
-
def check_zellij_session_status(self) -> Dict[str, Any]:
|
|
73
|
-
return self.session_manager.check_zellij_session_status()
|
|
74
|
-
|
|
75
|
-
def get_comprehensive_status(self) -> Dict[str, Any]:
|
|
76
|
-
if not self.layout_config:
|
|
77
|
-
return {"error": "No layout config available"}
|
|
78
|
-
return self.status_reporter.get_comprehensive_status(self.layout_config)
|
|
79
|
-
|
|
80
|
-
def print_status_report(self) -> None:
|
|
81
|
-
if not self.layout_config:
|
|
82
|
-
console.print("[bold red]❌ No layout config available[/bold red]")
|
|
83
|
-
return
|
|
84
|
-
self.status_reporter.print_status_report(self.layout_config)
|
|
85
|
-
|
|
86
|
-
def start_zellij_session(self, layout_file_path: Optional[str] = None) -> Dict[str, Any]:
|
|
87
|
-
return self.session_manager.start_zellij_session(layout_file_path or self.layout_path)
|
|
88
|
-
|
|
89
|
-
def attach_to_session(self) -> None:
|
|
90
|
-
self.session_manager.attach_to_session()
|
|
91
|
-
|
|
92
|
-
# Legacy methods for backward compatibility
|
|
93
|
-
def force_fresh_process_check(self, tab_name: str) -> Dict[str, Any]:
|
|
94
|
-
if not self.layout_config:
|
|
95
|
-
return {"error": "No layout config available"}
|
|
96
|
-
return self.process_monitor.force_fresh_process_check(tab_name, self.layout_config)
|
|
97
|
-
|
|
98
|
-
def verify_process_alive(self, pid: int) -> bool:
|
|
99
|
-
return self.process_monitor.verify_process_alive(pid)
|
|
100
|
-
|
|
101
|
-
def get_verified_process_status(self, tab_name: str) -> Dict[str, Any]:
|
|
102
|
-
if not self.layout_config:
|
|
103
|
-
return {"error": "No layout config available"}
|
|
104
|
-
return self.process_monitor.get_verified_process_status(tab_name, self.layout_config)
|
|
105
|
-
|
|
106
56
|
# Static methods for backward compatibility
|
|
107
57
|
@staticmethod
|
|
108
|
-
def run_remote_command(remote_name: str, command: str, timeout: int
|
|
58
|
+
def run_remote_command(remote_name: str, command: str, timeout: int):
|
|
109
59
|
executor = RemoteExecutor(remote_name)
|
|
110
60
|
return executor.run_command(command, timeout)
|
|
111
61
|
|
|
112
62
|
def to_dict(self) -> Dict[str, Any]:
|
|
113
63
|
return {"remote_name": self.remote_name, "session_name": self.session_name, "layout_config": self.layout_config, "layout_path": self.layout_path, "created_at": datetime.now().isoformat(), "class_name": self.__class__.__name__}
|
|
114
64
|
|
|
115
|
-
def to_json(self, file_path: Optional[Union[str, Path]]
|
|
65
|
+
def to_json(self, file_path: Optional[Union[str, Path]]) -> str:
|
|
116
66
|
# Generate file path if not provided
|
|
117
67
|
if file_path is None:
|
|
118
68
|
random_id = str(uuid.uuid4())[:8]
|
|
@@ -150,8 +100,8 @@ class ZellijRemoteLayoutGenerator:
|
|
|
150
100
|
raise FileNotFoundError(f"JSON file not found: {file_path}")
|
|
151
101
|
|
|
152
102
|
# Load JSON data
|
|
153
|
-
|
|
154
|
-
|
|
103
|
+
text = Path(file_path).read_text(encoding="utf-8")
|
|
104
|
+
data = json.loads(text)
|
|
155
105
|
|
|
156
106
|
# Validate that it's the correct class
|
|
157
107
|
if data.get("class_name") != cls.__name__:
|
|
@@ -176,7 +126,7 @@ class ZellijRemoteLayoutGenerator:
|
|
|
176
126
|
return instance
|
|
177
127
|
|
|
178
128
|
@staticmethod
|
|
179
|
-
def list_saved_sessions(directory_path: Optional[Union[str, Path]]
|
|
129
|
+
def list_saved_sessions(directory_path: Optional[Union[str, Path]]) -> List[str]:
|
|
180
130
|
if directory_path is None:
|
|
181
131
|
directory_path = Path.home() / "tmp_results" / "zellij_sessions" / "serialized"
|
|
182
132
|
else:
|
|
@@ -208,16 +158,16 @@ if __name__ == "__main__":
|
|
|
208
158
|
try:
|
|
209
159
|
# Create layout using the remote generator
|
|
210
160
|
generator = ZellijRemoteLayoutGenerator(remote_name=remote_name, session_name_prefix=session_name)
|
|
211
|
-
layout_path = generator.create_zellij_layout(sample_layout)
|
|
161
|
+
layout_path = generator.create_zellij_layout(sample_layout, None)
|
|
212
162
|
print(f"✅ Remote layout created successfully: {layout_path}")
|
|
213
163
|
|
|
214
164
|
# Demonstrate serialization
|
|
215
165
|
print("\n💾 Demonstrating serialization...")
|
|
216
|
-
saved_path = generator.to_json()
|
|
166
|
+
saved_path = generator.to_json(None)
|
|
217
167
|
print(f"✅ Session saved to: {saved_path}")
|
|
218
168
|
|
|
219
169
|
# List all saved sessions
|
|
220
|
-
saved_sessions = ZellijRemoteLayoutGenerator.list_saved_sessions()
|
|
170
|
+
saved_sessions = ZellijRemoteLayoutGenerator.list_saved_sessions(None)
|
|
221
171
|
print(f"📋 Available saved sessions: {saved_sessions}")
|
|
222
172
|
|
|
223
173
|
# Demonstrate loading (using the full path)
|
|
@@ -229,7 +179,10 @@ if __name__ == "__main__":
|
|
|
229
179
|
|
|
230
180
|
# Demonstrate status checking
|
|
231
181
|
print(f"\n🔍 Checking command status on remote '{remote_name}':")
|
|
232
|
-
generator.
|
|
182
|
+
if not generator.layout_config:
|
|
183
|
+
console.print("[bold red]❌ No layout config available[/bold red]")
|
|
184
|
+
else:
|
|
185
|
+
generator.status_reporter.print_status_report(generator.layout_config)
|
|
233
186
|
|
|
234
187
|
# Start the session (uncomment to actually start)
|
|
235
188
|
# start_result = generator.start_zellij_session()
|
|
@@ -15,13 +15,13 @@ logger = get_logger("cluster.sessions_managers.zellij_remote_manager")
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class ZellijSessionManager:
|
|
18
|
-
def __init__(self, machine_layouts: Dict[str, LayoutConfig], session_name_prefix: str
|
|
18
|
+
def __init__(self, machine_layouts: Dict[str, LayoutConfig], session_name_prefix: str):
|
|
19
19
|
self.session_name_prefix = session_name_prefix
|
|
20
20
|
self.machine_layouts = machine_layouts # Store the original config
|
|
21
21
|
self.managers: list[ZellijRemoteLayoutGenerator] = []
|
|
22
22
|
for machine, layout_config in machine_layouts.items():
|
|
23
23
|
an_m = ZellijRemoteLayoutGenerator(remote_name=machine, session_name_prefix=self.session_name_prefix)
|
|
24
|
-
an_m.create_zellij_layout(layout_config=layout_config)
|
|
24
|
+
an_m.create_zellij_layout(layout_config=layout_config, output_dir=None)
|
|
25
25
|
self.managers.append(an_m)
|
|
26
26
|
|
|
27
27
|
def ssh_to_all_machines(self) -> str:
|
|
@@ -40,18 +40,21 @@ class ZellijSessionManager:
|
|
|
40
40
|
|
|
41
41
|
def kill_all_sessions(self) -> None:
|
|
42
42
|
for an_m in self.managers:
|
|
43
|
-
ZellijRemoteLayoutGenerator.run_remote_command(remote_name=an_m.remote_name, command="zellij kill-all-sessions --yes")
|
|
43
|
+
ZellijRemoteLayoutGenerator.run_remote_command(remote_name=an_m.remote_name, command="zellij kill-all-sessions --yes", timeout=30)
|
|
44
44
|
|
|
45
45
|
def start_zellij_sessions(self) -> None:
|
|
46
46
|
for an_m in self.managers:
|
|
47
|
-
an_m.start_zellij_session()
|
|
47
|
+
an_m.session_manager.start_zellij_session(an_m.layout_path)
|
|
48
48
|
|
|
49
49
|
def run_monitoring_routine(self) -> None:
|
|
50
50
|
def routine(scheduler: Scheduler):
|
|
51
51
|
if scheduler.cycle % 2 == 0:
|
|
52
52
|
statuses = []
|
|
53
53
|
for _idx, an_m in enumerate(self.managers):
|
|
54
|
-
|
|
54
|
+
if not an_m.layout_config:
|
|
55
|
+
a_status = {}
|
|
56
|
+
else:
|
|
57
|
+
a_status = an_m.process_monitor.check_all_commands_status(an_m.layout_config)
|
|
55
58
|
statuses.append(a_status)
|
|
56
59
|
keys = []
|
|
57
60
|
for item in statuses:
|
|
@@ -76,7 +79,7 @@ class ZellijSessionManager:
|
|
|
76
79
|
else:
|
|
77
80
|
statuses = []
|
|
78
81
|
for _idx, an_m in enumerate(self.managers):
|
|
79
|
-
a_status = an_m.check_zellij_session_status()
|
|
82
|
+
a_status = an_m.session_manager.check_zellij_session_status()
|
|
80
83
|
statuses.append(a_status)
|
|
81
84
|
|
|
82
85
|
# Print statuses
|
|
@@ -86,7 +89,7 @@ class ZellijSessionManager:
|
|
|
86
89
|
sched = Scheduler(routine=routine, wait_ms=60_000, logger=logger)
|
|
87
90
|
sched.run()
|
|
88
91
|
|
|
89
|
-
def save(self, session_id: Optional[str]
|
|
92
|
+
def save(self, session_id: Optional[str]) -> str:
|
|
90
93
|
if session_id is None:
|
|
91
94
|
session_id = str(uuid.uuid4())[:8]
|
|
92
95
|
|
|
@@ -124,16 +127,16 @@ class ZellijSessionManager:
|
|
|
124
127
|
config_file = session_dir / "machine_layouts.json"
|
|
125
128
|
if not config_file.exists():
|
|
126
129
|
raise FileNotFoundError(f"Configuration file not found: {config_file}")
|
|
127
|
-
|
|
128
|
-
|
|
130
|
+
text = config_file.read_text(encoding="utf-8")
|
|
131
|
+
machine_layouts = json.loads(text)
|
|
129
132
|
|
|
130
133
|
# Load metadata
|
|
131
134
|
metadata_file = session_dir / "metadata.json"
|
|
132
135
|
session_name_prefix = "JobMgr" # default fallback
|
|
133
136
|
if metadata_file.exists():
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
+
text = metadata_file.read_text(encoding="utf-8")
|
|
138
|
+
metadata = json.loads(text)
|
|
139
|
+
session_name_prefix = metadata.get("session_name_prefix", "JobMgr")
|
|
137
140
|
# Create new instance (this will create new managers)
|
|
138
141
|
instance = cls(machine_layouts=machine_layouts, session_name_prefix=session_name_prefix)
|
|
139
142
|
# Load saved managers to restore their states
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
Example usage of the modularized Zellij remote layout generator.
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
|
+
from rich.console import Console
|
|
6
7
|
from machineconfig.cluster.sessions_managers.zellij_remote import ZellijRemoteLayoutGenerator
|
|
7
8
|
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
8
9
|
|
|
10
|
+
console = Console()
|
|
11
|
+
|
|
9
12
|
|
|
10
13
|
def example_usage():
|
|
11
14
|
"""Demonstrate the refactored modular usage."""
|
|
@@ -30,16 +33,19 @@ def example_usage():
|
|
|
30
33
|
generator = ZellijRemoteLayoutGenerator(remote_name=remote_name, session_name_prefix=session_name)
|
|
31
34
|
|
|
32
35
|
# Create layout file
|
|
33
|
-
layout_path = generator.create_zellij_layout(sample_layout)
|
|
36
|
+
layout_path = generator.create_zellij_layout(sample_layout, None)
|
|
34
37
|
print(f"✅ Remote layout created successfully: {layout_path}")
|
|
35
38
|
|
|
36
39
|
# Preview the layout content
|
|
37
|
-
preview = generator.
|
|
40
|
+
preview = generator.layout_generator.generate_layout_content(sample_layout)
|
|
38
41
|
print(f"📄 Layout preview:\n{preview}")
|
|
39
42
|
|
|
40
43
|
# Check status using the modular components
|
|
41
44
|
print(f"\n🔍 Checking command status on remote '{remote_name}':")
|
|
42
|
-
generator.
|
|
45
|
+
if not generator.layout_config:
|
|
46
|
+
console.print("[bold red]❌ No layout config available[/bold red]")
|
|
47
|
+
else:
|
|
48
|
+
generator.status_reporter.print_status_report(generator.layout_config)
|
|
43
49
|
|
|
44
50
|
# The individual components can also be used directly:
|
|
45
51
|
print("\n🔧 Direct component usage examples:")
|
|
@@ -31,7 +31,7 @@ class LayoutGenerator:
|
|
|
31
31
|
"""
|
|
32
32
|
|
|
33
33
|
@staticmethod
|
|
34
|
-
def generate_random_suffix(length: int
|
|
34
|
+
def generate_random_suffix(length: int) -> str:
|
|
35
35
|
"""Generate a random string suffix for unique layout file names."""
|
|
36
36
|
return "".join(random.choices(string.ascii_lowercase + string.digits, k=length))
|
|
37
37
|
|
|
@@ -121,7 +121,7 @@ class LayoutGenerator:
|
|
|
121
121
|
self.validate_tab_config(layout_config)
|
|
122
122
|
|
|
123
123
|
# Generate unique suffix for this layout
|
|
124
|
-
random_suffix = self.generate_random_suffix()
|
|
124
|
+
random_suffix = self.generate_random_suffix(8)
|
|
125
125
|
layout_content = self.generate_layout_content(layout_config)
|
|
126
126
|
|
|
127
127
|
try:
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
# TypedDict definitions for better type safety
|
|
2
|
-
from typing import NotRequired, TypedDict, Optional
|
|
3
1
|
|
|
4
|
-
|
|
2
|
+
from typing import NotRequired, TypedDict, Optional
|
|
5
3
|
from machineconfig.utils.schemas.layouts.layout_types import LayoutConfig
|
|
6
4
|
|
|
7
5
|
|
|
@@ -10,47 +8,37 @@ class ProcessInfo(TypedDict):
|
|
|
10
8
|
name: str
|
|
11
9
|
cmdline: list[str]
|
|
12
10
|
status: str
|
|
11
|
+
cmdline_str: NotRequired[str]
|
|
12
|
+
create_time: NotRequired[float]
|
|
13
|
+
is_direct_command: NotRequired[bool]
|
|
14
|
+
verified_alive: NotRequired[bool]
|
|
15
|
+
memory_mb: NotRequired[float]
|
|
16
|
+
|
|
13
17
|
|
|
14
18
|
class CommandStatus(TypedDict):
|
|
15
|
-
status: str
|
|
16
|
-
running: bool
|
|
17
|
-
processes: list[ProcessInfo]
|
|
18
|
-
command: str
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
status: str # e.g. running | not_running | unknown | error
|
|
20
|
+
running: bool # Convenience boolean
|
|
21
|
+
processes: list[ProcessInfo] # Matching processes (can be empty)
|
|
22
|
+
command: str # Original command string ('' if unknown)
|
|
23
|
+
tab_name: str # Tab identifier
|
|
24
|
+
# Optional / contextual fields
|
|
25
|
+
cwd: NotRequired[str]
|
|
21
26
|
error: NotRequired[str]
|
|
22
27
|
pid: NotRequired[int]
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
session_name: str
|
|
29
|
-
all_sessions: list[str]
|
|
30
|
-
error: NotRequired[str]
|
|
31
|
-
|
|
32
|
-
|
|
28
|
+
remote: NotRequired[str]
|
|
29
|
+
check_timestamp: NotRequired[str | float]
|
|
30
|
+
method: NotRequired[str]
|
|
31
|
+
raw_output: NotRequired[str]
|
|
32
|
+
verification_method: NotRequired[str]
|
|
33
33
|
class CommandSummary(TypedDict):
|
|
34
34
|
total_commands: int
|
|
35
35
|
running_commands: int
|
|
36
36
|
stopped_commands: int
|
|
37
37
|
session_healthy: bool
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
class CommandStatusResult(TypedDict):
|
|
41
|
-
status: str
|
|
42
|
-
running: bool
|
|
43
|
-
processes: list[ProcessInfo]
|
|
44
|
-
command: str
|
|
45
|
-
cwd: str
|
|
46
|
-
tab_name: str
|
|
47
|
-
error: NotRequired[str]
|
|
48
|
-
pid: NotRequired[int]
|
|
49
|
-
|
|
50
|
-
|
|
51
39
|
class ZellijSessionStatus(TypedDict):
|
|
52
40
|
zellij_running: bool
|
|
53
|
-
session_exists:
|
|
41
|
+
session_exists: bool
|
|
54
42
|
session_name: str
|
|
55
43
|
all_sessions: list[str]
|
|
56
44
|
error: NotRequired[str]
|
|
@@ -58,8 +46,27 @@ class ZellijSessionStatus(TypedDict):
|
|
|
58
46
|
|
|
59
47
|
class SessionReport(TypedDict):
|
|
60
48
|
session_status: ZellijSessionStatus # ZellijSessionStatus from zellij_local
|
|
61
|
-
commands_status: dict[str,
|
|
49
|
+
commands_status: dict[str, CommandStatus] # dict[str, CommandStatus from zellij_local]
|
|
62
50
|
summary: CommandSummary
|
|
51
|
+
class ComprehensiveStatus(TypedDict):
|
|
52
|
+
zellij_session: ZellijSessionStatus
|
|
53
|
+
commands: dict[str, CommandStatus]
|
|
54
|
+
summary: CommandSummary
|
|
55
|
+
class SessionMetadata(TypedDict):
|
|
56
|
+
session_name_prefix: str
|
|
57
|
+
created_at: str
|
|
58
|
+
num_managers: int
|
|
59
|
+
sessions: list[str]
|
|
60
|
+
manager_type: str
|
|
61
|
+
class ManagerData(TypedDict):
|
|
62
|
+
session_name: Optional[str]
|
|
63
|
+
layout_config: Optional[LayoutConfig] # Will be LayoutConfig from layout_types
|
|
64
|
+
layout_path: Optional[str]
|
|
65
|
+
class ActiveSessionInfo(TypedDict):
|
|
66
|
+
session_name: str
|
|
67
|
+
is_active: bool
|
|
68
|
+
tab_count: int
|
|
69
|
+
tabs: list[str]
|
|
63
70
|
|
|
64
71
|
|
|
65
72
|
class GlobalSummary(TypedDict):
|
|
@@ -77,8 +84,6 @@ class StartResult(TypedDict):
|
|
|
77
84
|
success: bool
|
|
78
85
|
message: NotRequired[str]
|
|
79
86
|
error: NotRequired[str]
|
|
80
|
-
|
|
81
|
-
|
|
82
87
|
class StatusRow(TypedDict):
|
|
83
88
|
session: str
|
|
84
89
|
tab: str
|
|
@@ -87,35 +92,3 @@ class StatusRow(TypedDict):
|
|
|
87
92
|
processes: int
|
|
88
93
|
|
|
89
94
|
|
|
90
|
-
class SessionMetadata(TypedDict):
|
|
91
|
-
session_name_prefix: str
|
|
92
|
-
created_at: str
|
|
93
|
-
num_managers: int
|
|
94
|
-
sessions: list[str]
|
|
95
|
-
manager_type: str
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
class ManagerData(TypedDict):
|
|
99
|
-
session_name: Optional[str]
|
|
100
|
-
layout_config: Optional[LayoutConfig] # Will be LayoutConfig from layout_types
|
|
101
|
-
layout_path: Optional[str]
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
class ActiveSessionInfo(TypedDict):
|
|
105
|
-
session_name: str
|
|
106
|
-
is_active: bool
|
|
107
|
-
tab_count: int
|
|
108
|
-
tabs: list[str]
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
class StatusSummary(TypedDict):
|
|
112
|
-
total_commands: int
|
|
113
|
-
running_commands: int
|
|
114
|
-
stopped_commands: int
|
|
115
|
-
session_healthy: bool
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
class ComprehensiveStatus(TypedDict):
|
|
119
|
-
zellij_session: ZellijSessionStatus
|
|
120
|
-
commands: dict[str, CommandStatusResult]
|
|
121
|
-
summary: StatusSummary
|