cyclo-manager 0.1.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-0.1.0.dev2/PKG-INFO +107 -0
- cyclo_manager-0.1.0.dev2/README.md +96 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager.egg-info/PKG-INFO +107 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager.egg-info/SOURCES.txt +13 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager.egg-info/dependency_links.txt +1 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager.egg-info/entry_points.txt +2 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager.egg-info/requires.txt +4 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager.egg-info/top_level.txt +1 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager_cli/__init__.py +3 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager_cli/cli.py +211 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager_cli/config/config.yml +10 -0
- cyclo_manager-0.1.0.dev2/cyclo_manager_cli/docker/docker-compose.yml +56 -0
- cyclo_manager-0.1.0.dev2/pyproject.toml +28 -0
- cyclo_manager-0.1.0.dev2/setup.cfg +9 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cyclo-manager
|
|
3
|
+
Version: 0.1.0.dev2
|
|
4
|
+
Summary: cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: pytest; extra == "dev"
|
|
10
|
+
Requires-Dist: ruff; extra == "dev"
|
|
11
|
+
|
|
12
|
+
# cyclo_manager CLI
|
|
13
|
+
|
|
14
|
+
`cyclo-manager` is a small **pip-installable CLI** that brings up the cyclo_manager stack using **Docker Compose v2**. It runs the packaged [`docker-compose.yml`](cyclo_manager_cli/docker/docker-compose.yml): starts the API and web UI, **creates** (but does not start) optional Zenoh and noVNC containers, and can **self-update** via PyPI.
|
|
15
|
+
|
|
16
|
+
The console script name is **`cyclo_manager`** (underscore).
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- **Docker** with **Compose v2** (`docker compose`, not only legacy `docker-compose`)
|
|
21
|
+
- **Python 3.10+**
|
|
22
|
+
- For **`cyclo_manager update`**: **`pip`** / **`pip3`** on `PATH`
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
Build and install a wheel (package name on PyPI / `pyproject.toml` is **`cyclo-manager`**):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
python -m build --wheel
|
|
30
|
+
pip install dist/cyclo_manager-*.whl
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If `cyclo_manager` is not found, add the user scripts directory to `PATH`:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
After install, use the CLI by name:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
cyclo_manager --help
|
|
43
|
+
cyclo_manager up
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
(If the script is still missing from `PATH`, you can run the same subcommands via `python3 -m cyclo_manager_cli.cli`, e.g. `python3 -m cyclo_manager_cli.cli up`.)
|
|
47
|
+
|
|
48
|
+
## Commands
|
|
49
|
+
|
|
50
|
+
| Command | What it does |
|
|
51
|
+
|--------|----------------|
|
|
52
|
+
| `cyclo_manager up` | `docker compose up -d` for **`cyclo_manager`** and **`ui`**; then `docker compose create --no-recreate` for **`rmw_zenoh`** and **`novnc-server`** so those containers exist but stay **stopped** |
|
|
53
|
+
| `cyclo_manager up -c /path/to/config.yml` | Same as `up`, but mounts this file into the API container as config. If the path does not exist, the CLI **copies** the bundled default config there first |
|
|
54
|
+
| `cyclo_manager up -r 35` | Sets **`ROS_DOMAIN_ID`** for the stack (default: **30**) |
|
|
55
|
+
| `cyclo_manager up --pull` | Runs `docker compose pull` before up/create |
|
|
56
|
+
| `cyclo_manager down` | `docker compose down` for the **packaged** compose file (stops/removes containers for that project) |
|
|
57
|
+
| `cyclo_manager update` | Runs `cyclo_manager down`, then `pip install -U cyclo-manager`, then `cyclo_manager up` again (optional `-c`, `-r`, `--pull` are forwarded to `up`) |
|
|
58
|
+
| `cyclo_manager --help` | Top-level help |
|
|
59
|
+
|
|
60
|
+
Implementation reference: [`cyclo_manager_cli/cli.py`](cyclo_manager_cli/cli.py).
|
|
61
|
+
|
|
62
|
+
### Compose services vs container names
|
|
63
|
+
|
|
64
|
+
| Compose service | Typical container name | `up` behavior |
|
|
65
|
+
|-----------------|------------------------|---------------|
|
|
66
|
+
| `cyclo_manager` | `cyclo_manager` | Started |
|
|
67
|
+
| `ui` | `cyclo_manager_ui` | Started |
|
|
68
|
+
| `rmw_zenoh` | `zenoh_daemon` | **Created only** (start from Control UI or `docker start zenoh_daemon`) |
|
|
69
|
+
| `novnc-server` | `novnc-server` | **Created only** (start when needed, e.g. `docker start novnc-server`) |
|
|
70
|
+
|
|
71
|
+
### Environment passed into Compose
|
|
72
|
+
|
|
73
|
+
- **`CYCLO_MANAGER_CONFIG_FILE`**: absolute path to the YAML config used on the host (default: bundled [`config/config.yml`](cyclo_manager_cli/config/config.yml))
|
|
74
|
+
- **`ROS_DOMAIN_ID`**: from `-r` / `--ros-domain-id` (default **30**)
|
|
75
|
+
|
|
76
|
+
`cyclo_manager down` always sets `CYCLO_MANAGER_CONFIG_FILE` to the **bundled** config path when invoking Compose (see `cmd_down` in `cli.py`).
|
|
77
|
+
|
|
78
|
+
## Bundled config
|
|
79
|
+
|
|
80
|
+
Default file: [`cyclo_manager_cli/config/config.yml`](cyclo_manager_cli/config/config.yml).
|
|
81
|
+
|
|
82
|
+
It lists **managed containers** and **agent Unix socket paths** (host paths mounted under `/agents` in the API container), for example:
|
|
83
|
+
|
|
84
|
+
- `ai_worker` → `/agents/ai_worker/s6_agent.sock`
|
|
85
|
+
- `physical_ai_server` → `/agents/physical_ai_server/s6_agent.sock`
|
|
86
|
+
|
|
87
|
+
Service names inside each container come from the agent, not from this file.
|
|
88
|
+
|
|
89
|
+
## URLs (packaged compose, `network_mode: host`)
|
|
90
|
+
|
|
91
|
+
After `cyclo_manager up`:
|
|
92
|
+
|
|
93
|
+
| Service | URL |
|
|
94
|
+
|---------|-----|
|
|
95
|
+
| cyclo_manager API | http://127.0.0.1:8081 |
|
|
96
|
+
| OpenAPI docs | http://127.0.0.1:8081/docs |
|
|
97
|
+
| Web UI | http://127.0.0.1:3000 |
|
|
98
|
+
|
|
99
|
+
Images and tags are defined in [`docker/docker-compose.yml`](cyclo_manager_cli/docker/docker-compose.yml) (e.g. `robotis/cyclo-manager`, `robotis/cyclo-manager-ui`).
|
|
100
|
+
|
|
101
|
+
## Development from the repository root
|
|
102
|
+
|
|
103
|
+
To run against **local** images and mounts (not the pip-bundled compose), use the root compose and config — see the main [project README](../README.md) and `docker-compose.dev.yml`.
|
|
104
|
+
|
|
105
|
+
## Dependencies
|
|
106
|
+
|
|
107
|
+
The CLI package itself declares **no** Python dependencies (`pyproject.toml`); it shells out to **`docker compose`** and optionally **`pip`**.
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# cyclo_manager CLI
|
|
2
|
+
|
|
3
|
+
`cyclo-manager` is a small **pip-installable CLI** that brings up the cyclo_manager stack using **Docker Compose v2**. It runs the packaged [`docker-compose.yml`](cyclo_manager_cli/docker/docker-compose.yml): starts the API and web UI, **creates** (but does not start) optional Zenoh and noVNC containers, and can **self-update** via PyPI.
|
|
4
|
+
|
|
5
|
+
The console script name is **`cyclo_manager`** (underscore).
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- **Docker** with **Compose v2** (`docker compose`, not only legacy `docker-compose`)
|
|
10
|
+
- **Python 3.10+**
|
|
11
|
+
- For **`cyclo_manager update`**: **`pip`** / **`pip3`** on `PATH`
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
Build and install a wheel (package name on PyPI / `pyproject.toml` is **`cyclo-manager`**):
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
python -m build --wheel
|
|
19
|
+
pip install dist/cyclo_manager-*.whl
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If `cyclo_manager` is not found, add the user scripts directory to `PATH`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
After install, use the CLI by name:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
cyclo_manager --help
|
|
32
|
+
cyclo_manager up
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
(If the script is still missing from `PATH`, you can run the same subcommands via `python3 -m cyclo_manager_cli.cli`, e.g. `python3 -m cyclo_manager_cli.cli up`.)
|
|
36
|
+
|
|
37
|
+
## Commands
|
|
38
|
+
|
|
39
|
+
| Command | What it does |
|
|
40
|
+
|--------|----------------|
|
|
41
|
+
| `cyclo_manager up` | `docker compose up -d` for **`cyclo_manager`** and **`ui`**; then `docker compose create --no-recreate` for **`rmw_zenoh`** and **`novnc-server`** so those containers exist but stay **stopped** |
|
|
42
|
+
| `cyclo_manager up -c /path/to/config.yml` | Same as `up`, but mounts this file into the API container as config. If the path does not exist, the CLI **copies** the bundled default config there first |
|
|
43
|
+
| `cyclo_manager up -r 35` | Sets **`ROS_DOMAIN_ID`** for the stack (default: **30**) |
|
|
44
|
+
| `cyclo_manager up --pull` | Runs `docker compose pull` before up/create |
|
|
45
|
+
| `cyclo_manager down` | `docker compose down` for the **packaged** compose file (stops/removes containers for that project) |
|
|
46
|
+
| `cyclo_manager update` | Runs `cyclo_manager down`, then `pip install -U cyclo-manager`, then `cyclo_manager up` again (optional `-c`, `-r`, `--pull` are forwarded to `up`) |
|
|
47
|
+
| `cyclo_manager --help` | Top-level help |
|
|
48
|
+
|
|
49
|
+
Implementation reference: [`cyclo_manager_cli/cli.py`](cyclo_manager_cli/cli.py).
|
|
50
|
+
|
|
51
|
+
### Compose services vs container names
|
|
52
|
+
|
|
53
|
+
| Compose service | Typical container name | `up` behavior |
|
|
54
|
+
|-----------------|------------------------|---------------|
|
|
55
|
+
| `cyclo_manager` | `cyclo_manager` | Started |
|
|
56
|
+
| `ui` | `cyclo_manager_ui` | Started |
|
|
57
|
+
| `rmw_zenoh` | `zenoh_daemon` | **Created only** (start from Control UI or `docker start zenoh_daemon`) |
|
|
58
|
+
| `novnc-server` | `novnc-server` | **Created only** (start when needed, e.g. `docker start novnc-server`) |
|
|
59
|
+
|
|
60
|
+
### Environment passed into Compose
|
|
61
|
+
|
|
62
|
+
- **`CYCLO_MANAGER_CONFIG_FILE`**: absolute path to the YAML config used on the host (default: bundled [`config/config.yml`](cyclo_manager_cli/config/config.yml))
|
|
63
|
+
- **`ROS_DOMAIN_ID`**: from `-r` / `--ros-domain-id` (default **30**)
|
|
64
|
+
|
|
65
|
+
`cyclo_manager down` always sets `CYCLO_MANAGER_CONFIG_FILE` to the **bundled** config path when invoking Compose (see `cmd_down` in `cli.py`).
|
|
66
|
+
|
|
67
|
+
## Bundled config
|
|
68
|
+
|
|
69
|
+
Default file: [`cyclo_manager_cli/config/config.yml`](cyclo_manager_cli/config/config.yml).
|
|
70
|
+
|
|
71
|
+
It lists **managed containers** and **agent Unix socket paths** (host paths mounted under `/agents` in the API container), for example:
|
|
72
|
+
|
|
73
|
+
- `ai_worker` → `/agents/ai_worker/s6_agent.sock`
|
|
74
|
+
- `physical_ai_server` → `/agents/physical_ai_server/s6_agent.sock`
|
|
75
|
+
|
|
76
|
+
Service names inside each container come from the agent, not from this file.
|
|
77
|
+
|
|
78
|
+
## URLs (packaged compose, `network_mode: host`)
|
|
79
|
+
|
|
80
|
+
After `cyclo_manager up`:
|
|
81
|
+
|
|
82
|
+
| Service | URL |
|
|
83
|
+
|---------|-----|
|
|
84
|
+
| cyclo_manager API | http://127.0.0.1:8081 |
|
|
85
|
+
| OpenAPI docs | http://127.0.0.1:8081/docs |
|
|
86
|
+
| Web UI | http://127.0.0.1:3000 |
|
|
87
|
+
|
|
88
|
+
Images and tags are defined in [`docker/docker-compose.yml`](cyclo_manager_cli/docker/docker-compose.yml) (e.g. `robotis/cyclo-manager`, `robotis/cyclo-manager-ui`).
|
|
89
|
+
|
|
90
|
+
## Development from the repository root
|
|
91
|
+
|
|
92
|
+
To run against **local** images and mounts (not the pip-bundled compose), use the root compose and config — see the main [project README](../README.md) and `docker-compose.dev.yml`.
|
|
93
|
+
|
|
94
|
+
## Dependencies
|
|
95
|
+
|
|
96
|
+
The CLI package itself declares **no** Python dependencies (`pyproject.toml`); it shells out to **`docker compose`** and optionally **`pip`**.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cyclo-manager
|
|
3
|
+
Version: 0.1.0.dev2
|
|
4
|
+
Summary: cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack.
|
|
5
|
+
License-Expression: Apache-2.0
|
|
6
|
+
Requires-Python: >=3.10
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: pytest; extra == "dev"
|
|
10
|
+
Requires-Dist: ruff; extra == "dev"
|
|
11
|
+
|
|
12
|
+
# cyclo_manager CLI
|
|
13
|
+
|
|
14
|
+
`cyclo-manager` is a small **pip-installable CLI** that brings up the cyclo_manager stack using **Docker Compose v2**. It runs the packaged [`docker-compose.yml`](cyclo_manager_cli/docker/docker-compose.yml): starts the API and web UI, **creates** (but does not start) optional Zenoh and noVNC containers, and can **self-update** via PyPI.
|
|
15
|
+
|
|
16
|
+
The console script name is **`cyclo_manager`** (underscore).
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- **Docker** with **Compose v2** (`docker compose`, not only legacy `docker-compose`)
|
|
21
|
+
- **Python 3.10+**
|
|
22
|
+
- For **`cyclo_manager update`**: **`pip`** / **`pip3`** on `PATH`
|
|
23
|
+
|
|
24
|
+
## Installation
|
|
25
|
+
|
|
26
|
+
Build and install a wheel (package name on PyPI / `pyproject.toml` is **`cyclo-manager`**):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
python -m build --wheel
|
|
30
|
+
pip install dist/cyclo_manager-*.whl
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
If `cyclo_manager` is not found, add the user scripts directory to `PATH`:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
After install, use the CLI by name:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
cyclo_manager --help
|
|
43
|
+
cyclo_manager up
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
(If the script is still missing from `PATH`, you can run the same subcommands via `python3 -m cyclo_manager_cli.cli`, e.g. `python3 -m cyclo_manager_cli.cli up`.)
|
|
47
|
+
|
|
48
|
+
## Commands
|
|
49
|
+
|
|
50
|
+
| Command | What it does |
|
|
51
|
+
|--------|----------------|
|
|
52
|
+
| `cyclo_manager up` | `docker compose up -d` for **`cyclo_manager`** and **`ui`**; then `docker compose create --no-recreate` for **`rmw_zenoh`** and **`novnc-server`** so those containers exist but stay **stopped** |
|
|
53
|
+
| `cyclo_manager up -c /path/to/config.yml` | Same as `up`, but mounts this file into the API container as config. If the path does not exist, the CLI **copies** the bundled default config there first |
|
|
54
|
+
| `cyclo_manager up -r 35` | Sets **`ROS_DOMAIN_ID`** for the stack (default: **30**) |
|
|
55
|
+
| `cyclo_manager up --pull` | Runs `docker compose pull` before up/create |
|
|
56
|
+
| `cyclo_manager down` | `docker compose down` for the **packaged** compose file (stops/removes containers for that project) |
|
|
57
|
+
| `cyclo_manager update` | Runs `cyclo_manager down`, then `pip install -U cyclo-manager`, then `cyclo_manager up` again (optional `-c`, `-r`, `--pull` are forwarded to `up`) |
|
|
58
|
+
| `cyclo_manager --help` | Top-level help |
|
|
59
|
+
|
|
60
|
+
Implementation reference: [`cyclo_manager_cli/cli.py`](cyclo_manager_cli/cli.py).
|
|
61
|
+
|
|
62
|
+
### Compose services vs container names
|
|
63
|
+
|
|
64
|
+
| Compose service | Typical container name | `up` behavior |
|
|
65
|
+
|-----------------|------------------------|---------------|
|
|
66
|
+
| `cyclo_manager` | `cyclo_manager` | Started |
|
|
67
|
+
| `ui` | `cyclo_manager_ui` | Started |
|
|
68
|
+
| `rmw_zenoh` | `zenoh_daemon` | **Created only** (start from Control UI or `docker start zenoh_daemon`) |
|
|
69
|
+
| `novnc-server` | `novnc-server` | **Created only** (start when needed, e.g. `docker start novnc-server`) |
|
|
70
|
+
|
|
71
|
+
### Environment passed into Compose
|
|
72
|
+
|
|
73
|
+
- **`CYCLO_MANAGER_CONFIG_FILE`**: absolute path to the YAML config used on the host (default: bundled [`config/config.yml`](cyclo_manager_cli/config/config.yml))
|
|
74
|
+
- **`ROS_DOMAIN_ID`**: from `-r` / `--ros-domain-id` (default **30**)
|
|
75
|
+
|
|
76
|
+
`cyclo_manager down` always sets `CYCLO_MANAGER_CONFIG_FILE` to the **bundled** config path when invoking Compose (see `cmd_down` in `cli.py`).
|
|
77
|
+
|
|
78
|
+
## Bundled config
|
|
79
|
+
|
|
80
|
+
Default file: [`cyclo_manager_cli/config/config.yml`](cyclo_manager_cli/config/config.yml).
|
|
81
|
+
|
|
82
|
+
It lists **managed containers** and **agent Unix socket paths** (host paths mounted under `/agents` in the API container), for example:
|
|
83
|
+
|
|
84
|
+
- `ai_worker` → `/agents/ai_worker/s6_agent.sock`
|
|
85
|
+
- `physical_ai_server` → `/agents/physical_ai_server/s6_agent.sock`
|
|
86
|
+
|
|
87
|
+
Service names inside each container come from the agent, not from this file.
|
|
88
|
+
|
|
89
|
+
## URLs (packaged compose, `network_mode: host`)
|
|
90
|
+
|
|
91
|
+
After `cyclo_manager up`:
|
|
92
|
+
|
|
93
|
+
| Service | URL |
|
|
94
|
+
|---------|-----|
|
|
95
|
+
| cyclo_manager API | http://127.0.0.1:8081 |
|
|
96
|
+
| OpenAPI docs | http://127.0.0.1:8081/docs |
|
|
97
|
+
| Web UI | http://127.0.0.1:3000 |
|
|
98
|
+
|
|
99
|
+
Images and tags are defined in [`docker/docker-compose.yml`](cyclo_manager_cli/docker/docker-compose.yml) (e.g. `robotis/cyclo-manager`, `robotis/cyclo-manager-ui`).
|
|
100
|
+
|
|
101
|
+
## Development from the repository root
|
|
102
|
+
|
|
103
|
+
To run against **local** images and mounts (not the pip-bundled compose), use the root compose and config — see the main [project README](../README.md) and `docker-compose.dev.yml`.
|
|
104
|
+
|
|
105
|
+
## Dependencies
|
|
106
|
+
|
|
107
|
+
The CLI package itself declares **no** Python dependencies (`pyproject.toml`); it shells out to **`docker compose`** and optionally **`pip`**.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.cfg
|
|
4
|
+
cyclo_manager.egg-info/PKG-INFO
|
|
5
|
+
cyclo_manager.egg-info/SOURCES.txt
|
|
6
|
+
cyclo_manager.egg-info/dependency_links.txt
|
|
7
|
+
cyclo_manager.egg-info/entry_points.txt
|
|
8
|
+
cyclo_manager.egg-info/requires.txt
|
|
9
|
+
cyclo_manager.egg-info/top_level.txt
|
|
10
|
+
cyclo_manager_cli/__init__.py
|
|
11
|
+
cyclo_manager_cli/cli.py
|
|
12
|
+
cyclo_manager_cli/config/config.yml
|
|
13
|
+
cyclo_manager_cli/docker/docker-compose.yml
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cyclo_manager_cli
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"""CLI for pip-installed cyclo_manager_cli: cyclo_manager up, cyclo_manager down, cyclo_manager update. Launches cyclo_manager server and UI via Docker."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import os
|
|
5
|
+
import shutil
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
PYPI_PACKAGE = "cyclo-manager"
|
|
11
|
+
|
|
12
|
+
# `cyclo_manager up` starts these immediately.
|
|
13
|
+
COMPOSE_SERVICES_UP = ("cyclo_manager", "ui")
|
|
14
|
+
# These get `docker compose create` only (stopped); start from UI or `docker start` when needed.
|
|
15
|
+
COMPOSE_SERVICES_CREATE_ONLY = ("rmw_zenoh", "novnc-server")
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _docker_dir() -> Path:
|
|
19
|
+
return Path(__file__).resolve().parent / "docker"
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def _config_dir() -> Path:
|
|
23
|
+
return Path(__file__).resolve().parent / "config"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _packaged_config_path() -> Path:
|
|
27
|
+
"""Path to the bundled config (config/config.yml). Used by default for cyclo_manager up."""
|
|
28
|
+
return _config_dir() / "config.yml"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def cmd_up(args: argparse.Namespace) -> int:
|
|
32
|
+
"""Run docker compose: start API + UI; create zenoh + noVNC containers without starting them."""
|
|
33
|
+
if args.config is None:
|
|
34
|
+
config_path = _packaged_config_path()
|
|
35
|
+
else:
|
|
36
|
+
config_path = Path(args.config).expanduser().resolve()
|
|
37
|
+
if not config_path.exists():
|
|
38
|
+
config_path.parent.mkdir(parents=True, exist_ok=True)
|
|
39
|
+
shutil.copy2(_packaged_config_path(), config_path)
|
|
40
|
+
print(f"Created default config at {config_path}", file=sys.stderr)
|
|
41
|
+
if not config_path.is_file():
|
|
42
|
+
print(f"Config file not found: {config_path}", file=sys.stderr)
|
|
43
|
+
return 1
|
|
44
|
+
compose_path = _docker_dir() / "docker-compose.yml"
|
|
45
|
+
if not compose_path.is_file():
|
|
46
|
+
print(f"Compose file not found: {compose_path}", file=sys.stderr)
|
|
47
|
+
return 1
|
|
48
|
+
env = os.environ.copy()
|
|
49
|
+
env["CYCLO_MANAGER_CONFIG_FILE"] = str(config_path)
|
|
50
|
+
env["ROS_DOMAIN_ID"] = str(args.ros_domain_id)
|
|
51
|
+
base = ["docker", "compose", "-f", str(compose_path)]
|
|
52
|
+
try:
|
|
53
|
+
if args.pull:
|
|
54
|
+
subprocess.run([*base, "pull"], env=env, check=True)
|
|
55
|
+
subprocess.run([*base, "up", "-d", *COMPOSE_SERVICES_UP], env=env, check=True)
|
|
56
|
+
subprocess.run(
|
|
57
|
+
[*base, "create", "--no-recreate", *COMPOSE_SERVICES_CREATE_ONLY],
|
|
58
|
+
env=env,
|
|
59
|
+
check=True,
|
|
60
|
+
)
|
|
61
|
+
except subprocess.CalledProcessError as e:
|
|
62
|
+
return e.returncode
|
|
63
|
+
except FileNotFoundError:
|
|
64
|
+
print(
|
|
65
|
+
"Docker not found. Install Docker and ensure 'docker compose' is available.",
|
|
66
|
+
file=sys.stderr,
|
|
67
|
+
)
|
|
68
|
+
return 1
|
|
69
|
+
print("cyclo_manager stack is up (API + UI running; zenoh_daemon + novnc-server created, not started).")
|
|
70
|
+
return 0
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def cmd_down(args: argparse.Namespace) -> int:
|
|
74
|
+
"""Stop cyclo_manager server, cyclo_manager_ui, and zenoh daemon (docker compose down)."""
|
|
75
|
+
compose_path = _docker_dir() / "docker-compose.yml"
|
|
76
|
+
if not compose_path.is_file():
|
|
77
|
+
print(f"Compose file not found: {compose_path}", file=sys.stderr)
|
|
78
|
+
return 1
|
|
79
|
+
env = os.environ.copy()
|
|
80
|
+
env["CYCLO_MANAGER_CONFIG_FILE"] = str(_packaged_config_path())
|
|
81
|
+
cmd = [
|
|
82
|
+
"docker",
|
|
83
|
+
"compose",
|
|
84
|
+
"-f",
|
|
85
|
+
str(compose_path),
|
|
86
|
+
"down",
|
|
87
|
+
]
|
|
88
|
+
try:
|
|
89
|
+
subprocess.run(cmd, env=env, check=True)
|
|
90
|
+
except subprocess.CalledProcessError as e:
|
|
91
|
+
return e.returncode
|
|
92
|
+
except FileNotFoundError:
|
|
93
|
+
print(
|
|
94
|
+
"Docker not found. Install Docker and ensure 'docker compose' is available.",
|
|
95
|
+
file=sys.stderr,
|
|
96
|
+
)
|
|
97
|
+
return 1
|
|
98
|
+
print("cyclo_manager server, cyclo_manager_ui, and zenoh daemon are down.")
|
|
99
|
+
return 0
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def cmd_update(args: argparse.Namespace) -> int:
|
|
103
|
+
"""Down containers, pip install -U cyclo-manager, then up again."""
|
|
104
|
+
cyclo_manager_exe = shutil.which("cyclo_manager")
|
|
105
|
+
if not cyclo_manager_exe:
|
|
106
|
+
print("cyclo_manager command not found in PATH.", file=sys.stderr)
|
|
107
|
+
return 1
|
|
108
|
+
pip_exe = shutil.which("pip3") or shutil.which("pip")
|
|
109
|
+
if not pip_exe:
|
|
110
|
+
print("pip not found; cannot update package.", file=sys.stderr)
|
|
111
|
+
return 1
|
|
112
|
+
|
|
113
|
+
print("Stopping containers (cyclo_manager down)...")
|
|
114
|
+
try:
|
|
115
|
+
subprocess.run([cyclo_manager_exe, "down"], check=True)
|
|
116
|
+
except subprocess.CalledProcessError as e:
|
|
117
|
+
return e.returncode
|
|
118
|
+
|
|
119
|
+
print(f"Updating {PYPI_PACKAGE} (pip install -U)...")
|
|
120
|
+
try:
|
|
121
|
+
subprocess.run(
|
|
122
|
+
[pip_exe, "install", "-U", PYPI_PACKAGE],
|
|
123
|
+
check=True,
|
|
124
|
+
timeout=120,
|
|
125
|
+
)
|
|
126
|
+
except subprocess.CalledProcessError as e:
|
|
127
|
+
print(f"pip install -U {PYPI_PACKAGE} failed.", file=sys.stderr)
|
|
128
|
+
return e.returncode
|
|
129
|
+
except subprocess.TimeoutExpired:
|
|
130
|
+
print("pip install timed out.", file=sys.stderr)
|
|
131
|
+
return 1
|
|
132
|
+
|
|
133
|
+
print("Starting containers (cyclo_manager up)...")
|
|
134
|
+
up_args = [cyclo_manager_exe, "up"]
|
|
135
|
+
if getattr(args, "config", None) is not None:
|
|
136
|
+
up_args.extend(["-c", str(args.config)])
|
|
137
|
+
if getattr(args, "pull", False):
|
|
138
|
+
up_args.append("--pull")
|
|
139
|
+
if getattr(args, "ros_domain_id", None) is not None:
|
|
140
|
+
up_args.extend(["-r", str(args.ros_domain_id)])
|
|
141
|
+
try:
|
|
142
|
+
subprocess.run(up_args, check=True)
|
|
143
|
+
except subprocess.CalledProcessError as e:
|
|
144
|
+
return e.returncode
|
|
145
|
+
|
|
146
|
+
print("cyclo_manager update completed.")
|
|
147
|
+
return 0
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def main() -> int:
|
|
151
|
+
parser = argparse.ArgumentParser(
|
|
152
|
+
prog="cyclo_manager",
|
|
153
|
+
description="cyclo_manager CLI: launch cyclo_manager server and UI containers. Services run via Docker images.",
|
|
154
|
+
)
|
|
155
|
+
sub = parser.add_subparsers(dest="command", help="Commands")
|
|
156
|
+
|
|
157
|
+
up_parser = sub.add_parser("up", help="Start cyclo_manager stack (docker compose)")
|
|
158
|
+
up_parser.add_argument(
|
|
159
|
+
"-c",
|
|
160
|
+
"--config",
|
|
161
|
+
metavar="PATH",
|
|
162
|
+
help="Config file path (default: use bundled config from package)",
|
|
163
|
+
)
|
|
164
|
+
up_parser.add_argument(
|
|
165
|
+
"-r",
|
|
166
|
+
"--ros-domain-id",
|
|
167
|
+
type=int,
|
|
168
|
+
default=30,
|
|
169
|
+
metavar="ID",
|
|
170
|
+
help="ROS2 domain ID for cyclo_manager server (default: 30)",
|
|
171
|
+
)
|
|
172
|
+
up_parser.add_argument(
|
|
173
|
+
"--pull",
|
|
174
|
+
action="store_true",
|
|
175
|
+
help="Pull all service images before create/up",
|
|
176
|
+
)
|
|
177
|
+
up_parser.set_defaults(func=cmd_up)
|
|
178
|
+
|
|
179
|
+
down_parser = sub.add_parser("down", help="Stop all stack containers (docker compose down)")
|
|
180
|
+
down_parser.set_defaults(func=cmd_down)
|
|
181
|
+
|
|
182
|
+
update_parser = sub.add_parser(
|
|
183
|
+
"update",
|
|
184
|
+
help="Down containers, pip install -U cyclo-manager, then up again",
|
|
185
|
+
)
|
|
186
|
+
update_parser.add_argument(
|
|
187
|
+
"-c",
|
|
188
|
+
"--config",
|
|
189
|
+
metavar="PATH",
|
|
190
|
+
help="Config file path for cyclo_manager up (default: use bundled config)",
|
|
191
|
+
)
|
|
192
|
+
update_parser.add_argument(
|
|
193
|
+
"-r",
|
|
194
|
+
"--ros-domain-id",
|
|
195
|
+
type=int,
|
|
196
|
+
default=30,
|
|
197
|
+
metavar="ID",
|
|
198
|
+
help="ROS2 domain ID for cyclo_manager up (default: 30)",
|
|
199
|
+
)
|
|
200
|
+
update_parser.add_argument(
|
|
201
|
+
"--pull",
|
|
202
|
+
action="store_true",
|
|
203
|
+
help="Always pull images when running cyclo_manager up",
|
|
204
|
+
)
|
|
205
|
+
update_parser.set_defaults(func=cmd_update)
|
|
206
|
+
|
|
207
|
+
args = parser.parse_args()
|
|
208
|
+
if not args.command:
|
|
209
|
+
parser.print_help()
|
|
210
|
+
return 0
|
|
211
|
+
return args.func(args)
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# cyclo_manager Configuration
|
|
2
|
+
# This file defines the containers that cyclo_manager can control.
|
|
3
|
+
#
|
|
4
|
+
# Services are discovered dynamically from each agent.
|
|
5
|
+
|
|
6
|
+
containers:
|
|
7
|
+
ai_worker:
|
|
8
|
+
socket_path: "/agents/ai_worker/s6_agent.sock"
|
|
9
|
+
physical_ai_server:
|
|
10
|
+
socket_path: "/agents/physical_ai_server/s6_agent.sock"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Packaged compose for pip-installed cyclo_manager_cli.
|
|
2
|
+
# Uses pre-built images; config path is set via CYCLO_MANAGER_CONFIG_FILE by the CLI.
|
|
3
|
+
# `cyclo_manager up` starts cyclo_manager + ui only; rmw_zenoh + novnc-server are created but left stopped.
|
|
4
|
+
services:
|
|
5
|
+
rmw_zenoh:
|
|
6
|
+
container_name: zenoh_daemon
|
|
7
|
+
image: robotis/zenoh-daemon:latest
|
|
8
|
+
restart: always
|
|
9
|
+
network_mode: host
|
|
10
|
+
init: true
|
|
11
|
+
|
|
12
|
+
cyclo_manager:
|
|
13
|
+
container_name: cyclo_manager
|
|
14
|
+
image: robotis/cyclo-manager:0.1.0
|
|
15
|
+
restart: always
|
|
16
|
+
network_mode: host
|
|
17
|
+
volumes:
|
|
18
|
+
- /dev:/dev
|
|
19
|
+
- /dev/shm:/dev/shm
|
|
20
|
+
- /var/run/robotis/agent_sockets:/agents # For agent socket access
|
|
21
|
+
- ${CYCLO_MANAGER_CONFIG_FILE}:/app/config.yml # For hot-reload on config changes
|
|
22
|
+
- /var/run/docker.sock:/var/run/docker.sock # For Docker API access
|
|
23
|
+
environment:
|
|
24
|
+
- CONFIG_FILE=/app/config.yml
|
|
25
|
+
- ROS_DOMAIN_ID=${ROS_DOMAIN_ID:-30}
|
|
26
|
+
|
|
27
|
+
ui:
|
|
28
|
+
container_name: cyclo_manager_ui
|
|
29
|
+
image: robotis/cyclo-manager-ui:0.1.0
|
|
30
|
+
restart: always
|
|
31
|
+
network_mode: host
|
|
32
|
+
environment:
|
|
33
|
+
- NEXT_PUBLIC_API_URL=http://127.0.0.1:8081
|
|
34
|
+
- NODE_ENV=production
|
|
35
|
+
|
|
36
|
+
novnc-server:
|
|
37
|
+
container_name: novnc-server
|
|
38
|
+
image: robotis/novnc-server:latest
|
|
39
|
+
restart: always
|
|
40
|
+
cap_add:
|
|
41
|
+
- SYS_NICE
|
|
42
|
+
ulimits:
|
|
43
|
+
rtprio: 99
|
|
44
|
+
rttime: -1
|
|
45
|
+
memlock: 8428281856
|
|
46
|
+
network_mode: host
|
|
47
|
+
environment:
|
|
48
|
+
- ROS_DOMAIN_ID=${ROS_DOMAIN_ID:-30}
|
|
49
|
+
- DISPLAY=:99
|
|
50
|
+
- DISPLAY_WIDTH=1920
|
|
51
|
+
- DISPLAY_HEIGHT=1080
|
|
52
|
+
- WEBSOCKIFY_PORT=8090
|
|
53
|
+
volumes:
|
|
54
|
+
- /dev:/dev
|
|
55
|
+
- /dev/shm:/dev/shm
|
|
56
|
+
privileged: true
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "cyclo-manager"
|
|
7
|
+
version = "0.1.0.dev2"
|
|
8
|
+
description = "cyclo_manager CLI: pip-installable launcher for cyclo_manager server and UI containers. Run 'cyclo_manager up' to start Docker stack."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "Apache-2.0"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
dependencies = []
|
|
13
|
+
|
|
14
|
+
[project.optional-dependencies]
|
|
15
|
+
dev = [
|
|
16
|
+
"pytest",
|
|
17
|
+
"ruff",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
[project.scripts]
|
|
21
|
+
cyclo_manager = "cyclo_manager_cli.cli:main"
|
|
22
|
+
|
|
23
|
+
[tool.setuptools.packages.find]
|
|
24
|
+
where = ["."]
|
|
25
|
+
include = ["cyclo_manager_cli*"]
|
|
26
|
+
|
|
27
|
+
[tool.setuptools.package-data]
|
|
28
|
+
cyclo_manager_cli = ["docker/*.yml", "docker/*.yaml", "config/*.yml", "config/*.yaml"]
|