nebula-config-kit 0.0.1__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.
@@ -0,0 +1,203 @@
1
+ Metadata-Version: 2.4
2
+ Name: nebula-config-kit
3
+ Version: 0.0.1
4
+ Summary: Define your Nebula mesh network once, generate validated configs for every host
5
+ Keywords: nebula,vpn,mesh-network,overlay-network,network-automation,configuration-management,infrastructure,pki
6
+ Author: Dmitry Tatarkin
7
+ Author-email: Dmitry Tatarkin <tatarkin@gmail.com>
8
+ License-Expression: MIT
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: System Administrators
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Topic :: System :: Networking
13
+ Classifier: Topic :: System :: Systems Administration
14
+ Classifier: Topic :: Security
15
+ Classifier: Typing :: Typed
16
+ Classifier: Environment :: Console
17
+ Classifier: Framework :: Pydantic :: 2
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Requires-Dist: pki-kit>=0.0.2
22
+ Requires-Dist: pydantic>=2.0
23
+ Requires-Dist: ruamel-yaml>=0.18
24
+ Requires-Dist: typer>=0.15 ; extra == 'cli'
25
+ Requires-Dist: rich>=13.0 ; extra == 'cli'
26
+ Requires-Python: >=3.12
27
+ Project-URL: Homepage, https://github.com/dtatarkin/nebula-config-kit
28
+ Project-URL: Repository, https://github.com/dtatarkin/nebula-config-kit
29
+ Project-URL: Issues, https://github.com/dtatarkin/nebula-config-kit/issues
30
+ Project-URL: Changelog, https://github.com/dtatarkin/nebula-config-kit/releases
31
+ Provides-Extra: cli
32
+ Description-Content-Type: text/markdown
33
+
34
+ # nebula-config-kit
35
+
36
+ **Stop hand-crafting Nebula configs. Define your mesh network once, generate configs for every host.**
37
+
38
+ nebula-config-kit is a Python library and CLI for managing [Nebula](https://github.com/slackhq/nebula) overlay network configurations. It takes a single declarative YAML file describing your entire network — hosts, lighthouses, relays, firewall rules — and generates validated, ready-to-deploy Nebula configs for each node.
39
+
40
+ ---
41
+
42
+ ## Why?
43
+
44
+ Managing a Nebula mesh network means juggling per-host YAML files that share 90% of their content but differ in subtle, error-prone ways. nebula-config-kit solves this:
45
+
46
+ - **Single source of truth** — one config file defines your entire network topology
47
+ - **Type-safe validation** — Pydantic models catch misconfigurations before deployment (duplicate IPs, missing lighthouses, invalid rules)
48
+ - **Automatic resolution** — lighthouse maps, relay lists, and firewall rules are computed per-host from your network definition
49
+ - **PKI integration** — built-in certificate management via pki-kit (CA creation, host cert signing, revocation)
50
+ - **Comment-preserving templates** — generated configs retain the original Nebula YAML comments for readability
51
+
52
+ ## Quick start
53
+
54
+ ### Install
55
+
56
+ ```bash
57
+ # With CLI
58
+ pip install nebula-config-kit[cli]
59
+
60
+ # Library only
61
+ pip install nebula-config-kit
62
+ ```
63
+
64
+ ### Define your network
65
+
66
+ Create `nebula-network.config.yml`:
67
+
68
+ ```yaml
69
+ network:
70
+ cidr: 10.10.0.0/16
71
+
72
+ certs:
73
+ ca_name: "My Network CA"
74
+ ca_duration: 3650d
75
+ host_duration: 365d
76
+
77
+ hosts:
78
+ defaults:
79
+ listen_port: 4242
80
+ tun_dev: nebula1
81
+ hosts:
82
+ lighthouse1:
83
+ nebula_ip: 10.10.0.1
84
+ public_endpoints: ["203.0.113.10"]
85
+ webserver:
86
+ nebula_ip: 10.10.0.10
87
+ database:
88
+ nebula_ip: 10.10.0.20
89
+
90
+ firewall:
91
+ security_groups:
92
+ icmp:
93
+ port: any
94
+ proto: icmp
95
+ direction: any
96
+ ssh:
97
+ port: 22
98
+ proto: tcp
99
+ direction: in
100
+ https:
101
+ port: 443
102
+ proto: tcp
103
+ direction: in
104
+ firewall_default:
105
+ all: [icmp]
106
+ firewall_rules:
107
+ webserver:
108
+ all: [ssh, https]
109
+ database:
110
+ webserver: [ssh]
111
+ ```
112
+
113
+ ### Generate configs
114
+
115
+ ```bash
116
+ # List all hosts
117
+ nebula-config hosts list
118
+
119
+ # Show resolved details for a host
120
+ nebula-config hosts show webserver
121
+
122
+ # Generate a complete Nebula config
123
+ nebula-config config generate webserver -o webserver.yml
124
+ ```
125
+
126
+ ### Use as a library
127
+
128
+ ```python
129
+ from pathlib import Path
130
+ from nebula_config_kit import load_config, resolve_host, generate_host_config
131
+ from nebula_config_kit.types import HostName
132
+
133
+ config = load_config(path=Path("nebula-network.config.yml"))
134
+ host = resolve_host(name=HostName("webserver"), config=config)
135
+ ```
136
+
137
+ ## Features
138
+
139
+ ### Host resolution
140
+
141
+ Hosts inherit from `defaults` and can override any setting. Lighthouses are auto-detected from hosts with `public_endpoints`. Relays are identified by the `am_relay` flag. Each host gets a resolved config with the correct static host map, lighthouse list, and relay list — excluding itself.
142
+
143
+ ### Security groups & firewall
144
+
145
+ Define reusable security groups, assign them to hosts or host groups, and nebula-config-kit resolves the full inbound/outbound firewall ruleset per host. Default rules apply to all hosts unless overridden.
146
+
147
+ ### PKI management
148
+
149
+ Integrated certificate lifecycle:
150
+
151
+ - CA key and certificate generation
152
+ - Host certificate signing with correct Nebula IP and groups
153
+ - Certificate revocation
154
+ - Validity tracking and renewal hints
155
+ - SOPS-encrypted key storage support
156
+
157
+ ### CLI output formats
158
+
159
+ ```bash
160
+ # Table (default), JSON, or YAML
161
+ nebula-config hosts list --output json
162
+ nebula-config hosts show database --output yaml
163
+ ```
164
+
165
+ ### Custom templates
166
+
167
+ Override the built-in Nebula config template to include your own settings:
168
+
169
+ ```bash
170
+ nebula-config config generate webserver --template my-template.yml
171
+ ```
172
+
173
+ ## Configuration
174
+
175
+ | Environment Variable | Default | Description |
176
+ | --------------------------------- | --------------------------- | ------------------------------------------ |
177
+ | `NEBULA_NETWORK_CONFIG` | `nebula-network.config.yml` | Path to network config file |
178
+ | `NEBULA_CONFIG_KIT_PKI_PATH` | `.` | Root directory for PKI stores |
179
+ | `NEBULA_CONFIG_KIT_PKI_NAME` | `default` | PKI instance name |
180
+ | `NEBULA_CONFIG_KIT_SOPS_ARGS` | — | Extra SOPS arguments for encrypted keys |
181
+ | `NEBULA_CONFIG_KIT_OUTPUT_FORMAT` | `table` | CLI output format: `table`, `json`, `yaml` |
182
+
183
+ ## Development
184
+
185
+ Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).
186
+
187
+ ```bash
188
+ # Install dependencies
189
+ uv sync --all-extras
190
+
191
+ # Run tests
192
+ just test
193
+
194
+ # Lint + type check
195
+ just lint
196
+
197
+ # All checks
198
+ just check
199
+ ```
200
+
201
+ ## License
202
+
203
+ See [LICENSE](LICENSE) for details.
@@ -0,0 +1,170 @@
1
+ # nebula-config-kit
2
+
3
+ **Stop hand-crafting Nebula configs. Define your mesh network once, generate configs for every host.**
4
+
5
+ nebula-config-kit is a Python library and CLI for managing [Nebula](https://github.com/slackhq/nebula) overlay network configurations. It takes a single declarative YAML file describing your entire network — hosts, lighthouses, relays, firewall rules — and generates validated, ready-to-deploy Nebula configs for each node.
6
+
7
+ ---
8
+
9
+ ## Why?
10
+
11
+ Managing a Nebula mesh network means juggling per-host YAML files that share 90% of their content but differ in subtle, error-prone ways. nebula-config-kit solves this:
12
+
13
+ - **Single source of truth** — one config file defines your entire network topology
14
+ - **Type-safe validation** — Pydantic models catch misconfigurations before deployment (duplicate IPs, missing lighthouses, invalid rules)
15
+ - **Automatic resolution** — lighthouse maps, relay lists, and firewall rules are computed per-host from your network definition
16
+ - **PKI integration** — built-in certificate management via pki-kit (CA creation, host cert signing, revocation)
17
+ - **Comment-preserving templates** — generated configs retain the original Nebula YAML comments for readability
18
+
19
+ ## Quick start
20
+
21
+ ### Install
22
+
23
+ ```bash
24
+ # With CLI
25
+ pip install nebula-config-kit[cli]
26
+
27
+ # Library only
28
+ pip install nebula-config-kit
29
+ ```
30
+
31
+ ### Define your network
32
+
33
+ Create `nebula-network.config.yml`:
34
+
35
+ ```yaml
36
+ network:
37
+ cidr: 10.10.0.0/16
38
+
39
+ certs:
40
+ ca_name: "My Network CA"
41
+ ca_duration: 3650d
42
+ host_duration: 365d
43
+
44
+ hosts:
45
+ defaults:
46
+ listen_port: 4242
47
+ tun_dev: nebula1
48
+ hosts:
49
+ lighthouse1:
50
+ nebula_ip: 10.10.0.1
51
+ public_endpoints: ["203.0.113.10"]
52
+ webserver:
53
+ nebula_ip: 10.10.0.10
54
+ database:
55
+ nebula_ip: 10.10.0.20
56
+
57
+ firewall:
58
+ security_groups:
59
+ icmp:
60
+ port: any
61
+ proto: icmp
62
+ direction: any
63
+ ssh:
64
+ port: 22
65
+ proto: tcp
66
+ direction: in
67
+ https:
68
+ port: 443
69
+ proto: tcp
70
+ direction: in
71
+ firewall_default:
72
+ all: [icmp]
73
+ firewall_rules:
74
+ webserver:
75
+ all: [ssh, https]
76
+ database:
77
+ webserver: [ssh]
78
+ ```
79
+
80
+ ### Generate configs
81
+
82
+ ```bash
83
+ # List all hosts
84
+ nebula-config hosts list
85
+
86
+ # Show resolved details for a host
87
+ nebula-config hosts show webserver
88
+
89
+ # Generate a complete Nebula config
90
+ nebula-config config generate webserver -o webserver.yml
91
+ ```
92
+
93
+ ### Use as a library
94
+
95
+ ```python
96
+ from pathlib import Path
97
+ from nebula_config_kit import load_config, resolve_host, generate_host_config
98
+ from nebula_config_kit.types import HostName
99
+
100
+ config = load_config(path=Path("nebula-network.config.yml"))
101
+ host = resolve_host(name=HostName("webserver"), config=config)
102
+ ```
103
+
104
+ ## Features
105
+
106
+ ### Host resolution
107
+
108
+ Hosts inherit from `defaults` and can override any setting. Lighthouses are auto-detected from hosts with `public_endpoints`. Relays are identified by the `am_relay` flag. Each host gets a resolved config with the correct static host map, lighthouse list, and relay list — excluding itself.
109
+
110
+ ### Security groups & firewall
111
+
112
+ Define reusable security groups, assign them to hosts or host groups, and nebula-config-kit resolves the full inbound/outbound firewall ruleset per host. Default rules apply to all hosts unless overridden.
113
+
114
+ ### PKI management
115
+
116
+ Integrated certificate lifecycle:
117
+
118
+ - CA key and certificate generation
119
+ - Host certificate signing with correct Nebula IP and groups
120
+ - Certificate revocation
121
+ - Validity tracking and renewal hints
122
+ - SOPS-encrypted key storage support
123
+
124
+ ### CLI output formats
125
+
126
+ ```bash
127
+ # Table (default), JSON, or YAML
128
+ nebula-config hosts list --output json
129
+ nebula-config hosts show database --output yaml
130
+ ```
131
+
132
+ ### Custom templates
133
+
134
+ Override the built-in Nebula config template to include your own settings:
135
+
136
+ ```bash
137
+ nebula-config config generate webserver --template my-template.yml
138
+ ```
139
+
140
+ ## Configuration
141
+
142
+ | Environment Variable | Default | Description |
143
+ | --------------------------------- | --------------------------- | ------------------------------------------ |
144
+ | `NEBULA_NETWORK_CONFIG` | `nebula-network.config.yml` | Path to network config file |
145
+ | `NEBULA_CONFIG_KIT_PKI_PATH` | `.` | Root directory for PKI stores |
146
+ | `NEBULA_CONFIG_KIT_PKI_NAME` | `default` | PKI instance name |
147
+ | `NEBULA_CONFIG_KIT_SOPS_ARGS` | — | Extra SOPS arguments for encrypted keys |
148
+ | `NEBULA_CONFIG_KIT_OUTPUT_FORMAT` | `table` | CLI output format: `table`, `json`, `yaml` |
149
+
150
+ ## Development
151
+
152
+ Requires Python 3.12+ and [uv](https://docs.astral.sh/uv/).
153
+
154
+ ```bash
155
+ # Install dependencies
156
+ uv sync --all-extras
157
+
158
+ # Run tests
159
+ just test
160
+
161
+ # Lint + type check
162
+ just lint
163
+
164
+ # All checks
165
+ just check
166
+ ```
167
+
168
+ ## License
169
+
170
+ See [LICENSE](LICENSE) for details.
@@ -0,0 +1,116 @@
1
+ [project]
2
+ name = "nebula-config-kit"
3
+ version = "0.0.1"
4
+ description = "Define your Nebula mesh network once, generate validated configs for every host"
5
+ readme = "README.md"
6
+ authors = [
7
+ { name = "Dmitry Tatarkin", email = "tatarkin@gmail.com" }
8
+ ]
9
+ license = "MIT"
10
+ requires-python = ">=3.12"
11
+ keywords = [
12
+ "nebula",
13
+ "vpn",
14
+ "mesh-network",
15
+ "overlay-network",
16
+ "network-automation",
17
+ "configuration-management",
18
+ "infrastructure",
19
+ "pki",
20
+ ]
21
+ classifiers = [
22
+ "Development Status :: 3 - Alpha",
23
+ "Intended Audience :: System Administrators",
24
+ "Intended Audience :: Developers",
25
+ "Topic :: System :: Networking",
26
+ "Topic :: System :: Systems Administration",
27
+ "Topic :: Security",
28
+ "Typing :: Typed",
29
+ "Environment :: Console",
30
+ "Framework :: Pydantic :: 2",
31
+ "Programming Language :: Python :: 3",
32
+ "Programming Language :: Python :: 3.12",
33
+ "Programming Language :: Python :: 3.13",
34
+ ]
35
+ dependencies = [
36
+ "pki-kit>=0.0.2",
37
+ "pydantic>=2.0",
38
+ "ruamel-yaml>=0.18",
39
+ ]
40
+
41
+ [project.urls]
42
+ Homepage = "https://github.com/dtatarkin/nebula-config-kit"
43
+ Repository = "https://github.com/dtatarkin/nebula-config-kit"
44
+ Issues = "https://github.com/dtatarkin/nebula-config-kit/issues"
45
+ Changelog = "https://github.com/dtatarkin/nebula-config-kit/releases"
46
+
47
+ [tool.uv.sources]
48
+ #pki-kit = { path = "lib/pki-kit", editable = true }
49
+
50
+ [project.optional-dependencies]
51
+ cli = ["typer>=0.15", "rich>=13.0"]
52
+
53
+ [project.scripts]
54
+ nebula-config = "nebula_config_kit.cli:main"
55
+ [dependency-groups]
56
+ dev = [
57
+ "codespell",
58
+ "mypy",
59
+ "pre-commit",
60
+ "pytest",
61
+ "python-dotenv[cli]",
62
+ "ruff",
63
+ "ty>=0.0.24",
64
+ ]
65
+
66
+ [tool.uv.build-backend]
67
+ module-name = "nebula_config_kit"
68
+
69
+ [build-system]
70
+ requires = ["uv_build"]
71
+ build-backend = "uv_build"
72
+
73
+ [tool.ruff]
74
+ target-version = "py312"
75
+ line-length = 120
76
+ src = ["src"]
77
+
78
+ [tool.ruff.lint]
79
+ select = ["F", "E", "W", "I", "N", "UP", "B", "A", "C4", "DTZ", "T20", "SIM", "TCH", "RUF", "PT", "S", "ANN"]
80
+
81
+ [tool.ruff.lint.per-file-ignores]
82
+ "tests/**/*.py" = ["ANN", "S101"]
83
+ "src/nebula_config_kit/cli/**/*.py" = ["T20", "TCH"]
84
+
85
+ [tool.ruff.lint.isort]
86
+ known-first-party = ["nebula_config_kit"]
87
+
88
+ [tool.ruff.lint.flake8-type-checking]
89
+ runtime-evaluated-base-classes = ["pydantic.BaseModel"]
90
+
91
+ [tool.mypy]
92
+ strict = true
93
+ plugins = ["pydantic.mypy"]
94
+ mypy_path = "src"
95
+
96
+ [[tool.mypy.overrides]]
97
+ module = "tests.*"
98
+ disallow_untyped_decorators = false
99
+
100
+ [[tool.mypy.overrides]]
101
+ module = "nebula_config_kit.cli.*"
102
+ disallow_untyped_decorators = false
103
+
104
+ [[tool.mypy.overrides]]
105
+ module = "ruamel.*"
106
+ ignore_missing_imports = true
107
+
108
+ [tool.pytest.ini_options]
109
+ testpaths = ["tests"]
110
+
111
+ [tool.ty.rules]
112
+ unused-type-ignore-comment = "ignore"
113
+ unresolved-import = "ignore"
114
+
115
+ [tool.codespell]
116
+ skip = ".git,uv.lock,dist"
@@ -0,0 +1,72 @@
1
+ """nebula-config-kit — Nebula overlay network configuration management."""
2
+
3
+ from ipaddress import IPv4Address, IPv4Network
4
+
5
+ from nebula_config_kit.config_gen import render_host_config
6
+ from nebula_config_kit.config_loader import DEFAULT_NEBULA_NETWORK_CONFIG_FILENAME, load_config
7
+ from nebula_config_kit.exceptions import (
8
+ ConfigFileError,
9
+ ConfigRenderError,
10
+ DuplicateIPError,
11
+ HostNotFoundError,
12
+ LighthouseConfigError,
13
+ NebulaConfigError,
14
+ )
15
+ from nebula_config_kit.firewall import resolve_firewall_rules
16
+ from nebula_config_kit.hosts import (
17
+ extract_lighthouses,
18
+ resolve_host_overrides,
19
+ resolve_lighthouses_for_host,
20
+ resolve_relays_for_host,
21
+ )
22
+ from nebula_config_kit.models import (
23
+ CertsConfig,
24
+ FirewallConfig,
25
+ HostConfig,
26
+ HostDefaults,
27
+ HostsConfig,
28
+ LighthouseInfo,
29
+ NebulaNetworkConfig,
30
+ NetworkConfig,
31
+ SecurityGroup,
32
+ )
33
+ from nebula_config_kit.network import get_prefix_length, make_sign_ip
34
+ from nebula_config_kit.orchestration import ResolvedHost, generate_host_config, resolve_host
35
+ from nebula_config_kit.types import Direction, FirewallRule, HostName, Protocol
36
+
37
+ __all__ = [
38
+ "DEFAULT_NEBULA_NETWORK_CONFIG_FILENAME",
39
+ "CertsConfig",
40
+ "ConfigFileError",
41
+ "ConfigRenderError",
42
+ "Direction",
43
+ "DuplicateIPError",
44
+ "FirewallConfig",
45
+ "FirewallRule",
46
+ "HostConfig",
47
+ "HostDefaults",
48
+ "HostName",
49
+ "HostNotFoundError",
50
+ "HostsConfig",
51
+ "IPv4Address",
52
+ "IPv4Network",
53
+ "LighthouseConfigError",
54
+ "LighthouseInfo",
55
+ "NebulaConfigError",
56
+ "NebulaNetworkConfig",
57
+ "NetworkConfig",
58
+ "Protocol",
59
+ "ResolvedHost",
60
+ "SecurityGroup",
61
+ "extract_lighthouses",
62
+ "generate_host_config",
63
+ "get_prefix_length",
64
+ "load_config",
65
+ "make_sign_ip",
66
+ "render_host_config",
67
+ "resolve_firewall_rules",
68
+ "resolve_host",
69
+ "resolve_host_overrides",
70
+ "resolve_lighthouses_for_host",
71
+ "resolve_relays_for_host",
72
+ ]
@@ -0,0 +1,82 @@
1
+ """nebula-config CLI — optional command-line interface."""
2
+
3
+ from typing import Annotated
4
+
5
+ import typer
6
+
7
+ from nebula_config_kit.cli._context import CliContext, OutputFormat
8
+ from nebula_config_kit.config_loader import DEFAULT_NEBULA_NETWORK_CONFIG_FILENAME
9
+ from nebula_config_kit.exceptions import NebulaConfigError
10
+
11
+ app = typer.Typer(
12
+ name="nebula-config",
13
+ help="Nebula overlay network configuration management.",
14
+ no_args_is_help=True,
15
+ )
16
+
17
+
18
+ def _version_callback(value: bool) -> None:
19
+ if value:
20
+ from importlib.metadata import version
21
+
22
+ print(f"nebula-config {version('nebula-config-kit')}")
23
+ raise typer.Exit
24
+
25
+
26
+ @app.callback()
27
+ def main_callback(
28
+ ctx: typer.Context,
29
+ config: Annotated[
30
+ str,
31
+ typer.Option(envvar="NEBULA_NETWORK_CONFIG", help="Path to network config file."),
32
+ ] = DEFAULT_NEBULA_NETWORK_CONFIG_FILENAME,
33
+ pki_base_path: Annotated[
34
+ str,
35
+ typer.Option(envvar="NEBULA_CONFIG_KIT_PKI_PATH", help="Root directory for pki-kit stores."),
36
+ ] = ".",
37
+ pki_name: Annotated[
38
+ str,
39
+ typer.Option(envvar="NEBULA_CONFIG_KIT_PKI_NAME", help="PKI instance name."),
40
+ ] = "default",
41
+ sops_args: Annotated[
42
+ str | None,
43
+ typer.Option(envvar="NEBULA_CONFIG_KIT_SOPS_ARGS", help="Extra SOPS arguments (space-separated)."),
44
+ ] = None,
45
+ output_format: Annotated[
46
+ OutputFormat,
47
+ typer.Option("--output-format", "-f", envvar="NEBULA_CONFIG_KIT_OUTPUT_FORMAT", help="Output format."),
48
+ ] = OutputFormat.TABLE,
49
+ _version: Annotated[
50
+ bool | None,
51
+ typer.Option("--version", callback=_version_callback, is_eager=True, help="Show version and exit."),
52
+ ] = None,
53
+ ) -> None:
54
+ """Nebula overlay network configuration management."""
55
+ from pathlib import Path
56
+
57
+ ctx.obj = CliContext(
58
+ config_path=Path(config),
59
+ pki_base_path=Path(pki_base_path),
60
+ pki_name=pki_name,
61
+ sops_args=tuple(sops_args.split()) if sops_args else (),
62
+ output_format=output_format,
63
+ )
64
+
65
+
66
+ # Register subcommand groups (import after app is defined to avoid circular imports)
67
+ from nebula_config_kit.cli._config import config_app # noqa: E402
68
+ from nebula_config_kit.cli._hosts import hosts_app # noqa: E402
69
+
70
+ app.add_typer(config_app)
71
+ app.add_typer(hosts_app)
72
+
73
+
74
+ def main() -> None:
75
+ """Entry point for the nebula-config CLI."""
76
+ try:
77
+ app()
78
+ except NebulaConfigError as exc:
79
+ from rich.console import Console
80
+
81
+ Console(stderr=True).print(f"[red]Error:[/red] {exc}")
82
+ raise typer.Exit(code=1) from None
@@ -0,0 +1,52 @@
1
+ """Config generation CLI subcommands."""
2
+
3
+ from pathlib import Path
4
+ from typing import Annotated
5
+
6
+ import typer
7
+
8
+ from nebula_config_kit.cli._context import CliContext
9
+
10
+ config_app = typer.Typer(name="config", help="Configuration generation.", no_args_is_help=True)
11
+
12
+
13
+ def _get_ctx(ctx: typer.Context) -> CliContext:
14
+ result: CliContext = ctx.obj
15
+ return result
16
+
17
+
18
+ @config_app.command("generate")
19
+ def generate(
20
+ ctx: typer.Context,
21
+ name: Annotated[str, typer.Argument(help="Host name to generate config for.")],
22
+ output: Annotated[
23
+ Path | None, typer.Option("--output", "-o", help="Path to write the generated config file.")
24
+ ] = None,
25
+ template: Annotated[Path | None, typer.Option(help="Custom Nebula config template.")] = None,
26
+ ) -> None:
27
+ """Generate Nebula configuration for a host."""
28
+ from nebula_config_kit.cli._context import nebula_pki_session
29
+ from nebula_config_kit.config_loader import load_config
30
+ from nebula_config_kit.exceptions import ConfigFileError
31
+ from nebula_config_kit.orchestration import generate_host_config
32
+ from nebula_config_kit.types import HostName
33
+
34
+ cli_ctx = _get_ctx(ctx=ctx)
35
+ config = load_config(cli_ctx.config_path)
36
+ if config is None:
37
+ raise ConfigFileError(message="Configuration file not found.")
38
+
39
+ with nebula_pki_session(cli_ctx) as pki:
40
+ config_yaml = generate_host_config(
41
+ HostName(name),
42
+ config=config,
43
+ pki=pki,
44
+ template_path=template,
45
+ )
46
+
47
+ if output is not None:
48
+ output.parent.mkdir(parents=True, exist_ok=True)
49
+ output.write_text(config_yaml)
50
+ print(f"Config written to {output}")
51
+ else:
52
+ print(config_yaml, end="")