cyclo-manager 0.2.0.dev9__tar.gz → 0.2.0.dev11__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-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/PKG-INFO +1 -1
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_host_agent/routers/update.py +0 -21
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager.egg-info/PKG-INFO +1 -1
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager_cli/cli.py +41 -8
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/pyproject.toml +1 -1
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/README.md +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_host_agent/__init__.py +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_host_agent/main.py +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_host_agent/models.py +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_host_agent/routers/__init__.py +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_host_agent/routers/repos.py +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager.egg-info/SOURCES.txt +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager.egg-info/dependency_links.txt +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager.egg-info/entry_points.txt +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager.egg-info/requires.txt +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager.egg-info/top_level.txt +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager_cli/__init__.py +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager_cli/config/config.yml +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager_cli/docker/docker-compose.yml +0 -0
- {cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyclo-manager
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev11
|
|
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
|
|
@@ -21,8 +21,6 @@
|
|
|
21
21
|
import asyncio
|
|
22
22
|
import logging
|
|
23
23
|
import shutil
|
|
24
|
-
import time
|
|
25
|
-
import subprocess
|
|
26
24
|
|
|
27
25
|
from fastapi import APIRouter, HTTPException, status
|
|
28
26
|
|
|
@@ -75,22 +73,3 @@ async def get_update_status() -> dict:
|
|
|
75
73
|
return _update_status
|
|
76
74
|
|
|
77
75
|
|
|
78
|
-
def _delayed_exec(cmd: list[str], delay: float = 2.0) -> None:
|
|
79
|
-
time.sleep(delay)
|
|
80
|
-
subprocess.run(cmd, check=False)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
@router.post('/reboot')
|
|
84
|
-
async def reboot_host() -> dict:
|
|
85
|
-
"""Reboot the host machine after returning a response."""
|
|
86
|
-
loop = asyncio.get_event_loop()
|
|
87
|
-
loop.run_in_executor(None, _delayed_exec, ['sudo', '/usr/sbin/reboot'])
|
|
88
|
-
return {'status': 'rebooting'}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
@router.post('/shutdown')
|
|
92
|
-
async def shutdown_host() -> dict:
|
|
93
|
-
"""Shut down the host machine after returning a response."""
|
|
94
|
-
loop = asyncio.get_event_loop()
|
|
95
|
-
loop.run_in_executor(None, _delayed_exec, ['sudo', '/usr/sbin/poweroff'])
|
|
96
|
-
return {'status': 'shutting_down'}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyclo-manager
|
|
3
|
-
Version: 0.2.0.
|
|
3
|
+
Version: 0.2.0.dev11
|
|
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
|
|
@@ -27,6 +27,7 @@ import argparse
|
|
|
27
27
|
import os
|
|
28
28
|
from pathlib import Path
|
|
29
29
|
import shutil
|
|
30
|
+
import socket
|
|
30
31
|
import subprocess
|
|
31
32
|
import sys
|
|
32
33
|
|
|
@@ -81,17 +82,20 @@ def _setup_socket_dir(user: str) -> bool:
|
|
|
81
82
|
Only host/ is chowned so other agent sockets under agent_sockets/ are untouched.
|
|
82
83
|
Removes a stale socket file (e.g. left by a previous root-owned service).
|
|
83
84
|
"""
|
|
85
|
+
print(f' [1/3] Creating socket directory {HOST_AGENT_SOCKET_DIR}...')
|
|
84
86
|
try:
|
|
85
87
|
subprocess.run(
|
|
86
88
|
['sudo', 'mkdir', '-p', HOST_AGENT_SOCKET_DIR],
|
|
87
89
|
check=True,
|
|
88
90
|
capture_output=True,
|
|
89
91
|
)
|
|
92
|
+
print(f' [2/3] Setting ownership to {user}:{user}...')
|
|
90
93
|
subprocess.run(
|
|
91
94
|
['sudo', 'chown', f'{user}:{user}', HOST_AGENT_SOCKET_DIR],
|
|
92
95
|
check=True,
|
|
93
96
|
capture_output=True,
|
|
94
97
|
)
|
|
98
|
+
print(f' [3/3] Removing stale socket file (if any)...')
|
|
95
99
|
subprocess.run(
|
|
96
100
|
['sudo', 'rm', '-f', HOST_AGENT_SOCKET],
|
|
97
101
|
check=True,
|
|
@@ -108,6 +112,7 @@ def _install_sudoers(user: str) -> bool:
|
|
|
108
112
|
Write /etc/sudoers.d/cyclo_manager granting NOPASSWD for udev operations
|
|
109
113
|
needed by container.sh (cp to /etc/udev/rules.d/, udevadm control/trigger).
|
|
110
114
|
"""
|
|
115
|
+
print(' Installing sudoers rules (cp, udevadm, reboot, poweroff)...')
|
|
111
116
|
sudoers_content = (
|
|
112
117
|
f'{user} ALL=(ALL) NOPASSWD: /usr/bin/cp, '
|
|
113
118
|
f'/usr/bin/udevadm control --reload-rules, '
|
|
@@ -170,6 +175,8 @@ After=network.target
|
|
|
170
175
|
Type=simple
|
|
171
176
|
User={user}
|
|
172
177
|
Group={user}
|
|
178
|
+
RuntimeDirectory=robotis/agent_sockets/host
|
|
179
|
+
RuntimeDirectoryMode=0755
|
|
173
180
|
ExecStart={agent_exe}
|
|
174
181
|
Environment=HOME={user_home}
|
|
175
182
|
Restart=always
|
|
@@ -181,18 +188,30 @@ WantedBy=multi-user.target
|
|
|
181
188
|
|
|
182
189
|
service_file = f'/etc/systemd/system/{HOST_AGENT_SERVICE}.service'
|
|
183
190
|
|
|
184
|
-
print(f'
|
|
191
|
+
print(f'Setting up {HOST_AGENT_SERVICE} systemd service (user={user})...')
|
|
185
192
|
try:
|
|
193
|
+
print(f' Writing unit file to {service_file}...')
|
|
186
194
|
subprocess.run(
|
|
187
195
|
['sudo', 'tee', service_file],
|
|
188
196
|
input=service_content.encode(),
|
|
189
197
|
capture_output=True,
|
|
190
198
|
check=True,
|
|
191
199
|
)
|
|
192
|
-
|
|
193
|
-
subprocess.run(['sudo', 'systemctl', '
|
|
194
|
-
|
|
195
|
-
|
|
200
|
+
print(' Running systemctl daemon-reload...')
|
|
201
|
+
subprocess.run(['sudo', 'systemctl', 'daemon-reload'], check=True, capture_output=True)
|
|
202
|
+
print(f' Enabling {HOST_AGENT_SERVICE}...')
|
|
203
|
+
subprocess.run(
|
|
204
|
+
['sudo', 'systemctl', 'enable', f'{HOST_AGENT_SERVICE}.service'],
|
|
205
|
+
check=True,
|
|
206
|
+
capture_output=True,
|
|
207
|
+
)
|
|
208
|
+
print(f' Starting {HOST_AGENT_SERVICE}...')
|
|
209
|
+
subprocess.run(
|
|
210
|
+
['sudo', 'systemctl', 'restart', f'{HOST_AGENT_SERVICE}.service'],
|
|
211
|
+
check=True,
|
|
212
|
+
capture_output=True,
|
|
213
|
+
)
|
|
214
|
+
print(f' {HOST_AGENT_SERVICE} is running.')
|
|
196
215
|
return 0
|
|
197
216
|
except subprocess.CalledProcessError as e:
|
|
198
217
|
print(f'Failed to install host agent service: {e}', file=sys.stderr)
|
|
@@ -204,6 +223,9 @@ WantedBy=multi-user.target
|
|
|
204
223
|
|
|
205
224
|
def cmd_up(args: argparse.Namespace) -> int:
|
|
206
225
|
"""Start API + UI; create zenoh and noVNC containers without starting them."""
|
|
226
|
+
print('--- cyclo_manager up ---')
|
|
227
|
+
|
|
228
|
+
print('[1/3] Setting up host agent...')
|
|
207
229
|
if _ensure_host_agent() != 0:
|
|
208
230
|
print('Warning: Failed to install host agent service.', file=sys.stderr)
|
|
209
231
|
|
|
@@ -217,11 +239,15 @@ def cmd_up(args: argparse.Namespace) -> int:
|
|
|
217
239
|
return 1
|
|
218
240
|
env = os.environ.copy()
|
|
219
241
|
env['CYCLO_MANAGER_CONFIG_FILE'] = str(config_path)
|
|
242
|
+
env.setdefault('HOSTNAME', socket.gethostname())
|
|
220
243
|
base = ['docker', 'compose', '-f', str(compose_path)]
|
|
221
244
|
try:
|
|
222
245
|
if args.pull:
|
|
246
|
+
print('[2/3] Pulling latest images...')
|
|
223
247
|
subprocess.run([*base, 'pull'], env=env, check=True)
|
|
248
|
+
print(f'[2/3] Starting containers: {", ".join(COMPOSE_SERVICES_UP)}...')
|
|
224
249
|
subprocess.run([*base, 'up', '-d', *COMPOSE_SERVICES_UP], env=env, check=True)
|
|
250
|
+
print(f'[3/3] Creating (not starting): {", ".join(COMPOSE_SERVICES_CREATE_ONLY)}...')
|
|
225
251
|
subprocess.run(
|
|
226
252
|
[*base, 'create', '--no-recreate', *COMPOSE_SERVICES_CREATE_ONLY],
|
|
227
253
|
env=env,
|
|
@@ -244,23 +270,27 @@ def cmd_up(args: argparse.Namespace) -> int:
|
|
|
244
270
|
|
|
245
271
|
def _teardown_host_agent() -> None:
|
|
246
272
|
"""Stop and remove the host agent service, unit file, sudoers, and socket dir."""
|
|
273
|
+
print(f'Tearing down {HOST_AGENT_SERVICE}...')
|
|
247
274
|
steps = [
|
|
248
275
|
(['sudo', 'systemctl', 'stop', f'{HOST_AGENT_SERVICE}.service'], 'stop service'),
|
|
249
276
|
(['sudo', 'systemctl', 'disable', f'{HOST_AGENT_SERVICE}.service'], 'disable service'),
|
|
250
277
|
(['sudo', 'rm', '-f', f'/etc/systemd/system/{HOST_AGENT_SERVICE}.service'], 'remove unit file'),
|
|
251
|
-
(['sudo', 'systemctl', 'daemon-reload'], 'reload
|
|
278
|
+
(['sudo', 'systemctl', 'daemon-reload'], 'daemon-reload'),
|
|
252
279
|
(['sudo', 'rm', '-f', '/etc/sudoers.d/cyclo_manager'], 'remove sudoers'),
|
|
253
280
|
(['sudo', 'rm', '-rf', HOST_AGENT_SOCKET_DIR], 'remove socket dir'),
|
|
254
281
|
]
|
|
255
282
|
for cmd, desc in steps:
|
|
283
|
+
print(f' {desc}...')
|
|
256
284
|
try:
|
|
257
285
|
subprocess.run(cmd, check=True, capture_output=True)
|
|
258
286
|
except subprocess.CalledProcessError:
|
|
259
|
-
print(f'Warning: failed to {desc}.', file=sys.stderr)
|
|
287
|
+
print(f' Warning: failed to {desc}.', file=sys.stderr)
|
|
260
288
|
|
|
261
289
|
|
|
262
290
|
def cmd_down(args: argparse.Namespace) -> int:
|
|
263
291
|
"""Stop cyclo_manager server, cyclo_manager_ui, and zenoh daemon (docker compose down)."""
|
|
292
|
+
print('--- cyclo_manager down ---')
|
|
293
|
+
|
|
264
294
|
_teardown_host_agent()
|
|
265
295
|
|
|
266
296
|
compose_path = _docker_dir() / 'docker-compose.yml'
|
|
@@ -269,6 +299,7 @@ def cmd_down(args: argparse.Namespace) -> int:
|
|
|
269
299
|
return 1
|
|
270
300
|
env = os.environ.copy()
|
|
271
301
|
env['CYCLO_MANAGER_CONFIG_FILE'] = str(_packaged_config_path())
|
|
302
|
+
env.setdefault('HOSTNAME', socket.gethostname())
|
|
272
303
|
cmd = [
|
|
273
304
|
'docker',
|
|
274
305
|
'compose',
|
|
@@ -276,6 +307,7 @@ def cmd_down(args: argparse.Namespace) -> int:
|
|
|
276
307
|
str(compose_path),
|
|
277
308
|
'down',
|
|
278
309
|
]
|
|
310
|
+
print('Stopping Docker containers (docker compose down)...')
|
|
279
311
|
try:
|
|
280
312
|
subprocess.run(cmd, env=env, check=True)
|
|
281
313
|
except subprocess.CalledProcessError as e:
|
|
@@ -287,7 +319,7 @@ def cmd_down(args: argparse.Namespace) -> int:
|
|
|
287
319
|
)
|
|
288
320
|
return 1
|
|
289
321
|
|
|
290
|
-
print('cyclo_manager
|
|
322
|
+
print('cyclo_manager is down.')
|
|
291
323
|
return 0
|
|
292
324
|
|
|
293
325
|
|
|
@@ -304,6 +336,7 @@ def cmd_update(args: argparse.Namespace) -> int:
|
|
|
304
336
|
return 1
|
|
305
337
|
env = os.environ.copy()
|
|
306
338
|
env['CYCLO_MANAGER_CONFIG_FILE'] = str(_packaged_config_path())
|
|
339
|
+
env.setdefault('HOSTNAME', socket.gethostname())
|
|
307
340
|
base = ['docker', 'compose', '-f', str(compose_path)]
|
|
308
341
|
|
|
309
342
|
print('Stopping containers...')
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cyclo-manager"
|
|
7
|
-
version = "0.2.0.
|
|
7
|
+
version = "0.2.0.dev11"
|
|
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
|
|
File without changes
|
{cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{cyclo_manager-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/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-0.2.0.dev9 → cyclo_manager-0.2.0.dev11}/cyclo_manager_cli/docker/docker-compose.yml
RENAMED
|
File without changes
|
|
File without changes
|