cyclo-manager 1.0.0.dev0__tar.gz → 1.0.0.dev2__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.dev0 → cyclo_manager-1.0.0.dev2}/PKG-INFO +8 -6
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/README.md +7 -5
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_host_agent/routers/repos.py +5 -2
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager.egg-info/PKG-INFO +8 -6
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager_cli/__init__.py +1 -1
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager_cli/cli.py +81 -20
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager_cli/docker/docker-compose.yml +2 -2
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/pyproject.toml +1 -1
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_host_agent/__init__.py +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_host_agent/main.py +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_host_agent/models.py +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_host_agent/routers/__init__.py +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_host_agent/routers/update.py +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager.egg-info/SOURCES.txt +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager.egg-info/dependency_links.txt +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager.egg-info/entry_points.txt +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager.egg-info/requires.txt +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager.egg-info/top_level.txt +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager_cli/config/config.yml +0 -0
- {cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/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.dev2
|
|
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
|
|
@@ -52,9 +52,9 @@ For the full monorepo (API source, UI source, dev compose), see the [repository
|
|
|
52
52
|
|
|
53
53
|
- **Docker** with **Compose v2** (`docker compose` — the legacy `docker-compose` binary alone is not enough)
|
|
54
54
|
- **Python 3.10+**
|
|
55
|
-
- **`sudo`** — required to install the host agent systemd unit, socket directory permissions, and sudoers rules
|
|
55
|
+
- **`sudo`** — required on normal-user hosts to install the host agent systemd unit, socket directory permissions, and sudoers rules
|
|
56
56
|
- For **`cyclo_manager update`:** **`pip`** or **`pip3`** on `PATH`
|
|
57
|
-
- **
|
|
57
|
+
- **Root shell handling** — root is rejected when a normal login user exists. On root-only devices, the host agent is installed as root.
|
|
58
58
|
- **Agent sockets** on the host under `/var/run/robotis/agent_sockets/` (robot containers and host agent). The bundled Compose file bind-mounts this tree into the API container as `/agents/`.
|
|
59
59
|
|
|
60
60
|
---
|
|
@@ -120,7 +120,7 @@ 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) |
|
|
123
|
+
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; 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
|
|
|
@@ -131,6 +131,8 @@ The API container reaches it at `/agents/host/host_agent.sock` (see bundled `con
|
|
|
131
131
|
|
|
132
132
|
`cyclo_manager up` and `cyclo_manager update` both call `_ensure_host_agent()`, which is idempotent — safe to run after upgrades or user changes.
|
|
133
133
|
|
|
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
|
+
|
|
134
136
|
---
|
|
135
137
|
|
|
136
138
|
## Compose services
|
|
@@ -139,8 +141,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
|
|
|
139
141
|
|
|
140
142
|
| Compose service | Container name | `cyclo_manager up` | Image (example) |
|
|
141
143
|
|-----------------|----------------|--------------------|-----------------|
|
|
142
|
-
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.
|
|
143
|
-
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.
|
|
144
|
+
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:1.0.0` |
|
|
145
|
+
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:1.0.0` |
|
|
144
146
|
| `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
|
|
145
147
|
| `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
|
|
146
148
|
|
|
@@ -38,9 +38,9 @@ For the full monorepo (API source, UI source, dev compose), see the [repository
|
|
|
38
38
|
|
|
39
39
|
- **Docker** with **Compose v2** (`docker compose` — the legacy `docker-compose` binary alone is not enough)
|
|
40
40
|
- **Python 3.10+**
|
|
41
|
-
- **`sudo`** — required to install the host agent systemd unit, socket directory permissions, and sudoers rules
|
|
41
|
+
- **`sudo`** — required on normal-user hosts to install the host agent systemd unit, socket directory permissions, and sudoers rules
|
|
42
42
|
- For **`cyclo_manager update`:** **`pip`** or **`pip3`** on `PATH`
|
|
43
|
-
- **
|
|
43
|
+
- **Root shell handling** — root is rejected when a normal login user exists. On root-only devices, the host agent is installed as root.
|
|
44
44
|
- **Agent sockets** on the host under `/var/run/robotis/agent_sockets/` (robot containers and host agent). The bundled Compose file bind-mounts this tree into the API container as `/agents/`.
|
|
45
45
|
|
|
46
46
|
---
|
|
@@ -106,7 +106,7 @@ 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) |
|
|
109
|
+
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; 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
|
|
|
@@ -117,6 +117,8 @@ The API container reaches it at `/agents/host/host_agent.sock` (see bundled `con
|
|
|
117
117
|
|
|
118
118
|
`cyclo_manager up` and `cyclo_manager update` both call `_ensure_host_agent()`, which is idempotent — safe to run after upgrades or user changes.
|
|
119
119
|
|
|
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
|
+
|
|
120
122
|
---
|
|
121
123
|
|
|
122
124
|
## Compose services
|
|
@@ -125,8 +127,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
|
|
|
125
127
|
|
|
126
128
|
| Compose service | Container name | `cyclo_manager up` | Image (example) |
|
|
127
129
|
|-----------------|----------------|--------------------|-----------------|
|
|
128
|
-
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.
|
|
129
|
-
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.
|
|
130
|
+
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:1.0.0` |
|
|
131
|
+
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:1.0.0` |
|
|
130
132
|
| `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
|
|
131
133
|
| `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
|
|
132
134
|
|
|
@@ -43,14 +43,17 @@ router = APIRouter(prefix='/repos', tags=['repos'])
|
|
|
43
43
|
GIT_TIMEOUT = 120.0
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
def
|
|
46
|
+
def _resolve_workspace() -> Path:
|
|
47
|
+
configured_workspace = os.environ.get('CYCLO_HOST_AGENT_WORKSPACE')
|
|
48
|
+
if configured_workspace:
|
|
49
|
+
return Path(configured_workspace).expanduser()
|
|
47
50
|
sudo_user = os.environ.get('SUDO_USER')
|
|
48
51
|
if sudo_user:
|
|
49
52
|
return Path(f'/home/{sudo_user}')
|
|
50
53
|
return Path.home()
|
|
51
54
|
|
|
52
55
|
|
|
53
|
-
WORKSPACE_PATH =
|
|
56
|
+
WORKSPACE_PATH = _resolve_workspace()
|
|
54
57
|
MANAGED_GITHUB_ORG = 'ROBOTIS-GIT'
|
|
55
58
|
ALLOWED_UPDATE_BRANCHES = frozenset({'main', 'jazzy'})
|
|
56
59
|
|
|
@@ -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.dev2
|
|
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
|
|
@@ -52,9 +52,9 @@ For the full monorepo (API source, UI source, dev compose), see the [repository
|
|
|
52
52
|
|
|
53
53
|
- **Docker** with **Compose v2** (`docker compose` — the legacy `docker-compose` binary alone is not enough)
|
|
54
54
|
- **Python 3.10+**
|
|
55
|
-
- **`sudo`** — required to install the host agent systemd unit, socket directory permissions, and sudoers rules
|
|
55
|
+
- **`sudo`** — required on normal-user hosts to install the host agent systemd unit, socket directory permissions, and sudoers rules
|
|
56
56
|
- For **`cyclo_manager update`:** **`pip`** or **`pip3`** on `PATH`
|
|
57
|
-
- **
|
|
57
|
+
- **Root shell handling** — root is rejected when a normal login user exists. On root-only devices, the host agent is installed as root.
|
|
58
58
|
- **Agent sockets** on the host under `/var/run/robotis/agent_sockets/` (robot containers and host agent). The bundled Compose file bind-mounts this tree into the API container as `/agents/`.
|
|
59
59
|
|
|
60
60
|
---
|
|
@@ -120,7 +120,7 @@ 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) |
|
|
123
|
+
| sudoers | `/etc/sudoers.d/cyclo_manager` (`cp`, `udevadm` for container setup scripts; 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
|
|
|
@@ -131,6 +131,8 @@ The API container reaches it at `/agents/host/host_agent.sock` (see bundled `con
|
|
|
131
131
|
|
|
132
132
|
`cyclo_manager up` and `cyclo_manager update` both call `_ensure_host_agent()`, which is idempotent — safe to run after upgrades or user changes.
|
|
133
133
|
|
|
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
|
+
|
|
134
136
|
---
|
|
135
137
|
|
|
136
138
|
## Compose services
|
|
@@ -139,8 +141,8 @@ Defined in [`cyclo_manager_cli/docker/docker-compose.yml`](cyclo_manager_cli/doc
|
|
|
139
141
|
|
|
140
142
|
| Compose service | Container name | `cyclo_manager up` | Image (example) |
|
|
141
143
|
|-----------------|----------------|--------------------|-----------------|
|
|
142
|
-
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:0.
|
|
143
|
-
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:0.
|
|
144
|
+
| `cyclo_manager` | `cyclo_manager` | **Started** | `robotis/cyclo-manager:1.0.0` |
|
|
145
|
+
| `ui` | `cyclo_manager_ui` | **Started** | `robotis/cyclo-manager-ui:1.0.0` |
|
|
144
146
|
| `rmw_zenoh` | `zenoh_daemon` | **Created only** | `robotis/zenoh-daemon:latest` |
|
|
145
147
|
| `novnc-server` | `novnc-server` | **Created only** | `robotis/novnc-server:latest` |
|
|
146
148
|
|
|
@@ -26,6 +26,7 @@ Launches cyclo_manager server and UI via Docker.
|
|
|
26
26
|
import argparse
|
|
27
27
|
import os
|
|
28
28
|
from pathlib import Path
|
|
29
|
+
import pwd
|
|
29
30
|
import shutil
|
|
30
31
|
import socket
|
|
31
32
|
import subprocess
|
|
@@ -36,10 +37,11 @@ HOST_AGENT_SERVICE = 'cyclo_host_agent'
|
|
|
36
37
|
HOST_AGENT_SOCKET = '/var/run/robotis/agent_sockets/host/host_agent.sock'
|
|
37
38
|
HOST_AGENT_SOCKET_DIR = '/var/run/robotis/agent_sockets/host'
|
|
38
39
|
|
|
39
|
-
# `cyclo_manager up` starts these immediately.
|
|
40
|
+
# `cyclo_manager up` starts these Containers immediately.
|
|
40
41
|
COMPOSE_SERVICES_UP = ('cyclo_manager', 'ui')
|
|
41
42
|
# These get `docker compose create` only (stopped); start from UI or `docker start`.
|
|
42
43
|
COMPOSE_SERVICES_CREATE_ONLY = ('rmw_zenoh', 'novnc-server')
|
|
44
|
+
DISABLED_LOGIN_SHELLS = {'', '/bin/false', '/sbin/nologin', '/usr/sbin/nologin'}
|
|
43
45
|
|
|
44
46
|
|
|
45
47
|
def _docker_dir() -> Path:
|
|
@@ -55,6 +57,47 @@ def _packaged_config_path() -> Path:
|
|
|
55
57
|
return _config_dir() / 'config.yml'
|
|
56
58
|
|
|
57
59
|
|
|
60
|
+
def _sudo_cmd(args: list[str]) -> list[str]:
|
|
61
|
+
"""Return args prefixed with sudo when the current process is not already root."""
|
|
62
|
+
if os.geteuid() == 0:
|
|
63
|
+
return args
|
|
64
|
+
return ['sudo', *args]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _user_home(user: str) -> Path:
|
|
68
|
+
"""Return a user's home directory from passwd, with a conservative fallback."""
|
|
69
|
+
try:
|
|
70
|
+
return Path(pwd.getpwnam(user).pw_dir)
|
|
71
|
+
except KeyError:
|
|
72
|
+
if user == 'root':
|
|
73
|
+
return Path('/root')
|
|
74
|
+
return Path(f'/home/{user}')
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _has_normal_login_user() -> bool:
|
|
78
|
+
"""Return True when the host has a non-root login user."""
|
|
79
|
+
for account in pwd.getpwall():
|
|
80
|
+
if account.pw_name == 'root':
|
|
81
|
+
continue
|
|
82
|
+
if account.pw_uid < 1000 or account.pw_uid >= 65534:
|
|
83
|
+
continue
|
|
84
|
+
if account.pw_shell in DISABLED_LOGIN_SHELLS:
|
|
85
|
+
continue
|
|
86
|
+
return True
|
|
87
|
+
return False
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _host_agent_workspace(user: str, user_home: Path) -> Path:
|
|
91
|
+
"""Return the workspace path the host agent should scan for git repositories."""
|
|
92
|
+
configured_workspace = os.environ.get('CYCLO_HOST_AGENT_WORKSPACE')
|
|
93
|
+
if configured_workspace:
|
|
94
|
+
return Path(configured_workspace).expanduser()
|
|
95
|
+
data_docker = Path('/data/docker')
|
|
96
|
+
if user == 'root' and data_docker.is_dir():
|
|
97
|
+
return data_docker
|
|
98
|
+
return user_home
|
|
99
|
+
|
|
100
|
+
|
|
58
101
|
def _resolve_service_user() -> tuple[str, Path] | None:
|
|
59
102
|
"""
|
|
60
103
|
Return (username, home) for the host agent systemd service.
|
|
@@ -64,9 +107,15 @@ def _resolve_service_user() -> tuple[str, Path] | None:
|
|
|
64
107
|
"""
|
|
65
108
|
sudo_user = os.environ.get('SUDO_USER')
|
|
66
109
|
if sudo_user:
|
|
67
|
-
return sudo_user,
|
|
68
|
-
user = os.environ.get('USER') or os.
|
|
110
|
+
return sudo_user, _user_home(sudo_user)
|
|
111
|
+
user = os.environ.get('USER') or pwd.getpwuid(os.getuid()).pw_name
|
|
69
112
|
if user == 'root':
|
|
113
|
+
if not _has_normal_login_user():
|
|
114
|
+
print(
|
|
115
|
+
'Info: root-only device detected; cyclo_host_agent will run as root.',
|
|
116
|
+
file=sys.stderr,
|
|
117
|
+
)
|
|
118
|
+
return 'root', Path('/root')
|
|
70
119
|
print(
|
|
71
120
|
'Error: cyclo_manager up must run as a normal user (e.g. robotis), not root.',
|
|
72
121
|
file=sys.stderr,
|
|
@@ -85,19 +134,19 @@ def _setup_socket_dir(user: str) -> bool:
|
|
|
85
134
|
print(f' [1/3] Creating socket directory {HOST_AGENT_SOCKET_DIR}...')
|
|
86
135
|
try:
|
|
87
136
|
subprocess.run(
|
|
88
|
-
['
|
|
137
|
+
_sudo_cmd(['mkdir', '-p', HOST_AGENT_SOCKET_DIR]),
|
|
89
138
|
check=True,
|
|
90
139
|
capture_output=True,
|
|
91
140
|
)
|
|
92
141
|
print(f' [2/3] Setting ownership to {user}:{user}...')
|
|
93
142
|
subprocess.run(
|
|
94
|
-
['
|
|
143
|
+
_sudo_cmd(['chown', f'{user}:{user}', HOST_AGENT_SOCKET_DIR]),
|
|
95
144
|
check=True,
|
|
96
145
|
capture_output=True,
|
|
97
146
|
)
|
|
98
147
|
print(' [3/3] Removing stale socket file (if any)...')
|
|
99
148
|
subprocess.run(
|
|
100
|
-
['
|
|
149
|
+
_sudo_cmd(['rm', '-f', HOST_AGENT_SOCKET]),
|
|
101
150
|
check=True,
|
|
102
151
|
capture_output=True,
|
|
103
152
|
)
|
|
@@ -123,13 +172,13 @@ def _install_sudoers(user: str) -> bool:
|
|
|
123
172
|
sudoers_file = '/etc/sudoers.d/cyclo_manager'
|
|
124
173
|
try:
|
|
125
174
|
subprocess.run(
|
|
126
|
-
['
|
|
175
|
+
_sudo_cmd(['tee', sudoers_file]),
|
|
127
176
|
input=sudoers_content.encode(),
|
|
128
177
|
capture_output=True,
|
|
129
178
|
check=True,
|
|
130
179
|
)
|
|
131
180
|
subprocess.run(
|
|
132
|
-
['
|
|
181
|
+
_sudo_cmd(['chmod', '440', sudoers_file]),
|
|
133
182
|
check=True,
|
|
134
183
|
capture_output=True,
|
|
135
184
|
)
|
|
@@ -151,6 +200,7 @@ def _ensure_host_agent() -> int:
|
|
|
151
200
|
return 1
|
|
152
201
|
|
|
153
202
|
user, user_home = account
|
|
203
|
+
workspace_path = _host_agent_workspace(user, user_home)
|
|
154
204
|
agent_exe = shutil.which('cyclo_host_agent')
|
|
155
205
|
if not agent_exe:
|
|
156
206
|
print(
|
|
@@ -163,7 +213,7 @@ def _ensure_host_agent() -> int:
|
|
|
163
213
|
if not _setup_socket_dir(user):
|
|
164
214
|
return 1
|
|
165
215
|
|
|
166
|
-
if not _install_sudoers(user):
|
|
216
|
+
if user != 'root' and not _install_sudoers(user):
|
|
167
217
|
return 1
|
|
168
218
|
|
|
169
219
|
service_content = f"""\
|
|
@@ -179,6 +229,7 @@ RuntimeDirectory=robotis/agent_sockets/host
|
|
|
179
229
|
RuntimeDirectoryMode=0755
|
|
180
230
|
ExecStart={agent_exe}
|
|
181
231
|
Environment=HOME={user_home}
|
|
232
|
+
Environment=CYCLO_HOST_AGENT_WORKSPACE={workspace_path}
|
|
182
233
|
Restart=always
|
|
183
234
|
RestartSec=3
|
|
184
235
|
|
|
@@ -192,22 +243,26 @@ WantedBy=multi-user.target
|
|
|
192
243
|
try:
|
|
193
244
|
print(f' Writing unit file to {service_file}...')
|
|
194
245
|
subprocess.run(
|
|
195
|
-
['
|
|
246
|
+
_sudo_cmd(['tee', service_file]),
|
|
196
247
|
input=service_content.encode(),
|
|
197
248
|
capture_output=True,
|
|
198
249
|
check=True,
|
|
199
250
|
)
|
|
200
251
|
print(' Running systemctl daemon-reload...')
|
|
201
|
-
subprocess.run(
|
|
252
|
+
subprocess.run(
|
|
253
|
+
_sudo_cmd(['systemctl', 'daemon-reload']),
|
|
254
|
+
check=True,
|
|
255
|
+
capture_output=True,
|
|
256
|
+
)
|
|
202
257
|
print(f' Enabling {HOST_AGENT_SERVICE}...')
|
|
203
258
|
subprocess.run(
|
|
204
|
-
['
|
|
259
|
+
_sudo_cmd(['systemctl', 'enable', f'{HOST_AGENT_SERVICE}.service']),
|
|
205
260
|
check=True,
|
|
206
261
|
capture_output=True,
|
|
207
262
|
)
|
|
208
263
|
print(f' Starting {HOST_AGENT_SERVICE}...')
|
|
209
264
|
subprocess.run(
|
|
210
|
-
['
|
|
265
|
+
_sudo_cmd(['systemctl', 'restart', f'{HOST_AGENT_SERVICE}.service']),
|
|
211
266
|
check=True,
|
|
212
267
|
capture_output=True,
|
|
213
268
|
)
|
|
@@ -217,7 +272,7 @@ WantedBy=multi-user.target
|
|
|
217
272
|
print(f'Failed to install host agent service: {e}', file=sys.stderr)
|
|
218
273
|
return 1
|
|
219
274
|
except FileNotFoundError:
|
|
220
|
-
print('
|
|
275
|
+
print('Required command not found. Install the host agent service manually.', file=sys.stderr)
|
|
221
276
|
return 1
|
|
222
277
|
|
|
223
278
|
|
|
@@ -272,15 +327,21 @@ def _teardown_host_agent() -> None:
|
|
|
272
327
|
"""Stop and remove the host agent service, unit file, sudoers, and socket dir."""
|
|
273
328
|
print(f'Tearing down {HOST_AGENT_SERVICE}...')
|
|
274
329
|
steps = [
|
|
275
|
-
(['sudo', 'systemctl', 'stop', f'{HOST_AGENT_SERVICE}.service'], 'stop service'),
|
|
276
|
-
(['sudo', 'systemctl', 'disable', f'{HOST_AGENT_SERVICE}.service'], 'disable service'),
|
|
277
330
|
(
|
|
278
|
-
['
|
|
331
|
+
_sudo_cmd(['systemctl', 'stop', f'{HOST_AGENT_SERVICE}.service']),
|
|
332
|
+
'stop service',
|
|
333
|
+
),
|
|
334
|
+
(
|
|
335
|
+
_sudo_cmd(['systemctl', 'disable', f'{HOST_AGENT_SERVICE}.service']),
|
|
336
|
+
'disable service',
|
|
337
|
+
),
|
|
338
|
+
(
|
|
339
|
+
_sudo_cmd(['rm', '-f', f'/etc/systemd/system/{HOST_AGENT_SERVICE}.service']),
|
|
279
340
|
'remove unit file',
|
|
280
341
|
),
|
|
281
|
-
(['
|
|
282
|
-
(['
|
|
283
|
-
(['
|
|
342
|
+
(_sudo_cmd(['systemctl', 'daemon-reload']), 'daemon-reload'),
|
|
343
|
+
(_sudo_cmd(['rm', '-f', '/etc/sudoers.d/cyclo_manager']), 'remove sudoers'),
|
|
344
|
+
(_sudo_cmd(['rm', '-rf', HOST_AGENT_SOCKET_DIR]), 'remove socket dir'),
|
|
284
345
|
]
|
|
285
346
|
for cmd, desc in steps:
|
|
286
347
|
print(f' {desc}...')
|
{cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/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.
|
|
14
|
+
image: robotis/cyclo-manager:1.0.0
|
|
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.
|
|
30
|
+
image: robotis/cyclo-manager-ui:1.0.0
|
|
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 = "1.0.0.
|
|
7
|
+
version = "1.0.0.dev2"
|
|
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.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
{cyclo_manager-1.0.0.dev0 → cyclo_manager-1.0.0.dev2}/cyclo_manager.egg-info/entry_points.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|