cyclo-manager 0.2.0.dev12__tar.gz → 0.2.1.dev0__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.dev12 → cyclo_manager-0.2.1.dev0}/PKG-INFO +5 -11
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/README.md +4 -10
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/main.py +3 -4
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/models.py +8 -0
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/routers/repos.py +23 -7
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/routers/update.py +4 -2
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/PKG-INFO +5 -11
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/__init__.py +1 -1
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/cli.py +12 -5
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/config/config.yml +1 -1
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/docker/docker-compose.yml +2 -2
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/pyproject.toml +1 -1
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/setup.cfg +1 -1
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/__init__.py +0 -0
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_host_agent/routers/__init__.py +0 -0
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/SOURCES.txt +0 -0
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/dependency_links.txt +0 -0
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/entry_points.txt +0 -0
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/requires.txt +0 -0
- {cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyclo-manager
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1.dev0
|
|
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
|
|
@@ -67,12 +67,6 @@ From **PyPI**:
|
|
|
67
67
|
pip install cyclo-manager
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Pre-release versions:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
pip install --pre cyclo-manager==0.2.0.dev0
|
|
74
|
-
```
|
|
75
|
-
|
|
76
70
|
If `cyclo_manager` is not on `PATH`, add the user script directory:
|
|
77
71
|
|
|
78
72
|
```bash
|
|
@@ -144,8 +138,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
|
|
|
144
138
|
|
|
145
139
|
| Compose service | Container name | `cyclo_manager up` | Image (example) |
|
|
146
140
|
|-----------------|----------------|--------------------|-----------------|
|
|
147
|
-
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.
|
|
148
|
-
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.
|
|
141
|
+
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.1` |
|
|
142
|
+
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.1` |
|
|
149
143
|
| `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
|
|
150
144
|
| `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
|
|
151
145
|
|
|
@@ -177,7 +171,7 @@ robot_container: ai_worker
|
|
|
177
171
|
|
|
178
172
|
sockets:
|
|
179
173
|
ai_worker: "/agents/ai_worker/s6_agent.sock"
|
|
180
|
-
|
|
174
|
+
cyclo_intelligence: "/agents/cyclo_intelligence/s6_agent.sock"
|
|
181
175
|
host_agent: "/agents/host/host_agent.sock"
|
|
182
176
|
```
|
|
183
177
|
|
|
@@ -198,7 +192,7 @@ On the host, sockets typically live under:
|
|
|
198
192
|
```text
|
|
199
193
|
/var/run/robotis/agent_sockets/
|
|
200
194
|
├── ai_worker/s6_agent.sock
|
|
201
|
-
├──
|
|
195
|
+
├── cyclo_intelligence/s6_agent.sock
|
|
202
196
|
└── host/host_agent.sock ← created by cyclo_manager up
|
|
203
197
|
```
|
|
204
198
|
|
|
@@ -53,12 +53,6 @@ From **PyPI**:
|
|
|
53
53
|
pip install cyclo-manager
|
|
54
54
|
```
|
|
55
55
|
|
|
56
|
-
Pre-release versions:
|
|
57
|
-
|
|
58
|
-
```bash
|
|
59
|
-
pip install --pre cyclo-manager==0.2.0.dev0
|
|
60
|
-
```
|
|
61
|
-
|
|
62
56
|
If `cyclo_manager` is not on `PATH`, add the user script directory:
|
|
63
57
|
|
|
64
58
|
```bash
|
|
@@ -130,8 +124,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
|
|
|
130
124
|
|
|
131
125
|
| Compose service | Container name | `cyclo_manager up` | Image (example) |
|
|
132
126
|
|-----------------|----------------|--------------------|-----------------|
|
|
133
|
-
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.
|
|
134
|
-
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.
|
|
127
|
+
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.1` |
|
|
128
|
+
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.1` |
|
|
135
129
|
| `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
|
|
136
130
|
| `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
|
|
137
131
|
|
|
@@ -163,7 +157,7 @@ robot_container: ai_worker
|
|
|
163
157
|
|
|
164
158
|
sockets:
|
|
165
159
|
ai_worker: "/agents/ai_worker/s6_agent.sock"
|
|
166
|
-
|
|
160
|
+
cyclo_intelligence: "/agents/cyclo_intelligence/s6_agent.sock"
|
|
167
161
|
host_agent: "/agents/host/host_agent.sock"
|
|
168
162
|
```
|
|
169
163
|
|
|
@@ -184,7 +178,7 @@ On the host, sockets typically live under:
|
|
|
184
178
|
```text
|
|
185
179
|
/var/run/robotis/agent_sockets/
|
|
186
180
|
├── ai_worker/s6_agent.sock
|
|
187
|
-
├──
|
|
181
|
+
├── cyclo_intelligence/s6_agent.sock
|
|
188
182
|
└── host/host_agent.sock ← created by cyclo_manager up
|
|
189
183
|
```
|
|
190
184
|
|
|
@@ -21,10 +21,9 @@
|
|
|
21
21
|
import logging
|
|
22
22
|
from pathlib import Path
|
|
23
23
|
|
|
24
|
-
import uvicorn
|
|
25
|
-
from fastapi import FastAPI
|
|
26
|
-
|
|
27
24
|
from cyclo_host_agent.routers import repos, update
|
|
25
|
+
from fastapi import FastAPI
|
|
26
|
+
import uvicorn
|
|
28
27
|
|
|
29
28
|
logging.basicConfig(
|
|
30
29
|
level=logging.INFO,
|
|
@@ -37,7 +36,7 @@ SOCKET_PATH = '/var/run/robotis/agent_sockets/host/host_agent.sock'
|
|
|
37
36
|
app = FastAPI(
|
|
38
37
|
title='cyclo_host_agent',
|
|
39
38
|
description='Host agent for Cyclo Manager: repo management.',
|
|
40
|
-
version='0.2.
|
|
39
|
+
version='0.2.1',
|
|
41
40
|
)
|
|
42
41
|
|
|
43
42
|
app.include_router(repos.router)
|
|
@@ -71,6 +71,14 @@ class RepoStatusResponse(BaseModel):
|
|
|
71
71
|
has_changes: bool
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
class RepoBranchCheckResponse(BaseModel):
|
|
75
|
+
"""Response for GET /repos/{name}/branch."""
|
|
76
|
+
|
|
77
|
+
name: str
|
|
78
|
+
branch: Optional[str] = None
|
|
79
|
+
allowed: bool
|
|
80
|
+
|
|
81
|
+
|
|
74
82
|
class UpdateRequest(BaseModel):
|
|
75
83
|
"""Request body for POST /repos/{name}/update."""
|
|
76
84
|
|
|
@@ -20,23 +20,23 @@
|
|
|
20
20
|
|
|
21
21
|
import asyncio
|
|
22
22
|
import os
|
|
23
|
-
import re
|
|
24
23
|
from pathlib import Path
|
|
24
|
+
import re
|
|
25
25
|
from typing import Optional
|
|
26
26
|
|
|
27
|
-
from fastapi import APIRouter, HTTPException, status
|
|
28
|
-
|
|
29
27
|
from cyclo_host_agent.models import (
|
|
30
28
|
ContainerScriptResponse,
|
|
31
29
|
FileChange,
|
|
30
|
+
RepoBranchCheckResponse,
|
|
32
31
|
RepoInfo,
|
|
33
32
|
RepoListResponse,
|
|
34
33
|
RepoStatusResponse,
|
|
35
|
-
RepoUpdateStatus,
|
|
36
34
|
RepoUpdatesResponse,
|
|
35
|
+
RepoUpdateStatus,
|
|
37
36
|
UpdateRequest,
|
|
38
37
|
UpdateResponse,
|
|
39
38
|
)
|
|
39
|
+
from fastapi import APIRouter, HTTPException, status
|
|
40
40
|
|
|
41
41
|
router = APIRouter(prefix='/repos', tags=['repos'])
|
|
42
42
|
|
|
@@ -109,12 +109,12 @@ async def _ensure_allowed_branch(repo_path: Path) -> None:
|
|
|
109
109
|
allowed = ', '.join(sorted(ALLOWED_UPDATE_BRANCHES))
|
|
110
110
|
if branch:
|
|
111
111
|
detail = (
|
|
112
|
-
f
|
|
112
|
+
f'Updates are only allowed on branches: {allowed}. '
|
|
113
113
|
f"Current branch is '{branch}'."
|
|
114
114
|
)
|
|
115
115
|
else:
|
|
116
116
|
detail = (
|
|
117
|
-
f
|
|
117
|
+
f'Updates are only allowed on branches: {allowed}. '
|
|
118
118
|
'Could not determine the current branch (detached HEAD?).'
|
|
119
119
|
)
|
|
120
120
|
raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=detail)
|
|
@@ -221,7 +221,12 @@ async def _repo_update_status(repo_path: Path) -> Optional[RepoUpdateStatus]:
|
|
|
221
221
|
|
|
222
222
|
latest = await _fetch_latest_tag(remote_url)
|
|
223
223
|
if not latest:
|
|
224
|
-
return RepoUpdateStatus(
|
|
224
|
+
return RepoUpdateStatus(
|
|
225
|
+
name=repo_path.name,
|
|
226
|
+
branch=branch,
|
|
227
|
+
current_version=current,
|
|
228
|
+
has_update=False,
|
|
229
|
+
)
|
|
225
230
|
|
|
226
231
|
return RepoUpdateStatus(
|
|
227
232
|
name=repo_path.name,
|
|
@@ -356,6 +361,17 @@ async def list_repos() -> RepoListResponse:
|
|
|
356
361
|
return RepoListResponse(repos=repos, workspace_path=str(WORKSPACE_PATH))
|
|
357
362
|
|
|
358
363
|
|
|
364
|
+
@router.get('/{name}/branch', response_model=RepoBranchCheckResponse)
|
|
365
|
+
async def get_repo_branch(name: str) -> RepoBranchCheckResponse:
|
|
366
|
+
repo_path = _get_repo(name)
|
|
367
|
+
branch = await _current_branch(repo_path)
|
|
368
|
+
return RepoBranchCheckResponse(
|
|
369
|
+
name=name,
|
|
370
|
+
branch=branch,
|
|
371
|
+
allowed=branch in ALLOWED_UPDATE_BRANCHES,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
|
|
359
375
|
@router.get('/{name}/status', response_model=RepoStatusResponse)
|
|
360
376
|
async def get_repo_status(name: str) -> RepoStatusResponse:
|
|
361
377
|
repo_path = _get_repo(name)
|
|
@@ -62,6 +62,10 @@ async def start_update() -> dict:
|
|
|
62
62
|
raise HTTPException(status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
|
|
63
63
|
detail='cyclo_manager command not found')
|
|
64
64
|
|
|
65
|
+
if _update_status.get('phase') == 'updating':
|
|
66
|
+
raise HTTPException(status_code=status.HTTP_409_CONFLICT,
|
|
67
|
+
detail='Update already in progress')
|
|
68
|
+
|
|
65
69
|
_update_status = {'phase': 'updating', 'output': '', 'error': ''}
|
|
66
70
|
asyncio.create_task(_run_update(cyclo_exe))
|
|
67
71
|
return {'status': 'update started'}
|
|
@@ -71,5 +75,3 @@ async def start_update() -> dict:
|
|
|
71
75
|
async def get_update_status() -> dict:
|
|
72
76
|
"""Return the current update phase and stored outputs."""
|
|
73
77
|
return _update_status
|
|
74
|
-
|
|
75
|
-
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cyclo-manager
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1.dev0
|
|
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
|
|
@@ -67,12 +67,6 @@ From **PyPI**:
|
|
|
67
67
|
pip install cyclo-manager
|
|
68
68
|
```
|
|
69
69
|
|
|
70
|
-
Pre-release versions:
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
pip install --pre cyclo-manager==0.2.0.dev0
|
|
74
|
-
```
|
|
75
|
-
|
|
76
70
|
If `cyclo_manager` is not on `PATH`, add the user script directory:
|
|
77
71
|
|
|
78
72
|
```bash
|
|
@@ -144,8 +138,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
|
|
|
144
138
|
|
|
145
139
|
| Compose service | Container name | `cyclo_manager up` | Image (example) |
|
|
146
140
|
|-----------------|----------------|--------------------|-----------------|
|
|
147
|
-
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.
|
|
148
|
-
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.
|
|
141
|
+
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.2.1` |
|
|
142
|
+
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.2.1` |
|
|
149
143
|
| `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
|
|
150
144
|
| `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
|
|
151
145
|
|
|
@@ -177,7 +171,7 @@ robot_container: ai_worker
|
|
|
177
171
|
|
|
178
172
|
sockets:
|
|
179
173
|
ai_worker: "/agents/ai_worker/s6_agent.sock"
|
|
180
|
-
|
|
174
|
+
cyclo_intelligence: "/agents/cyclo_intelligence/s6_agent.sock"
|
|
181
175
|
host_agent: "/agents/host/host_agent.sock"
|
|
182
176
|
```
|
|
183
177
|
|
|
@@ -198,7 +192,7 @@ On the host, sockets typically live under:
|
|
|
198
192
|
```text
|
|
199
193
|
/var/run/robotis/agent_sockets/
|
|
200
194
|
├── ai_worker/s6_agent.sock
|
|
201
|
-
├──
|
|
195
|
+
├── cyclo_intelligence/s6_agent.sock
|
|
202
196
|
└── host/host_agent.sock ← created by cyclo_manager up
|
|
203
197
|
```
|
|
204
198
|
|
|
@@ -95,7 +95,7 @@ def _setup_socket_dir(user: str) -> bool:
|
|
|
95
95
|
check=True,
|
|
96
96
|
capture_output=True,
|
|
97
97
|
)
|
|
98
|
-
print(
|
|
98
|
+
print(' [3/3] Removing stale socket file (if any)...')
|
|
99
99
|
subprocess.run(
|
|
100
100
|
['sudo', 'rm', '-f', HOST_AGENT_SOCKET],
|
|
101
101
|
check=True,
|
|
@@ -109,8 +109,10 @@ def _setup_socket_dir(user: str) -> bool:
|
|
|
109
109
|
|
|
110
110
|
def _install_sudoers(user: str) -> bool:
|
|
111
111
|
"""
|
|
112
|
-
Write
|
|
113
|
-
|
|
112
|
+
Write sudoers rules for cyclo_manager.
|
|
113
|
+
|
|
114
|
+
Grant NOPASSWD for udev operations needed by container.sh
|
|
115
|
+
(cp to /etc/udev/rules.d/, udevadm control/trigger).
|
|
114
116
|
"""
|
|
115
117
|
print(' Installing sudoers rules (cp, udevadm)...')
|
|
116
118
|
sudoers_content = (
|
|
@@ -272,7 +274,10 @@ def _teardown_host_agent() -> None:
|
|
|
272
274
|
steps = [
|
|
273
275
|
(['sudo', 'systemctl', 'stop', f'{HOST_AGENT_SERVICE}.service'], 'stop service'),
|
|
274
276
|
(['sudo', 'systemctl', 'disable', f'{HOST_AGENT_SERVICE}.service'], 'disable service'),
|
|
275
|
-
(
|
|
277
|
+
(
|
|
278
|
+
['sudo', 'rm', '-f', f'/etc/systemd/system/{HOST_AGENT_SERVICE}.service'],
|
|
279
|
+
'remove unit file',
|
|
280
|
+
),
|
|
276
281
|
(['sudo', 'systemctl', 'daemon-reload'], 'daemon-reload'),
|
|
277
282
|
(['sudo', 'rm', '-f', '/etc/sudoers.d/cyclo_manager'], 'remove sudoers'),
|
|
278
283
|
(['sudo', 'rm', '-rf', HOST_AGENT_SOCKET_DIR], 'remove socket dir'),
|
|
@@ -370,7 +375,9 @@ def cmd_update(args: argparse.Namespace) -> int:
|
|
|
370
375
|
return e.returncode
|
|
371
376
|
|
|
372
377
|
print('Refreshing host agent (unit, socket, sudoers)...')
|
|
373
|
-
_ensure_host_agent()
|
|
378
|
+
if _ensure_host_agent() != 0:
|
|
379
|
+
print('Warning: Failed to refresh host agent service.', file=sys.stderr)
|
|
380
|
+
return 1
|
|
374
381
|
|
|
375
382
|
print('cyclo_manager update completed.')
|
|
376
383
|
return 0
|
{cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager_cli/docker/docker-compose.yml
RENAMED
|
@@ -11,7 +11,7 @@ services:
|
|
|
11
11
|
|
|
12
12
|
cyclo_manager:
|
|
13
13
|
container_name: cyclo_manager
|
|
14
|
-
image: robotis/cyclo-manager:0.2.
|
|
14
|
+
image: robotis/cyclo-manager:0.2.1
|
|
15
15
|
restart: always
|
|
16
16
|
network_mode: host
|
|
17
17
|
volumes:
|
|
@@ -27,7 +27,7 @@ services:
|
|
|
27
27
|
|
|
28
28
|
ui:
|
|
29
29
|
container_name: cyclo_manager_ui
|
|
30
|
-
image: robotis/cyclo-manager-ui:0.2.
|
|
30
|
+
image: robotis/cyclo-manager-ui:0.2.1
|
|
31
31
|
restart: always
|
|
32
32
|
network_mode: host
|
|
33
33
|
environment:
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cyclo-manager"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1.dev0"
|
|
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
|
{cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{cyclo_manager-0.2.0.dev12 → cyclo_manager-0.2.1.dev0}/cyclo_manager.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|