smanager 0.2.2__tar.gz → 0.3.0__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.
- smanager-0.3.0/LICENSE.txt +21 -0
- smanager-0.3.0/PKG-INFO +120 -0
- smanager-0.3.0/README.md +105 -0
- {smanager-0.2.2 → smanager-0.3.0}/pyproject.toml +6 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/__init__.py +1 -1
- smanager-0.3.0/smanager/cli/commands/__init__.py +8 -0
- smanager-0.3.0/smanager/cli/commands/all.py +132 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/cli/commands/config.py +1 -1
- smanager-0.3.0/smanager/cli/commands/dependency.py +93 -0
- smanager-0.3.0/smanager/cli/commands/group.py +88 -0
- smanager-0.3.0/smanager/cli/commands/info.py +160 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/cli/commands/metadata.py +7 -4
- smanager-0.3.0/smanager/cli/commands/service.py +88 -0
- smanager-0.3.0/smanager/cli/commands/status.py +50 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/cli/config.py +20 -0
- smanager-0.3.0/smanager/cli/formatters/__init__.py +10 -0
- smanager-0.3.0/smanager/cli/formatters/info_table.py +77 -0
- smanager-0.3.0/smanager/cli/formatters/runtime_style.py +89 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/cli/formatters/status_table.py +13 -5
- {smanager-0.2.2 → smanager-0.3.0}/smanager/cli/main.py +1 -2
- {smanager-0.2.2 → smanager-0.3.0}/smanager/cli/metadata_wizard.py +13 -12
- {smanager-0.2.2 → smanager-0.3.0}/smanager/crawler/sd_finder.py +10 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/global_manager/global_manager.py +10 -19
- {smanager-0.2.2 → smanager-0.3.0}/smanager/service_managers/__init__.py +8 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/service_managers/docker_manager.py +3 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/service_managers/local_manager.py +3 -0
- smanager-0.3.0/smanager/service_managers/registry.py +36 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/vpn/base_vpn.py +5 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/vpn/providers/tailscale.py +24 -1
- smanager-0.3.0/smanager.egg-info/PKG-INFO +120 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager.egg-info/SOURCES.txt +11 -1
- {smanager-0.2.2 → smanager-0.3.0}/tests/test_events.py +32 -0
- smanager-0.3.0/tests/test_info_output.py +237 -0
- smanager-0.3.0/tests/test_runtime_style.py +125 -0
- smanager-0.3.0/tests/test_sd_finder.py +87 -0
- smanager-0.3.0/tests/test_service_manager_registry.py +65 -0
- {smanager-0.2.2 → smanager-0.3.0}/tests/test_status_output.py +53 -3
- smanager-0.3.0/tests/test_tailscale_vpn.py +62 -0
- smanager-0.2.2/PKG-INFO +0 -8
- smanager-0.2.2/README.md +0 -60
- smanager-0.2.2/smanager/cli/commands/__init__.py +0 -11
- smanager-0.2.2/smanager/cli/commands/all.py +0 -38
- smanager-0.2.2/smanager/cli/commands/dependency.py +0 -27
- smanager-0.2.2/smanager/cli/commands/group.py +0 -27
- smanager-0.2.2/smanager/cli/commands/service.py +0 -27
- smanager-0.2.2/smanager/cli/commands/status.py +0 -71
- smanager-0.2.2/smanager/cli/formatters/__init__.py +0 -3
- smanager-0.2.2/smanager.egg-info/PKG-INFO +0 -8
- {smanager-0.2.2 → smanager-0.3.0}/setup.cfg +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/cli/__init__.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/cli/events.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/crawler/__init__.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/datatypes/__init__.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/datatypes/config.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/datatypes/sd_info_v2.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/datatypes/service_status.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/events.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/global_manager/__init__.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/global_manager/base_global_manager.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/service_managers/base_manager.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/service_managers/base_sdv2_manager.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/vpn/__init__.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/vpn/providers/__init__.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager/vpn/registry.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager.egg-info/dependency_links.txt +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager.egg-info/entry_points.txt +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager.egg-info/requires.txt +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/smanager.egg-info/top_level.txt +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/tests/test_cli_events.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/tests/test_metadata_wizard.py +0 -0
- {smanager-0.2.2 → smanager-0.3.0}/tests/test_service_manager_events.py +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Daniel Pérez Rodríguez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
smanager-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: smanager
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: A simple server manager for self-hosted services
|
|
5
|
+
Author: Daniel Pérez Rodríguez
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Description-Content-Type: text/markdown
|
|
9
|
+
License-File: LICENSE.txt
|
|
10
|
+
Requires-Dist: PyYAML>=6.0
|
|
11
|
+
Requires-Dist: click>=8.0
|
|
12
|
+
Requires-Dist: rich>=13.0
|
|
13
|
+
Requires-Dist: InquirerPy>=0.3.4
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# SManager
|
|
17
|
+
> A simple server manager for self-hosted services, with VPN integration and support for both local and Docker-based services.
|
|
18
|
+
|
|
19
|
+
When building a self-hosted setup, it’s common to end up with dozens of local services, Docker containers, and maintenance scripts scattered across your system. Tasks as simple as restarting or stopping a service can quickly become frustrating when there’s no clear overview of what is running, how components relate to each other, or how everything is managed.
|
|
20
|
+
|
|
21
|
+
SManager provides a simple and unified CLI for managing both local and Docker services, with built-in support for VPN integration and interactive metadata management.
|
|
22
|
+
|
|
23
|
+
Reseting all your music-related services becomes as simple as:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
smanager group restart music
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
- Unified service management for local/systemd and Docker runtimes.
|
|
31
|
+
- VPN integration (Tailscale provider support).
|
|
32
|
+
- Interactive metadata creation and editing.
|
|
33
|
+
- YAML-based global configuration.
|
|
34
|
+
- Rich service status reporting with optional JSON output.
|
|
35
|
+
|
|
36
|
+
## CLI Usage
|
|
37
|
+
Use this command pattern:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
smanager <group> <command> [options]
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Discover available commands at any level:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
smanager --help
|
|
47
|
+
smanager <group> --help
|
|
48
|
+
smanager <group> <command> --help
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Status Commands
|
|
52
|
+
|
|
53
|
+
Status is now a subcommand under each resource group:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
smanager service status <service_id>
|
|
57
|
+
smanager group status <group_name>
|
|
58
|
+
smanager dependency status <dependency_name>
|
|
59
|
+
smanager all status
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Optional JSON output is available for each status command:
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
smanager service status <service_id> --json
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Info Commands
|
|
69
|
+
|
|
70
|
+
Info is available under each resource group and shows service name plus WebUI URL:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
smanager service info <service_id>
|
|
74
|
+
smanager group info <group_name>
|
|
75
|
+
smanager dependency info <dependency_name>
|
|
76
|
+
smanager all info
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Use `--details` to include extra operational columns:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
smanager service info <service_id> --details
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Metadata Commands
|
|
86
|
+
The `metadata` group provides interactive workflows for service metadata files.
|
|
87
|
+
|
|
88
|
+
### Create Metadata
|
|
89
|
+
```bash
|
|
90
|
+
smanager metadata init
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Optional output override:
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
smanager metadata init --output /path/to/sd_info.json
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Edit Existing Metadata
|
|
100
|
+
```bash
|
|
101
|
+
smanager metadata edit
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Edit a specific file directly:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
smanager metadata edit --file /path/to/sd_info.json
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Behavior summary:
|
|
111
|
+
- Interactive prompts with inline defaults.
|
|
112
|
+
- Runtime-aware sections (Docker vs Local).
|
|
113
|
+
- Multi-select support for `groups` and `depends_on`.
|
|
114
|
+
- Validation before writing changes.
|
|
115
|
+
|
|
116
|
+
## Notes
|
|
117
|
+
- `metadata init` creates a new file.
|
|
118
|
+
- `metadata edit` modifies an existing file.
|
|
119
|
+
- Use command-specific `--help` for the latest options and examples.
|
|
120
|
+
|
smanager-0.3.0/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# SManager
|
|
2
|
+
> A simple server manager for self-hosted services, with VPN integration and support for both local and Docker-based services.
|
|
3
|
+
|
|
4
|
+
When building a self-hosted setup, it’s common to end up with dozens of local services, Docker containers, and maintenance scripts scattered across your system. Tasks as simple as restarting or stopping a service can quickly become frustrating when there’s no clear overview of what is running, how components relate to each other, or how everything is managed.
|
|
5
|
+
|
|
6
|
+
SManager provides a simple and unified CLI for managing both local and Docker services, with built-in support for VPN integration and interactive metadata management.
|
|
7
|
+
|
|
8
|
+
Reseting all your music-related services becomes as simple as:
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
smanager group restart music
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Features
|
|
15
|
+
- Unified service management for local/systemd and Docker runtimes.
|
|
16
|
+
- VPN integration (Tailscale provider support).
|
|
17
|
+
- Interactive metadata creation and editing.
|
|
18
|
+
- YAML-based global configuration.
|
|
19
|
+
- Rich service status reporting with optional JSON output.
|
|
20
|
+
|
|
21
|
+
## CLI Usage
|
|
22
|
+
Use this command pattern:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
smanager <group> <command> [options]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Discover available commands at any level:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
smanager --help
|
|
32
|
+
smanager <group> --help
|
|
33
|
+
smanager <group> <command> --help
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Status Commands
|
|
37
|
+
|
|
38
|
+
Status is now a subcommand under each resource group:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
smanager service status <service_id>
|
|
42
|
+
smanager group status <group_name>
|
|
43
|
+
smanager dependency status <dependency_name>
|
|
44
|
+
smanager all status
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Optional JSON output is available for each status command:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
smanager service status <service_id> --json
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Info Commands
|
|
54
|
+
|
|
55
|
+
Info is available under each resource group and shows service name plus WebUI URL:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
smanager service info <service_id>
|
|
59
|
+
smanager group info <group_name>
|
|
60
|
+
smanager dependency info <dependency_name>
|
|
61
|
+
smanager all info
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Use `--details` to include extra operational columns:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
smanager service info <service_id> --details
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Metadata Commands
|
|
71
|
+
The `metadata` group provides interactive workflows for service metadata files.
|
|
72
|
+
|
|
73
|
+
### Create Metadata
|
|
74
|
+
```bash
|
|
75
|
+
smanager metadata init
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Optional output override:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
smanager metadata init --output /path/to/sd_info.json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Edit Existing Metadata
|
|
85
|
+
```bash
|
|
86
|
+
smanager metadata edit
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Edit a specific file directly:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
smanager metadata edit --file /path/to/sd_info.json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Behavior summary:
|
|
96
|
+
- Interactive prompts with inline defaults.
|
|
97
|
+
- Runtime-aware sections (Docker vs Local).
|
|
98
|
+
- Multi-select support for `groups` and `depends_on`.
|
|
99
|
+
- Validation before writing changes.
|
|
100
|
+
|
|
101
|
+
## Notes
|
|
102
|
+
- `metadata init` creates a new file.
|
|
103
|
+
- `metadata edit` modifies an existing file.
|
|
104
|
+
- Use command-specific `--help` for the latest options and examples.
|
|
105
|
+
|
|
@@ -5,6 +5,12 @@ build-backend = "setuptools.build_meta"
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "smanager"
|
|
7
7
|
dynamic = ["version"]
|
|
8
|
+
authors = [
|
|
9
|
+
{name = "Daniel Pérez Rodríguez"}
|
|
10
|
+
]
|
|
11
|
+
description = "A simple server manager for self-hosted services"
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
license = "MIT"
|
|
8
14
|
requires-python = ">=3.9"
|
|
9
15
|
dependencies = [
|
|
10
16
|
"PyYAML>=6.0",
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
from .service import service_cmd
|
|
2
|
+
from .group import group_cmd
|
|
3
|
+
from .dependency import dependency_cmd
|
|
4
|
+
from .all import all_cmd
|
|
5
|
+
from .config import config_cmd
|
|
6
|
+
from .metadata import metadata_cmd
|
|
7
|
+
|
|
8
|
+
__all__ = ["service_cmd", "group_cmd", "dependency_cmd", "all_cmd", "config_cmd", "metadata_cmd"]
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from ..config import get_manager
|
|
4
|
+
from ..events import attach_cli_event_renderer
|
|
5
|
+
from .info import emit_all_info
|
|
6
|
+
from .status import emit_all_status
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group(name="all")
|
|
10
|
+
@click.pass_context
|
|
11
|
+
def all_cmd(ctx: click.Context) -> None:
|
|
12
|
+
"""Manage all services.
|
|
13
|
+
|
|
14
|
+
\b
|
|
15
|
+
Actions: start, stop, restart, enable, disable, status, info
|
|
16
|
+
|
|
17
|
+
Management actions require --yes to prevent accidental execution.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _run_all_action(ctx: click.Context, action: str, yes: bool) -> None:
|
|
22
|
+
if not yes:
|
|
23
|
+
raise click.UsageError(
|
|
24
|
+
f"This will run '{action}' on ALL services. Pass --yes to confirm."
|
|
25
|
+
)
|
|
26
|
+
manager = get_manager(ctx)
|
|
27
|
+
detach_renderer = attach_cli_event_renderer(manager, command_scope="all")
|
|
28
|
+
try:
|
|
29
|
+
manager.manage_all(action)
|
|
30
|
+
except ValueError as e:
|
|
31
|
+
raise click.ClickException(str(e))
|
|
32
|
+
except RuntimeError as e:
|
|
33
|
+
raise click.ClickException(str(e))
|
|
34
|
+
finally:
|
|
35
|
+
detach_renderer()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@all_cmd.command(name="start")
|
|
39
|
+
@click.option(
|
|
40
|
+
"--yes",
|
|
41
|
+
is_flag=True,
|
|
42
|
+
default=False,
|
|
43
|
+
help="Confirm the operation on all services.",
|
|
44
|
+
)
|
|
45
|
+
@click.pass_context
|
|
46
|
+
def all_start(ctx: click.Context, yes: bool) -> None:
|
|
47
|
+
"""Start all managed services.
|
|
48
|
+
|
|
49
|
+
Requires --yes to prevent accidental execution.
|
|
50
|
+
"""
|
|
51
|
+
_run_all_action(ctx, "start", yes)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@all_cmd.command(name="stop")
|
|
55
|
+
@click.option(
|
|
56
|
+
"--yes",
|
|
57
|
+
is_flag=True,
|
|
58
|
+
default=False,
|
|
59
|
+
help="Confirm the operation on all services.",
|
|
60
|
+
)
|
|
61
|
+
@click.pass_context
|
|
62
|
+
def all_stop(ctx: click.Context, yes: bool) -> None:
|
|
63
|
+
"""Stop all managed services.
|
|
64
|
+
|
|
65
|
+
Requires --yes to prevent accidental execution.
|
|
66
|
+
"""
|
|
67
|
+
_run_all_action(ctx, "stop", yes)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@all_cmd.command(name="restart")
|
|
71
|
+
@click.option(
|
|
72
|
+
"--yes",
|
|
73
|
+
is_flag=True,
|
|
74
|
+
default=False,
|
|
75
|
+
help="Confirm the operation on all services.",
|
|
76
|
+
)
|
|
77
|
+
@click.pass_context
|
|
78
|
+
def all_restart(ctx: click.Context, yes: bool) -> None:
|
|
79
|
+
"""Restart all managed services.
|
|
80
|
+
|
|
81
|
+
Requires --yes to prevent accidental execution.
|
|
82
|
+
"""
|
|
83
|
+
_run_all_action(ctx, "restart", yes)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@all_cmd.command(name="enable")
|
|
87
|
+
@click.option(
|
|
88
|
+
"--yes",
|
|
89
|
+
is_flag=True,
|
|
90
|
+
default=False,
|
|
91
|
+
help="Confirm the operation on all services.",
|
|
92
|
+
)
|
|
93
|
+
@click.pass_context
|
|
94
|
+
def all_enable(ctx: click.Context, yes: bool) -> None:
|
|
95
|
+
"""Enable all managed services.
|
|
96
|
+
|
|
97
|
+
Requires --yes to prevent accidental execution.
|
|
98
|
+
"""
|
|
99
|
+
_run_all_action(ctx, "enable", yes)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
@all_cmd.command(name="disable")
|
|
103
|
+
@click.option(
|
|
104
|
+
"--yes",
|
|
105
|
+
is_flag=True,
|
|
106
|
+
default=False,
|
|
107
|
+
help="Confirm the operation on all services.",
|
|
108
|
+
)
|
|
109
|
+
@click.pass_context
|
|
110
|
+
def all_disable(ctx: click.Context, yes: bool) -> None:
|
|
111
|
+
"""Disable all managed services.
|
|
112
|
+
|
|
113
|
+
Requires --yes to prevent accidental execution.
|
|
114
|
+
"""
|
|
115
|
+
_run_all_action(ctx, "disable", yes)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
@all_cmd.command(name="status")
|
|
119
|
+
@click.option("--json", "as_json", is_flag=True, default=False, help="Output as JSON.")
|
|
120
|
+
@click.pass_context
|
|
121
|
+
def all_status(ctx: click.Context, as_json: bool) -> None:
|
|
122
|
+
"""Show status for all managed services."""
|
|
123
|
+
emit_all_status(ctx, as_json)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
@all_cmd.command(name="info")
|
|
127
|
+
@click.option("--details", is_flag=True, default=False, help="Include extra metadata columns.")
|
|
128
|
+
@click.option("--json", "as_json", is_flag=True, default=False, help="Output as JSON.")
|
|
129
|
+
@click.pass_context
|
|
130
|
+
def all_info(ctx: click.Context, details: bool, as_json: bool) -> None:
|
|
131
|
+
"""Show info for all managed services."""
|
|
132
|
+
emit_all_info(ctx, as_json, details)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from ..config import get_manager
|
|
4
|
+
from ..events import attach_cli_event_renderer
|
|
5
|
+
from .info import emit_dependency_info
|
|
6
|
+
from .status import emit_dependency_status
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group(name="dependency")
|
|
10
|
+
@click.pass_context
|
|
11
|
+
def dependency_cmd(ctx: click.Context) -> None:
|
|
12
|
+
"""Manage services by dependency.
|
|
13
|
+
|
|
14
|
+
\b
|
|
15
|
+
Actions: start, stop, restart, enable, disable, status, info
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _run_dependency_action(ctx: click.Context, action: str, dependency_name: str) -> None:
|
|
20
|
+
manager = get_manager(ctx)
|
|
21
|
+
detach_renderer = attach_cli_event_renderer(manager, command_scope="dependency")
|
|
22
|
+
try:
|
|
23
|
+
manager.manage_by_dependency(dependency_name, action)
|
|
24
|
+
except ValueError as e:
|
|
25
|
+
raise click.ClickException(str(e))
|
|
26
|
+
except RuntimeError as e:
|
|
27
|
+
raise click.ClickException(str(e))
|
|
28
|
+
finally:
|
|
29
|
+
detach_renderer()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dependency_cmd.command(name="start")
|
|
33
|
+
@click.argument("dependency_name")
|
|
34
|
+
@click.pass_context
|
|
35
|
+
def dependency_start(ctx: click.Context, dependency_name: str) -> None:
|
|
36
|
+
"""Start services that depend on DEPENDENCY_NAME."""
|
|
37
|
+
_run_dependency_action(ctx, "start", dependency_name)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dependency_cmd.command(name="stop")
|
|
41
|
+
@click.argument("dependency_name")
|
|
42
|
+
@click.pass_context
|
|
43
|
+
def dependency_stop(ctx: click.Context, dependency_name: str) -> None:
|
|
44
|
+
"""Stop services that depend on DEPENDENCY_NAME."""
|
|
45
|
+
_run_dependency_action(ctx, "stop", dependency_name)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@dependency_cmd.command(name="restart")
|
|
49
|
+
@click.argument("dependency_name")
|
|
50
|
+
@click.pass_context
|
|
51
|
+
def dependency_restart(ctx: click.Context, dependency_name: str) -> None:
|
|
52
|
+
"""Restart services that depend on DEPENDENCY_NAME."""
|
|
53
|
+
_run_dependency_action(ctx, "restart", dependency_name)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@dependency_cmd.command(name="enable")
|
|
57
|
+
@click.argument("dependency_name")
|
|
58
|
+
@click.pass_context
|
|
59
|
+
def dependency_enable(ctx: click.Context, dependency_name: str) -> None:
|
|
60
|
+
"""Enable services that depend on DEPENDENCY_NAME."""
|
|
61
|
+
_run_dependency_action(ctx, "enable", dependency_name)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@dependency_cmd.command(name="disable")
|
|
65
|
+
@click.argument("dependency_name")
|
|
66
|
+
@click.pass_context
|
|
67
|
+
def dependency_disable(ctx: click.Context, dependency_name: str) -> None:
|
|
68
|
+
"""Disable services that depend on DEPENDENCY_NAME."""
|
|
69
|
+
_run_dependency_action(ctx, "disable", dependency_name)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@dependency_cmd.command(name="status")
|
|
73
|
+
@click.argument("dependency_name")
|
|
74
|
+
@click.option("--json", "as_json", is_flag=True, default=False, help="Output as JSON.")
|
|
75
|
+
@click.pass_context
|
|
76
|
+
def dependency_status(ctx: click.Context, dependency_name: str, as_json: bool) -> None:
|
|
77
|
+
"""Show status for services by dependency."""
|
|
78
|
+
emit_dependency_status(ctx, dependency_name, as_json)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@dependency_cmd.command(name="info")
|
|
82
|
+
@click.argument("dependency_name")
|
|
83
|
+
@click.option("--details", is_flag=True, default=False, help="Include extra metadata columns.")
|
|
84
|
+
@click.option("--json", "as_json", is_flag=True, default=False, help="Output as JSON.")
|
|
85
|
+
@click.pass_context
|
|
86
|
+
def dependency_info(
|
|
87
|
+
ctx: click.Context,
|
|
88
|
+
dependency_name: str,
|
|
89
|
+
details: bool,
|
|
90
|
+
as_json: bool,
|
|
91
|
+
) -> None:
|
|
92
|
+
"""Show info for services by dependency."""
|
|
93
|
+
emit_dependency_info(ctx, dependency_name, as_json, details)
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import click
|
|
2
|
+
|
|
3
|
+
from ..config import get_manager
|
|
4
|
+
from ..events import attach_cli_event_renderer
|
|
5
|
+
from .info import emit_group_info
|
|
6
|
+
from .status import emit_group_status
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@click.group(name="group")
|
|
10
|
+
@click.pass_context
|
|
11
|
+
def group_cmd(ctx: click.Context) -> None:
|
|
12
|
+
"""Manage all services in a group.
|
|
13
|
+
|
|
14
|
+
\b
|
|
15
|
+
Actions: start, stop, restart, enable, disable, status, info
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def _run_group_action(ctx: click.Context, action: str, group_name: str) -> None:
|
|
20
|
+
manager = get_manager(ctx)
|
|
21
|
+
detach_renderer = attach_cli_event_renderer(manager, command_scope="group")
|
|
22
|
+
try:
|
|
23
|
+
manager.manage_group(group_name, action)
|
|
24
|
+
except ValueError as e:
|
|
25
|
+
raise click.ClickException(str(e))
|
|
26
|
+
except RuntimeError as e:
|
|
27
|
+
raise click.ClickException(str(e))
|
|
28
|
+
finally:
|
|
29
|
+
detach_renderer()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@group_cmd.command(name="start")
|
|
33
|
+
@click.argument("group_name")
|
|
34
|
+
@click.pass_context
|
|
35
|
+
def group_start(ctx: click.Context, group_name: str) -> None:
|
|
36
|
+
"""Start all services in GROUP_NAME."""
|
|
37
|
+
_run_group_action(ctx, "start", group_name)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@group_cmd.command(name="stop")
|
|
41
|
+
@click.argument("group_name")
|
|
42
|
+
@click.pass_context
|
|
43
|
+
def group_stop(ctx: click.Context, group_name: str) -> None:
|
|
44
|
+
"""Stop all services in GROUP_NAME."""
|
|
45
|
+
_run_group_action(ctx, "stop", group_name)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@group_cmd.command(name="restart")
|
|
49
|
+
@click.argument("group_name")
|
|
50
|
+
@click.pass_context
|
|
51
|
+
def group_restart(ctx: click.Context, group_name: str) -> None:
|
|
52
|
+
"""Restart all services in GROUP_NAME."""
|
|
53
|
+
_run_group_action(ctx, "restart", group_name)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
@group_cmd.command(name="enable")
|
|
57
|
+
@click.argument("group_name")
|
|
58
|
+
@click.pass_context
|
|
59
|
+
def group_enable(ctx: click.Context, group_name: str) -> None:
|
|
60
|
+
"""Enable all services in GROUP_NAME."""
|
|
61
|
+
_run_group_action(ctx, "enable", group_name)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@group_cmd.command(name="disable")
|
|
65
|
+
@click.argument("group_name")
|
|
66
|
+
@click.pass_context
|
|
67
|
+
def group_disable(ctx: click.Context, group_name: str) -> None:
|
|
68
|
+
"""Disable all services in GROUP_NAME."""
|
|
69
|
+
_run_group_action(ctx, "disable", group_name)
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@group_cmd.command(name="status")
|
|
73
|
+
@click.argument("group_name")
|
|
74
|
+
@click.option("--json", "as_json", is_flag=True, default=False, help="Output as JSON.")
|
|
75
|
+
@click.pass_context
|
|
76
|
+
def group_status(ctx: click.Context, group_name: str, as_json: bool) -> None:
|
|
77
|
+
"""Show status for all services in GROUP_NAME."""
|
|
78
|
+
emit_group_status(ctx, group_name, as_json)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
@group_cmd.command(name="info")
|
|
82
|
+
@click.argument("group_name")
|
|
83
|
+
@click.option("--details", is_flag=True, default=False, help="Include extra metadata columns.")
|
|
84
|
+
@click.option("--json", "as_json", is_flag=True, default=False, help="Output as JSON.")
|
|
85
|
+
@click.pass_context
|
|
86
|
+
def group_info(ctx: click.Context, group_name: str, details: bool, as_json: bool) -> None:
|
|
87
|
+
"""Show info for all services in GROUP_NAME."""
|
|
88
|
+
emit_group_info(ctx, group_name, as_json, details)
|