cyclo-manager 1.0.0.dev5__tar.gz → 1.0.0.dev6__tar.gz
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.
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/PKG-INFO +4 -4
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/README.md +3 -3
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_host_agent/routers/update.py +1 -4
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager.egg-info/PKG-INFO +4 -4
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager_cli/cli.py +64 -7
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/pyproject.toml +1 -1
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_host_agent/__init__.py +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_host_agent/main.py +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_host_agent/models.py +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_host_agent/routers/__init__.py +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_host_agent/routers/repos.py +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager.egg-info/SOURCES.txt +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager.egg-info/dependency_links.txt +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager.egg-info/entry_points.txt +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager.egg-info/requires.txt +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager.egg-info/top_level.txt +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager_cli/__init__.py +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager_cli/config/config.yml +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager_cli/docker/docker-compose.yml +0 -0
- {cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyclo-manager
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev6
|
|
4
4
|
Summary: cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack.
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -120,16 +120,16 @@ The pip package installs a small **FastAPI** server that listens on a **Unix dom
|
|
|
120
120
|
|------|------|
|
|
121
121
|
| Socket | `/var/run/robotis/agent_sockets/host/host_agent.sock` |
|
|
122
122
|
| systemd unit | `cyclo_host_agent.service` |
|
|
123
|
-
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; skipped on root-only devices) |
|
|
123
|
+
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; `refresh-host-agent` CLI subcommand for UI updates; skipped on root-only devices) |
|
|
124
124
|
|
|
125
125
|
The API container reaches it at `/agents/host/host_agent.sock` (see bundled `config.yml`).
|
|
126
126
|
|
|
127
127
|
**Responsibilities:**
|
|
128
128
|
|
|
129
129
|
- List and update **`~/ROBOTIS-GIT/*`** git repositories (Version Management in the UI)
|
|
130
|
-
- Run
|
|
130
|
+
- Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`
|
|
131
131
|
|
|
132
|
-
`cyclo_manager up`
|
|
132
|
+
`cyclo_manager up` installs the `refresh-host-agent` CLI subcommand into sudoers. It is registered as `sys.executable -m cyclo_manager_cli.cli refresh-host-agent` so systemd updates do not depend on `PATH`. After that, UI-triggered updates can refresh the host agent non-interactively. The command is idempotent and refreshes the socket directory, sudoers file, systemd unit, and service state after package upgrades.
|
|
133
133
|
|
|
134
134
|
Repository scanning uses `CYCLO_HOST_AGENT_WORKSPACE` when set. Otherwise it uses the service user's home directory, except root-only devices with `/data/docker`, where `/data/docker` is used automatically.
|
|
135
135
|
|
|
@@ -106,16 +106,16 @@ The pip package installs a small **FastAPI** server that listens on a **Unix dom
|
|
|
106
106
|
|------|------|
|
|
107
107
|
| Socket | `/var/run/robotis/agent_sockets/host/host_agent.sock` |
|
|
108
108
|
| systemd unit | `cyclo_host_agent.service` |
|
|
109
|
-
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; skipped on root-only devices) |
|
|
109
|
+
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; `refresh-host-agent` CLI subcommand for UI updates; skipped on root-only devices) |
|
|
110
110
|
|
|
111
111
|
The API container reaches it at `/agents/host/host_agent.sock` (see bundled `config.yml`).
|
|
112
112
|
|
|
113
113
|
**Responsibilities:**
|
|
114
114
|
|
|
115
115
|
- List and update **`~/ROBOTIS-GIT/*`** git repositories (Version Management in the UI)
|
|
116
|
-
- Run
|
|
116
|
+
- Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`
|
|
117
117
|
|
|
118
|
-
`cyclo_manager up`
|
|
118
|
+
`cyclo_manager up` installs the `refresh-host-agent` CLI subcommand into sudoers. It is registered as `sys.executable -m cyclo_manager_cli.cli refresh-host-agent` so systemd updates do not depend on `PATH`. After that, UI-triggered updates can refresh the host agent non-interactively. The command is idempotent and refreshes the socket directory, sudoers file, systemd unit, and service state after package upgrades.
|
|
119
119
|
|
|
120
120
|
Repository scanning uses `CYCLO_HOST_AGENT_WORKSPACE` when set. Otherwise it uses the service user's home directory, except root-only devices with `/data/docker`, where `/data/docker` is used automatically.
|
|
121
121
|
|
|
@@ -19,13 +19,10 @@
|
|
|
19
19
|
"""System-level endpoints for the host agent."""
|
|
20
20
|
|
|
21
21
|
import asyncio
|
|
22
|
-
import logging
|
|
23
22
|
import sys
|
|
24
23
|
|
|
25
24
|
from fastapi import APIRouter, HTTPException, status
|
|
26
25
|
|
|
27
|
-
logger = logging.getLogger(__name__)
|
|
28
|
-
|
|
29
26
|
router = APIRouter(prefix='/system', tags=['system'])
|
|
30
27
|
|
|
31
28
|
_update_status: dict = {'phase': 'idle', 'output': '', 'error': ''}
|
|
@@ -57,7 +54,7 @@ async def _run_update() -> None:
|
|
|
57
54
|
|
|
58
55
|
@router.post('/update')
|
|
59
56
|
async def start_update() -> dict:
|
|
60
|
-
"""
|
|
57
|
+
"""Run cyclo_manager update in the background."""
|
|
61
58
|
global _update_status
|
|
62
59
|
|
|
63
60
|
if _update_status.get('phase') == 'updating':
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyclo-manager
|
|
3
|
-
Version: 1.0.0.
|
|
3
|
+
Version: 1.0.0.dev6
|
|
4
4
|
Summary: cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack.
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
Requires-Python: >=3.10
|
|
@@ -120,16 +120,16 @@ The pip package installs a small **FastAPI** server that listens on a **Unix dom
|
|
|
120
120
|
|------|------|
|
|
121
121
|
| Socket | `/var/run/robotis/agent_sockets/host/host_agent.sock` |
|
|
122
122
|
| systemd unit | `cyclo_host_agent.service` |
|
|
123
|
-
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; skipped on root-only devices) |
|
|
123
|
+
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; `refresh-host-agent` CLI subcommand for UI updates; skipped on root-only devices) |
|
|
124
124
|
|
|
125
125
|
The API container reaches it at `/agents/host/host_agent.sock` (see bundled `config.yml`).
|
|
126
126
|
|
|
127
127
|
**Responsibilities:**
|
|
128
128
|
|
|
129
129
|
- List and update **`~/ROBOTIS-GIT/*`** git repositories (Version Management in the UI)
|
|
130
|
-
- Run
|
|
130
|
+
- Run Cyclo Manager package updates from the UI by delegating to `cyclo_manager update`
|
|
131
131
|
|
|
132
|
-
`cyclo_manager up`
|
|
132
|
+
`cyclo_manager up` installs the `refresh-host-agent` CLI subcommand into sudoers. It is registered as `sys.executable -m cyclo_manager_cli.cli refresh-host-agent` so systemd updates do not depend on `PATH`. After that, UI-triggered updates can refresh the host agent non-interactively. The command is idempotent and refreshes the socket directory, sudoers file, systemd unit, and service state after package upgrades.
|
|
133
133
|
|
|
134
134
|
Repository scanning uses `CYCLO_HOST_AGENT_WORKSPACE` when set. Otherwise it uses the service user's home directory, except root-only devices with `/data/docker`, where `/data/docker` is used automatically.
|
|
135
135
|
|
|
@@ -160,14 +160,22 @@ def _install_sudoers(user: str) -> bool:
|
|
|
160
160
|
"""
|
|
161
161
|
Write sudoers rules for cyclo_manager.
|
|
162
162
|
|
|
163
|
-
Grant NOPASSWD for udev operations
|
|
164
|
-
(cp to /etc/udev/rules.d/, udevadm control/trigger).
|
|
163
|
+
Grant NOPASSWD for udev operations and the root-only host-agent refresh command.
|
|
165
164
|
"""
|
|
166
|
-
|
|
165
|
+
if not sys.executable:
|
|
166
|
+
print(
|
|
167
|
+
'Python executable is unknown. '
|
|
168
|
+
'Run `pip install cyclo-manager` and retry.',
|
|
169
|
+
file=sys.stderr,
|
|
170
|
+
)
|
|
171
|
+
return False
|
|
172
|
+
|
|
173
|
+
print(' Installing sudoers rules (cp, udevadm, host-agent refresh command)...')
|
|
167
174
|
sudoers_content = (
|
|
168
175
|
f'{user} ALL=(ALL) NOPASSWD: /usr/bin/cp, '
|
|
169
176
|
f'/usr/bin/udevadm control --reload-rules, '
|
|
170
|
-
f'/usr/bin/udevadm trigger
|
|
177
|
+
f'/usr/bin/udevadm trigger, '
|
|
178
|
+
f'{sys.executable} -m cyclo_manager_cli.cli refresh-host-agent\n'
|
|
171
179
|
)
|
|
172
180
|
sudoers_file = '/etc/sudoers.d/cyclo_manager'
|
|
173
181
|
try:
|
|
@@ -188,7 +196,7 @@ def _install_sudoers(user: str) -> bool:
|
|
|
188
196
|
return False
|
|
189
197
|
|
|
190
198
|
|
|
191
|
-
def _ensure_host_agent() -> int:
|
|
199
|
+
def _ensure_host_agent(restart_no_block: bool = False) -> int:
|
|
192
200
|
"""
|
|
193
201
|
Install or refresh cyclo_host_agent: systemd unit, socket dir, and service start.
|
|
194
202
|
|
|
@@ -261,8 +269,11 @@ WantedBy=multi-user.target
|
|
|
261
269
|
capture_output=True,
|
|
262
270
|
)
|
|
263
271
|
print(f' Starting {HOST_AGENT_SERVICE}...')
|
|
272
|
+
restart_cmd = ['systemctl', 'restart', f'{HOST_AGENT_SERVICE}.service']
|
|
273
|
+
if restart_no_block:
|
|
274
|
+
restart_cmd.insert(1, '--no-block')
|
|
264
275
|
subprocess.run(
|
|
265
|
-
_sudo_cmd(
|
|
276
|
+
_sudo_cmd(restart_cmd),
|
|
266
277
|
check=True,
|
|
267
278
|
capture_output=True,
|
|
268
279
|
)
|
|
@@ -276,6 +287,46 @@ WantedBy=multi-user.target
|
|
|
276
287
|
return 1
|
|
277
288
|
|
|
278
289
|
|
|
290
|
+
def _refresh_host_agent_after_update() -> int:
|
|
291
|
+
"""Refresh host agent with the sudoers-registered cyclo_manager command when possible."""
|
|
292
|
+
if os.geteuid() == 0:
|
|
293
|
+
return _ensure_host_agent(restart_no_block=True)
|
|
294
|
+
if not sys.executable:
|
|
295
|
+
print(
|
|
296
|
+
'Python executable is unknown; falling back to setup.',
|
|
297
|
+
file=sys.stderr,
|
|
298
|
+
)
|
|
299
|
+
return _ensure_host_agent() if sys.stdin.isatty() else 1
|
|
300
|
+
|
|
301
|
+
refresh_command = [sys.executable, '-m', 'cyclo_manager_cli.cli', 'refresh-host-agent']
|
|
302
|
+
print(f'Refreshing host agent with sudo command: {" ".join(refresh_command)}')
|
|
303
|
+
try:
|
|
304
|
+
subprocess.run(['sudo', '-n', *refresh_command], check=True)
|
|
305
|
+
return 0
|
|
306
|
+
except subprocess.CalledProcessError as e:
|
|
307
|
+
if sys.stdin.isatty():
|
|
308
|
+
print(
|
|
309
|
+
'Warning: sudo refresh command failed; falling back to interactive setup.',
|
|
310
|
+
file=sys.stderr,
|
|
311
|
+
)
|
|
312
|
+
return _ensure_host_agent()
|
|
313
|
+
print(f'Host-agent refresh command failed: {e}', file=sys.stderr)
|
|
314
|
+
return e.returncode
|
|
315
|
+
except FileNotFoundError:
|
|
316
|
+
if sys.stdin.isatty():
|
|
317
|
+
return _ensure_host_agent()
|
|
318
|
+
print('sudo not found; cannot refresh host agent service.', file=sys.stderr)
|
|
319
|
+
return 1
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
def cmd_refresh_host_agent(args: argparse.Namespace) -> int:
|
|
323
|
+
"""Refresh the host agent from sudoers after a package update."""
|
|
324
|
+
if os.geteuid() != 0:
|
|
325
|
+
print('cyclo_manager refresh-host-agent must run as root.', file=sys.stderr)
|
|
326
|
+
return 1
|
|
327
|
+
return _ensure_host_agent(restart_no_block=True)
|
|
328
|
+
|
|
329
|
+
|
|
279
330
|
def cmd_up(args: argparse.Namespace) -> int:
|
|
280
331
|
"""Start API + UI; create zenoh and noVNC containers without starting them."""
|
|
281
332
|
print('--- cyclo_manager up ---')
|
|
@@ -445,7 +496,7 @@ def cmd_update(args: argparse.Namespace) -> int:
|
|
|
445
496
|
return e.returncode
|
|
446
497
|
|
|
447
498
|
print('Refreshing host agent (unit, socket, sudoers)...')
|
|
448
|
-
if
|
|
499
|
+
if _refresh_host_agent_after_update() != 0:
|
|
449
500
|
print('Warning: Failed to refresh host agent service.', file=sys.stderr)
|
|
450
501
|
return 1
|
|
451
502
|
|
|
@@ -486,6 +537,12 @@ def main() -> int:
|
|
|
486
537
|
)
|
|
487
538
|
update_parser.set_defaults(func=cmd_update)
|
|
488
539
|
|
|
540
|
+
refresh_parser = sub.add_parser(
|
|
541
|
+
'refresh-host-agent',
|
|
542
|
+
help='Refresh cyclo_host_agent service after package update',
|
|
543
|
+
)
|
|
544
|
+
refresh_parser.set_defaults(func=cmd_refresh_host_agent)
|
|
545
|
+
|
|
489
546
|
args = parser.parse_args()
|
|
490
547
|
if not args.command:
|
|
491
548
|
parser.print_help()
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cyclo-manager"
|
|
7
|
-
version = "1.0.0.
|
|
7
|
+
version = "1.0.0.dev6"
|
|
8
8
|
description = "cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "Apache-2.0"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{cyclo_manager-1.0.0.dev5 → cyclo_manager-1.0.0.dev6}/cyclo_manager_cli/docker/docker-compose.yml
RENAMED
|
File without changes
|
|
File without changes
|