empeira 0.1.0.pre.alpha.1
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.
- checksums.yaml +7 -0
- data/LICENSE +661 -0
- data/README.md +150 -0
- data/bin/empeira +18 -0
- data/config/defaults.yaml +229 -0
- data/docs/addons.md +331 -0
- data/docs/architecture.md +277 -0
- data/docs/configuration.md +1204 -0
- data/docs/development.md +472 -0
- data/docs/hiera-and-eyaml.md +361 -0
- data/docs/installation.md +280 -0
- data/docs/networking.md +362 -0
- data/docs/nodes.md +642 -0
- data/docs/proxy.md +136 -0
- data/docs/troubleshooting.md +361 -0
- data/lib/empeira/addons/environment.rb +82 -0
- data/lib/empeira/addons/error.rb +14 -0
- data/lib/empeira/addons/installation.rb +119 -0
- data/lib/empeira/addons/manifest.rb +112 -0
- data/lib/empeira/addons/service.rb +50 -0
- data/lib/empeira/addons/storage.rb +94 -0
- data/lib/empeira/agent/acquisition.rb +120 -0
- data/lib/empeira/agent/artifact.rb +41 -0
- data/lib/empeira/agent/authentication.rb +122 -0
- data/lib/empeira/agent/cache.rb +122 -0
- data/lib/empeira/agent/cache_storage.rb +82 -0
- data/lib/empeira/agent/download.rb +84 -0
- data/lib/empeira/agent/native_commands.rb +84 -0
- data/lib/empeira/agent/release_sources.rb +64 -0
- data/lib/empeira/agent/target.rb +66 -0
- data/lib/empeira/agent/versions.rb +29 -0
- data/lib/empeira/application.rb +86 -0
- data/lib/empeira/build.json +5 -0
- data/lib/empeira/build_info.rb +46 -0
- data/lib/empeira/cli/addons.rb +45 -0
- data/lib/empeira/cli/base.rb +73 -0
- data/lib/empeira/cli/completion.rb +42 -0
- data/lib/empeira/cli/config.rb +22 -0
- data/lib/empeira/cli/main.rb +114 -0
- data/lib/empeira/cli/node.rb +87 -0
- data/lib/empeira/cli/progress.rb +169 -0
- data/lib/empeira/cli/proxy.rb +36 -0
- data/lib/empeira/cli/update.rb +23 -0
- data/lib/empeira/completion/addons.rb +93 -0
- data/lib/empeira/completion/bash.rb +62 -0
- data/lib/empeira/completion/catalog.rb +170 -0
- data/lib/empeira/configuration/additional_services.rb +74 -0
- data/lib/empeira/configuration/addons.rb +85 -0
- data/lib/empeira/configuration/agent_schema.rb +163 -0
- data/lib/empeira/configuration/agent_values.rb +54 -0
- data/lib/empeira/configuration/bootstrap_guests.rb +42 -0
- data/lib/empeira/configuration/command_mocks.rb +65 -0
- data/lib/empeira/configuration/display.rb +20 -0
- data/lib/empeira/configuration/dns_rewrites.rb +58 -0
- data/lib/empeira/configuration/document.rb +67 -0
- data/lib/empeira/configuration/eyaml.rb +46 -0
- data/lib/empeira/configuration/hiera_modulepath.rb +40 -0
- data/lib/empeira/configuration/hiera_mount_schema.rb +62 -0
- data/lib/empeira/configuration/hiera_mounts.rb +83 -0
- data/lib/empeira/configuration/image_schema.rb +68 -0
- data/lib/empeira/configuration/loader.rb +70 -0
- data/lib/empeira/configuration/merge.rb +48 -0
- data/lib/empeira/configuration/network_redirects.rb +73 -0
- data/lib/empeira/configuration/node_images.rb +64 -0
- data/lib/empeira/configuration/schema.rb +215 -0
- data/lib/empeira/configuration/server_mounts.rb +106 -0
- data/lib/empeira/configuration/service_configuration.rb +40 -0
- data/lib/empeira/configuration/ssh_preferences.rb +83 -0
- data/lib/empeira/configuration/user.rb +46 -0
- data/lib/empeira/configuration/vm_interfaces.rb +147 -0
- data/lib/empeira/control_plane/additional_configurations.rb +106 -0
- data/lib/empeira/control_plane/browser.rb +73 -0
- data/lib/empeira/control_plane/controller.rb +763 -0
- data/lib/empeira/control_plane/discovery.rb +69 -0
- data/lib/empeira/control_plane/environment.rb +101 -0
- data/lib/empeira/control_plane/files.rb +263 -0
- data/lib/empeira/control_plane/health.rb +104 -0
- data/lib/empeira/control_plane/plan.rb +356 -0
- data/lib/empeira/control_plane/storage.rb +48 -0
- data/lib/empeira/errors.rb +9 -0
- data/lib/empeira/execution/console.rb +45 -0
- data/lib/empeira/execution/diagnostics.rb +210 -0
- data/lib/empeira/execution/launch_error.rb +14 -0
- data/lib/empeira/execution/result.rb +11 -0
- data/lib/empeira/execution/runner.rb +235 -0
- data/lib/empeira/execution/terminal.rb +35 -0
- data/lib/empeira/hostname_pattern.rb +14 -0
- data/lib/empeira/images/configuration.rb +44 -0
- data/lib/empeira/images/identity.rb +30 -0
- data/lib/empeira/images/recipe.rb +22 -0
- data/lib/empeira/images/reference.rb +43 -0
- data/lib/empeira/images/source.rb +19 -0
- data/lib/empeira/immutable.rb +19 -0
- data/lib/empeira/infrastructure/cleanup.rb +328 -0
- data/lib/empeira/infrastructure/definition.rb +59 -0
- data/lib/empeira/infrastructure/owned_files.rb +63 -0
- data/lib/empeira/infrastructure/recovery_inventory.rb +53 -0
- data/lib/empeira/infrastructure/service.rb +237 -0
- data/lib/empeira/infrastructure/status.rb +73 -0
- data/lib/empeira/infrastructure/store.rb +274 -0
- data/lib/empeira/modules/events.rb +67 -0
- data/lib/empeira/modules/git_safety.rb +60 -0
- data/lib/empeira/modules/host_git.rb +91 -0
- data/lib/empeira/modules/image.rb +27 -0
- data/lib/empeira/modules/installer.rb +67 -0
- data/lib/empeira/modules/request.rb +68 -0
- data/lib/empeira/modules/state.rb +87 -0
- data/lib/empeira/modules/storage.rb +35 -0
- data/lib/empeira/network/bootstrap_proxy.rb +157 -0
- data/lib/empeira/network/definition.rb +61 -0
- data/lib/empeira/network/direct_egress.rb +133 -0
- data/lib/empeira/network/egress.rb +27 -0
- data/lib/empeira/network/gateway.rb +79 -0
- data/lib/empeira/network/host_policy.rb +53 -0
- data/lib/empeira/network/naming.rb +28 -0
- data/lib/empeira/network/peer/adapter_image.rb +32 -0
- data/lib/empeira/network/peer/allocation.rb +45 -0
- data/lib/empeira/network/peer/attachment.rb +27 -0
- data/lib/empeira/network/peer/backend.rb +108 -0
- data/lib/empeira/network/peer/channel.rb +133 -0
- data/lib/empeira/network/peer/channel_server.rb +71 -0
- data/lib/empeira/network/peer/docker_adapter.rb +165 -0
- data/lib/empeira/network/peer/helper_security.rb +40 -0
- data/lib/empeira/network/peer/layout.rb +55 -0
- data/lib/empeira/network/peer/linux_podman.rb +114 -0
- data/lib/empeira/network/peer/podman_machine.rb +112 -0
- data/lib/empeira/network/policy.rb +39 -0
- data/lib/empeira/network/proxy_bindings.rb +52 -0
- data/lib/empeira/network/proxy_policy.rb +64 -0
- data/lib/empeira/network/redirects.rb +89 -0
- data/lib/empeira/network/resource.rb +50 -0
- data/lib/empeira/node/agent_installer.rb +31 -0
- data/lib/empeira/node/agent_package.rb +125 -0
- data/lib/empeira/node/agent_repository.rb +160 -0
- data/lib/empeira/node/apt_configuration.rb +85 -0
- data/lib/empeira/node/bootstrap.rb +17 -0
- data/lib/empeira/node/certificates.rb +98 -0
- data/lib/empeira/node/command_mock.rb +38 -0
- data/lib/empeira/node/command_mocks.rb +114 -0
- data/lib/empeira/node/container.rb +134 -0
- data/lib/empeira/node/container_agent_bootstrap.rb +43 -0
- data/lib/empeira/node/container_bootstrap.rb +52 -0
- data/lib/empeira/node/container_guest.rb +42 -0
- data/lib/empeira/node/container_lifecycle.rb +145 -0
- data/lib/empeira/node/container_preparation.rb +144 -0
- data/lib/empeira/node/container_state.rb +129 -0
- data/lib/empeira/node/definition.rb +20 -0
- data/lib/empeira/node/diagnostic_command.rb +19 -0
- data/lib/empeira/node/dnf_agent_repository.rb +202 -0
- data/lib/empeira/node/external_fact.rb +21 -0
- data/lib/empeira/node/image.rb +38 -0
- data/lib/empeira/node/interactive_tools.rb +33 -0
- data/lib/empeira/node/interface.rb +18 -0
- data/lib/empeira/node/inventory.rb +143 -0
- data/lib/empeira/node/package_bootstrap.rb +129 -0
- data/lib/empeira/node/package_proxy.rb +102 -0
- data/lib/empeira/node/package_sources.rb +19 -0
- data/lib/empeira/node/puppet_command.rb +12 -0
- data/lib/empeira/node/rpm_configuration.rb +62 -0
- data/lib/empeira/node/run_request.rb +52 -0
- data/lib/empeira/node/runtime_proxy.rb +86 -0
- data/lib/empeira/node/service.rb +72 -0
- data/lib/empeira/node/ssh_client.rb +25 -0
- data/lib/empeira/node/ssh_credentials.rb +78 -0
- data/lib/empeira/node/ssh_endpoint.rb +58 -0
- data/lib/empeira/node/ssh_identity.rb +37 -0
- data/lib/empeira/node/user_ssh.rb +60 -0
- data/lib/empeira/node/vm.rb +89 -0
- data/lib/empeira/node/vm_bootstrap.rb +53 -0
- data/lib/empeira/node/vm_lifecycle.rb +212 -0
- data/lib/empeira/node/vm_preflight.rb +37 -0
- data/lib/empeira/node/vm_preparation.rb +161 -0
- data/lib/empeira/node/vm_state.rb +161 -0
- data/lib/empeira/platform/facts.rb +66 -0
- data/lib/empeira/platform/kvm.rb +91 -0
- data/lib/empeira/platform/locations.rb +51 -0
- data/lib/empeira/platform/resolvers.rb +85 -0
- data/lib/empeira/platform/routes.rb +50 -0
- data/lib/empeira/progress.rb +70 -0
- data/lib/empeira/project_root.rb +47 -0
- data/lib/empeira/providers/lifecycle.rb +96 -0
- data/lib/empeira/providers/registry.rb +21 -0
- data/lib/empeira/providers/resource.rb +32 -0
- data/lib/empeira/providers.rb +55 -0
- data/lib/empeira/runtime/agent_helper.rb +34 -0
- data/lib/empeira/runtime/container.rb +184 -0
- data/lib/empeira/runtime/diagnostic_execution.rb +52 -0
- data/lib/empeira/runtime/docker.rb +87 -0
- data/lib/empeira/runtime/image_metadata.rb +83 -0
- data/lib/empeira/runtime/interface.rb +8 -0
- data/lib/empeira/runtime/mount_probe.rb +57 -0
- data/lib/empeira/runtime/podman.rb +122 -0
- data/lib/empeira/runtime/recipe_build.rb +103 -0
- data/lib/empeira/runtime/registry_diagnostics.rb +23 -0
- data/lib/empeira/runtime/service_arguments.rb +55 -0
- data/lib/empeira/runtime/service_images.rb +118 -0
- data/lib/empeira/runtime/service_inspection.rb +159 -0
- data/lib/empeira/runtime/services.rb +120 -0
- data/lib/empeira/runtime/update_helper.rb +97 -0
- data/lib/empeira/runtime/workspace_network.rb +69 -0
- data/lib/empeira/server/environment_configuration.rb +53 -0
- data/lib/empeira/server/http.rb +38 -0
- data/lib/empeira/server/puppetdb_runtime.rb +74 -0
- data/lib/empeira/server/relay_certificate.rb +76 -0
- data/lib/empeira/server/runtime.rb +90 -0
- data/lib/empeira/services/definition.rb +42 -0
- data/lib/empeira/updates/images.rb +104 -0
- data/lib/empeira/updates/modules.rb +45 -0
- data/lib/empeira/updates/service.rb +45 -0
- data/lib/empeira/version_requirement.rb +23 -0
- data/lib/empeira/vm/agent.rb +66 -0
- data/lib/empeira/vm/bootstrap_requirements.rb +69 -0
- data/lib/empeira/vm/certificate_runtime.rb +30 -0
- data/lib/empeira/vm/cloud_init.rb +171 -0
- data/lib/empeira/vm/disk.rb +136 -0
- data/lib/empeira/vm/guest.rb +123 -0
- data/lib/empeira/vm/guest_channel.rb +110 -0
- data/lib/empeira/vm/guest_network.rb +94 -0
- data/lib/empeira/vm/guest_output.rb +52 -0
- data/lib/empeira/vm/guest_shell.rb +79 -0
- data/lib/empeira/vm/guest_upload.rb +43 -0
- data/lib/empeira/vm/image_cache.rb +77 -0
- data/lib/empeira/vm/image_source.rb +91 -0
- data/lib/empeira/vm/interface.rb +8 -0
- data/lib/empeira/vm/interface_ownership.rb +124 -0
- data/lib/empeira/vm/interface_routes.rb +101 -0
- data/lib/empeira/vm/interfaces.rb +240 -0
- data/lib/empeira/vm/management.rb +73 -0
- data/lib/empeira/vm/prerequisites.rb +42 -0
- data/lib/empeira/vm/qemu.rb +83 -0
- data/lib/empeira/vm/qemu_runtime.rb +404 -0
- data/lib/empeira/vm/removal.rb +30 -0
- data/lib/empeira/vm/root_disk.rb +92 -0
- data/lib/empeira/vm/session_lock.rb +56 -0
- data/lib/empeira/vm/system_ssh.rb +29 -0
- data/lib/empeira/workspace.rb +42 -0
- data/lib/empeira.rb +209 -0
- data/resources/browser/relay.rb +22 -0
- data/resources/gateway/Containerfile +8 -0
- data/resources/gateway/bridge.rb +66 -0
- data/resources/gateway/configure.rb +323 -0
- data/resources/modules/Containerfile +15 -0
- data/resources/modules/Gemfile +5 -0
- data/resources/modules/Gemfile.lock +105 -0
- data/resources/modules/worker.rb +161 -0
- data/resources/network/adapter/Containerfile +13 -0
- data/resources/network/adapter/bridge_linux.go +51 -0
- data/resources/network/adapter/framing.go +45 -0
- data/resources/network/adapter/framing_test.go +53 -0
- data/resources/network/adapter/go.mod +3 -0
- data/resources/network/adapter/main_linux.go +273 -0
- data/resources/network/channel.rb +18 -0
- data/resources/network/ssh_connect.rb +32 -0
- data/resources/nodes/apt_sources.rb +66 -0
- data/resources/nodes/debian/Containerfile +10 -0
- data/resources/nodes/diagnostic_exec.rb +109 -0
- data/resources/nodes/interactive_tools.rb +139 -0
- data/resources/nodes/managed_file.rb +91 -0
- data/resources/nodes/management/guest_agent.py +415 -0
- data/resources/nodes/management/setup.sh +20 -0
- data/resources/nodes/management/shell_rc.sh +12 -0
- data/resources/nodes/management/system_account.sh +24 -0
- data/resources/nodes/management/system_home.sh +15 -0
- data/resources/nodes/rpm/Containerfile +10 -0
- data/resources/nodes/runtime_proxy.rb +244 -0
- data/resources/nodes/ssh/proxy.rb +16 -0
- data/resources/nodes/ssh/sshd_config +15 -0
- data/resources/nodes/ssh/start +6 -0
- data/resources/proxy/Containerfile +10 -0
- data/resources/relay/Containerfile +5 -0
- data/resources/relay/puppetdb.rb +81 -0
- data/resources/relay/server_environment.rb +10 -0
- data/resources/relay/server_start.sh +41 -0
- metadata +326 -0
|
@@ -0,0 +1,1204 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Empeira runs `git rev-parse --show-toplevel` through the central execution runner
|
|
4
|
+
from the current directory, canonicalizes the returned root (including macOS
|
|
5
|
+
symlink paths), and requires `<git-root>/.empeira.yaml`. The marker explicitly opts
|
|
6
|
+
that Git repository into Empeira. Invocation from any subdirectory works; there is
|
|
7
|
+
no `--project` override or Puppet-repository heuristic. Missing Git/markers produce
|
|
8
|
+
actionable errors including the resolved root and `touch` command.
|
|
9
|
+
|
|
10
|
+
An empty file or `{}` uses defaults. Nonempty configuration must be one YAML mapping.
|
|
11
|
+
Duplicate keys, multiple documents, aliases and object tags are rejected. Unreadable
|
|
12
|
+
files and broken marker symlinks fail. Help/version/self-update are project-independent.
|
|
13
|
+
|
|
14
|
+
Precedence, from lowest to highest:
|
|
15
|
+
|
|
16
|
+
1. [Built-in defaults](../config/defaults.yaml).
|
|
17
|
+
2. The selected control repository's `.empeira.yaml`.
|
|
18
|
+
3. Optional host preferences in `~/.empeira.yaml`.
|
|
19
|
+
4. Explicitly permitted CLI overrides.
|
|
20
|
+
|
|
21
|
+
Mappings deep-merge; scalars and arrays replace lower-precedence values. Explicit
|
|
22
|
+
`null` is allowed only where the schema permits it. Every source is validated
|
|
23
|
+
before merging, so a later override cannot hide an invalid project setting.
|
|
24
|
+
Cross-field validation runs against the effective configuration.
|
|
25
|
+
|
|
26
|
+
## Optional user preferences
|
|
27
|
+
|
|
28
|
+
`~/.empeira.yaml` holds local workstation preferences and is not committed to the
|
|
29
|
+
control repository. A missing or empty file is normal and produces no warning.
|
|
30
|
+
It may contain exactly these settings, independently or together:
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
runtime:
|
|
34
|
+
container_engine: docker
|
|
35
|
+
images:
|
|
36
|
+
registry: registry.example.net
|
|
37
|
+
ssh:
|
|
38
|
+
user: empeira
|
|
39
|
+
identity: ~/.ssh/id_ed25519
|
|
40
|
+
port: 22
|
|
41
|
+
rules:
|
|
42
|
+
- hosts: ["web-*", "app-?.example.net"]
|
|
43
|
+
user: root
|
|
44
|
+
identity: ~/.ssh/id_ed25519_lab
|
|
45
|
+
port: 2222
|
|
46
|
+
- hosts: ["db-*"]
|
|
47
|
+
user: admin
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
User preferences override the same project keys; an explicit `--container-engine`
|
|
51
|
+
overrides the user preference. All other project mappings remain intact. For example,
|
|
52
|
+
a project selecting Podman and `images.registry: null` uses Docker and the cache above
|
|
53
|
+
on this workstation without changing the repository. Explicit user `registry: null`
|
|
54
|
+
restores Docker Hub resolution. `config show` displays the effective non-sensitive values.
|
|
55
|
+
There is no separate source-reporting option.
|
|
56
|
+
|
|
57
|
+
`ssh` is personal configuration for interactive `empeira node ssh` only; it is
|
|
58
|
+
rejected in project YAML. Global `user`, `identity` and `port` are independently optional,
|
|
59
|
+
as is the `rules` array. Each rule requires a nonempty `hosts` array and at least
|
|
60
|
+
one of `user`, `identity` or `port`. Ports must be integers from 1 to 65535.
|
|
61
|
+
Unknown keys and passwords are rejected. Patterns match
|
|
62
|
+
the entire hostname, ignore case and support only `*` and `?`, with the same matching
|
|
63
|
+
semantics as proxy hostname rules. Any pattern can select a rule. All matching
|
|
64
|
+
rules apply in list order; the last rule defining a field wins for that field.
|
|
65
|
+
An omitted field preserves the previous value.
|
|
66
|
+
|
|
67
|
+
Each field resolves independently: explicit `--user`/`--identity`/`--port`, then its last
|
|
68
|
+
matching rule, then its global value, then the provider default. Without a configured
|
|
69
|
+
value, VMs use `empeira` and their existing managed key; containers use the local
|
|
70
|
+
username and normal OpenSSH identities/agent/config. Both providers default to system
|
|
71
|
+
SSH guest port 22; this is independent of any private host transport port. Identity paths in this YAML
|
|
72
|
+
must be absolute or start with `~/`, expanded through the platform home. Relative
|
|
73
|
+
CLI identity paths retain their existing meaning relative to the invocation directory.
|
|
74
|
+
Before connecting, the selected external key must be a readable regular file with
|
|
75
|
+
no symlink and no group/other permission bits (`chmod 600` or `400`). Key contents
|
|
76
|
+
are never read, copied or included in diagnostics by preference resolution.
|
|
77
|
+
|
|
78
|
+
Personal SSH preferences are kept outside the effective infrastructure configuration,
|
|
79
|
+
`config show`, inventory and fingerprints. They do not alter internal VM SSH,
|
|
80
|
+
bootstrap, agent configuration, Puppet, shell/console, start/run or control-plane
|
|
81
|
+
behavior. File checks apply only when an identity is selected for `node ssh`.
|
|
82
|
+
New VMs use the locked system account `empeira` with home `/var/lib/empeira` only
|
|
83
|
+
for the default regular system SSH login, without sudo grants. Its UID is allocated
|
|
84
|
+
by the guest. Internal management uses root, an independent key and a dedicated
|
|
85
|
+
public-key-only daemon with PAM disabled; personal SSH settings never affect it.
|
|
86
|
+
There is no configurable management user, UID or compatibility option. Older VM
|
|
87
|
+
layouts require explicit destruction with the previous revision and recreation.
|
|
88
|
+
|
|
89
|
+
This file is deliberately not a second project definition. Any other key, including
|
|
90
|
+
`server`, `agent`, `network`, `containers`, `browser`, `images.server`, `images.nodes`, or
|
|
91
|
+
credential fields, fails with the user-file path and offending YAML path. Duplicate
|
|
92
|
+
keys, aliases, object tags, multiple YAML documents and control-character keys are
|
|
93
|
+
rejected just as for project YAML. Invalid lower-precedence values cannot be hidden
|
|
94
|
+
by a later override. A user file does not replace the required project opt-in marker.
|
|
95
|
+
Home resolution uses Ruby/platform facilities on Linux, macOS and WSL2.
|
|
96
|
+
|
|
97
|
+
## Project configuration
|
|
98
|
+
|
|
99
|
+
Example `.empeira.yaml`:
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
version: 1
|
|
103
|
+
requirements:
|
|
104
|
+
empeira: null # Set a release requirement when using a released Empeira build.
|
|
105
|
+
runtime:
|
|
106
|
+
container_engine: podman
|
|
107
|
+
server:
|
|
108
|
+
environment: production
|
|
109
|
+
network:
|
|
110
|
+
egress: []
|
|
111
|
+
proxy:
|
|
112
|
+
enabled: false
|
|
113
|
+
node_defaults:
|
|
114
|
+
os: ubuntu
|
|
115
|
+
version: "24.04"
|
|
116
|
+
memory: 2048
|
|
117
|
+
cpus: 2
|
|
118
|
+
puppetdb:
|
|
119
|
+
enabled: true
|
|
120
|
+
bootstrap:
|
|
121
|
+
enabled: false
|
|
122
|
+
scripts: []
|
|
123
|
+
packages:
|
|
124
|
+
install: {default: [], debian: [], redhat: []}
|
|
125
|
+
remove: {default: [], debian: [], redhat: []}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
`version: 1` is the configuration schema version, unrelated to the application
|
|
129
|
+
release version. A partial project mapping may omit it and inherit the default.
|
|
130
|
+
`node_defaults.version` is an OS version string and must be quoted if numeric.
|
|
131
|
+
|
|
132
|
+
| Path | Type and default |
|
|
133
|
+
| --- | --- |
|
|
134
|
+
| `version` | Integer, exactly `1` |
|
|
135
|
+
| `requirements.empeira` | RubyGems requirement string, or `null` (default) |
|
|
136
|
+
| `runtime.container_engine` | `podman` (default) or `docker` |
|
|
137
|
+
| `server.runtime` | OpenVox startup defaults; optional startup, configuration path and environment-key overrides for compatible custom images |
|
|
138
|
+
| `puppetdb.runtime` | OpenVoxDB process defaults; optional entrypoint, user, Java arguments, paths and environment key overrides for compatible custom images |
|
|
139
|
+
| `images.server` | OpenVox Server OCI image by default; repository/tag, digest or exact reference |
|
|
140
|
+
| `images.puppetdb` | OpenVoxDB OCI image by default; independent of the server image |
|
|
141
|
+
| `images.postgres` | PostgreSQL OCI image, independently replaceable |
|
|
142
|
+
| `agent.package`, `agent.version` | Defined in [built-in defaults](../config/defaults.yaml); independent of server images |
|
|
143
|
+
| `agent.install.method` | `repository` (default) or `package` |
|
|
144
|
+
| `agent.install.repositories.KEY` | Pinned OpenVox release packages and reviewed destinations by default |
|
|
145
|
+
| `agent.install.apt.KEY`, `agent.install.dnf.KEY` | Native sources with a generic `default` and partial OS overrides |
|
|
146
|
+
| `agent.install.packages.KEY.ARCH` | Direct HTTPS `.deb`/`.rpm` URL, optional SHA-256 and signature policy |
|
|
147
|
+
| `agent.cache.enabled` | Shared host package cache, enabled by default |
|
|
148
|
+
| `server.environment` | Puppet environment name, `production` |
|
|
149
|
+
| `server.memory`, `server.cpus` | Positive integers, `1536` MiB and `2` CPUs |
|
|
150
|
+
| `server.timeout` | Positive readiness timeout in seconds per component, `240` |
|
|
151
|
+
| `server.mounts` | Additional server-only host bind mounts, `[]`; `source`, `target`, optional boolean `readonly` (default `true`) |
|
|
152
|
+
| `puppetdb.memory` | Positive integer MiB, `768` |
|
|
153
|
+
| `network.egress` | Direct TCP proxy-bypass host/port entries, `[]`; a project array replaces the default array |
|
|
154
|
+
| `network.redirects` | Exact IPv4/protocol/port endpoints redirected to enabled internal services, `[]` |
|
|
155
|
+
| `proxy.enabled` | Boolean, `false`; creates the normal HTTP/HTTPS policy proxy |
|
|
156
|
+
| `proxy.global` | DNS destination array, `[]` |
|
|
157
|
+
| `proxy.rules` | Additive hostname-glob rules with `hosts` and `allow` arrays, `[]` |
|
|
158
|
+
| `vm.disk` | New VM virtual disk capacity in GiB, integer `1`–`2048`, default `30`; must accommodate the base image |
|
|
159
|
+
| `vm.interfaces` | VM-only hostname rules defining dummy/VLAN devices with explicit IPv4 CIDR host addresses, `[]` |
|
|
160
|
+
| `vm.console.root_password` | Initial console password, `empeira`; a string overrides it and `null` disables it |
|
|
161
|
+
| `dns.upstream` | `mode: host` and empty `servers` by default; explicit mode requires resolver IPs |
|
|
162
|
+
| `dns.additional_resolver` | Optional DNS name or IP address queried before the existing upstream for non-Empeira names; NXDOMAIN/NODATA fall through |
|
|
163
|
+
| `dns.rewrites` | Exact external hostnames mapped to enabled `<service>.empeira.internal` targets; `[]` by default |
|
|
164
|
+
| `hiera.mounts` | Puppet-aware module/environment mounts, `[]`; each source is optional unless `required: true` |
|
|
165
|
+
| `node_defaults.os` | Configured node OS family, default `ubuntu` |
|
|
166
|
+
| `node_defaults.version` | OS version string, default `"24.04"` |
|
|
167
|
+
| `node_defaults.init` | `process` by default; `systemd` requires supported Podman/cgroup v2 |
|
|
168
|
+
| `node_defaults.memory` | Positive integer MiB, `1024` |
|
|
169
|
+
| `node_defaults.cpus` | Positive integer, `2` |
|
|
170
|
+
| `mocks.commands` | Named command stubs for test nodes, `{}`; each requires `path`, `mock_to` and `exit_code` |
|
|
171
|
+
| `puppetdb.enabled` | Boolean, `true` |
|
|
172
|
+
| `eyaml.enabled` | Boolean, `false`; requires both key paths when enabled |
|
|
173
|
+
| `eyaml.private_key`, `eyaml.public_key` | Local PEM file paths, `null` by default |
|
|
174
|
+
| `bootstrap.guests` | Reviewed agent-presence metadata and bootstrap-proxy destination domains; Rocky and AlmaLinux supply stable package base URLs |
|
|
175
|
+
| `bootstrap.packages.install` | Global one-time package lists for `default`, `debian` and `redhat` |
|
|
176
|
+
| `bootstrap.packages.remove` | Global one-time removal lists for `default`, `debian` and `redhat` |
|
|
177
|
+
| `images.direct_egress` | Recipe or explicit image reference implementing the workspace gateway contract |
|
|
178
|
+
| `images.r10k.build` | Disposable r10k helper recipe, `modules/Containerfile` |
|
|
179
|
+
| `modules.path` | Actual directory containing modules directly; `modules` by default, relative to the canonical repository root or absolute |
|
|
180
|
+
| `addons` | Mapping of standalone addon names to `git`, `ref`, and optional `config` mapping; empty by default. The addon receives its own settings as `EMPEIRA_ADDON_CONFIG_*`. See [addons](addons.md). |
|
|
181
|
+
| `bootstrap.enabled` | Boolean, `false` |
|
|
182
|
+
| `bootstrap.scripts` | Project-local UTF-8 script paths, `[]`; run during VM cloud-init only when enabled |
|
|
183
|
+
| `images.registry` | Optional default registry host; `null` resolves hostless repositories through `docker.io` |
|
|
184
|
+
| `browser.image` | Configurable repository/tag, `docker.io/linuxserver/chromium:latest` |
|
|
185
|
+
| `browser.start_url` | Initial Chromium page, `about:blank` |
|
|
186
|
+
| `containers.additional` | Array of infrastructure service definitions, `[]` |
|
|
187
|
+
|
|
188
|
+
Unknown keys, unused namespaces, named nodes, and `node_defaults.provider` are
|
|
189
|
+
rejected. `puppetdb.enabled: false` omits PostgreSQL/PuppetDB and disables server
|
|
190
|
+
storeconfigs/report integration, preserving any previously created database volumes.
|
|
191
|
+
|
|
192
|
+
### DNS rewrites for internal services
|
|
193
|
+
|
|
194
|
+
Use an additional infrastructure service as a local API Compatibility Layer:
|
|
195
|
+
|
|
196
|
+
```yaml
|
|
197
|
+
dns:
|
|
198
|
+
rewrites:
|
|
199
|
+
- from: ipam.example.net
|
|
200
|
+
to: api-layer.empeira.internal
|
|
201
|
+
- from: inventory.example.net
|
|
202
|
+
to: api-layer.empeira.internal
|
|
203
|
+
containers:
|
|
204
|
+
additional:
|
|
205
|
+
- name: api-layer
|
|
206
|
+
image:
|
|
207
|
+
repository: registry.example.net/lab/api-layer
|
|
208
|
+
tag: "1"
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Each entry requires exactly `from` and `to`. Hostnames are case-insensitive; a
|
|
212
|
+
trailing root dot is accepted. Duplicate sources, wildcards, regular expressions,
|
|
213
|
+
URLs and IP addresses are rejected. Sources must be outside `empeira.internal`,
|
|
214
|
+
which prevents self references and cycles. Targets must name an enabled built-in
|
|
215
|
+
or additional service, using exactly `<service>.empeira.internal`; node names and
|
|
216
|
+
nested names are not service targets. `up` reports missing or disabled targets
|
|
217
|
+
before acquiring images or changing infrastructure.
|
|
218
|
+
|
|
219
|
+
Run `empeira up` after adding, changing or removing a rewrite. CoreDNS reloads its
|
|
220
|
+
configuration while preserving its container and existing container/VM nodes.
|
|
221
|
+
Service-discovery updates supply the current target IPv4 address; no IP belongs in
|
|
222
|
+
the rewrite configuration. Repeated unchanged `up` calls do not reload the policy.
|
|
223
|
+
See [DNS rewrites](networking.md#exact-dns-rewrites) for DNS response semantics.
|
|
224
|
+
|
|
225
|
+
A DNS rewrite changes name resolution only. Applications still send the original
|
|
226
|
+
HTTP Host/TLS SNI name and use their original protocol and port. The service must
|
|
227
|
+
implement the desired API behavior and, for HTTPS, present a certificate valid for
|
|
228
|
+
the original hostname that the client trusts. Empeira supplies no TLS termination,
|
|
229
|
+
certificate management, HTTP transformation, port mapping or proxy-policy changes.
|
|
230
|
+
|
|
231
|
+
### Additional server bind mounts
|
|
232
|
+
|
|
233
|
+
Projects can expose local artifacts to the Puppet/OpenVox configuration server:
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
server:
|
|
237
|
+
mounts:
|
|
238
|
+
- source: ../artifacts
|
|
239
|
+
target: /srv/puppet-artifacts
|
|
240
|
+
- source: /srv/example-ca
|
|
241
|
+
target: /etc/example-ca
|
|
242
|
+
readonly: true
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
Relative sources resolve against the canonical Git control-repository root, even
|
|
246
|
+
when invoking Empeira from a subdirectory. Absolute sources outside the repository
|
|
247
|
+
are allowed. Sources must exist and resolve through `realpath` to regular files or
|
|
248
|
+
directories; broken source symlinks, control characters and commas are rejected.
|
|
249
|
+
Targets must be absolute, are normalized, and cannot contain `..` segments or
|
|
250
|
+
control characters/commas. `/` itself and system paths `/dev`, `/proc` and `/sys`
|
|
251
|
+
cannot be mounted. Source data trees must not contain sockets, devices or other
|
|
252
|
+
special files. Validation does not follow nested directory symlinks.
|
|
253
|
+
|
|
254
|
+
Mounts are read-only unless explicitly configured with `readonly: false`. Writable
|
|
255
|
+
mounts allow the server to change host data, subject to host filesystem permissions.
|
|
256
|
+
The runtime must be able to see the canonical host path, including when its engine
|
|
257
|
+
runs in a VM. Empeira checks mounted visibility using the existing mount probe.
|
|
258
|
+
This interface accepts no named volumes, tmpfs, device/runtime-socket mounts,
|
|
259
|
+
propagation flags, SELinux options or arbitrary Docker/Podman mount strings.
|
|
260
|
+
|
|
261
|
+
The mounts belong exclusively to `server.empeira.internal`. For example, a manifest
|
|
262
|
+
can use `file('/srv/puppet-artifacts/banner.txt')` during catalog compilation to
|
|
263
|
+
supply a Puppet `file` resource's content, if that is what the control code expects.
|
|
264
|
+
Empeira provides the bind mount without adding Puppet-specific file handling.
|
|
265
|
+
It does **not** expose the host path to agent nodes: a server-local path is not
|
|
266
|
+
automatically an agent-local `source` path. Container/VM nodes, PuppetDB, PostgreSQL,
|
|
267
|
+
DNS, proxy, browser, additional services and the r10k helper receive no such mounts.
|
|
268
|
+
|
|
269
|
+
Duplicate targets and ancestor/descendant overlaps between project mounts are
|
|
270
|
+
rejected. The same collision check covers all actual Empeira-managed server mount
|
|
271
|
+
targets, including CA, SSL, server data, the environment/control repository,
|
|
272
|
+
modules, Hiera, EYAML and PuppetDB startup/configuration files when enabled.
|
|
273
|
+
|
|
274
|
+
Mounted directory content stays live: editing files requires no server recreation.
|
|
275
|
+
Contents are not hashed. Changing the canonical source, normalized target or
|
|
276
|
+
`readonly` changes the server service fingerprint; the next `empeira up` uses normal
|
|
277
|
+
selective reconciliation to recreate the server. There is no hot-mount operation.
|
|
278
|
+
For an individually mounted file, edit it in place: editors that replace its inode
|
|
279
|
+
may require recreating the server. Mount its containing directory for atomic file
|
|
280
|
+
replacement to remain visible.
|
|
281
|
+
|
|
282
|
+
### Command mocks on test nodes
|
|
283
|
+
|
|
284
|
+
Use `mocks.commands` for Puppet tests that need external commands to exist and
|
|
285
|
+
respond successfully or with a controlled failure. Each mapping key is the logical
|
|
286
|
+
command name; any number of commands can be configured. Both container and VM nodes
|
|
287
|
+
use this workspace configuration.
|
|
288
|
+
|
|
289
|
+
```yaml
|
|
290
|
+
mocks:
|
|
291
|
+
commands:
|
|
292
|
+
testcmd:
|
|
293
|
+
path: /usr/local/bin/testcmd
|
|
294
|
+
mock_to: echo
|
|
295
|
+
exit_code: 0
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
Empeira creates an executable stub at `path`. Running
|
|
299
|
+
`/usr/local/bin/testcmd run example` prints `testcmd run example` and exits with zero.
|
|
300
|
+
The echo target prints the logical name followed by every argument in order,
|
|
301
|
+
without interpreting options, shell expressions or backslash escapes.
|
|
302
|
+
|
|
303
|
+
To forward to a test script already present on the node:
|
|
304
|
+
|
|
305
|
+
```yaml
|
|
306
|
+
mocks:
|
|
307
|
+
commands:
|
|
308
|
+
foo:
|
|
309
|
+
path: /usr/local/bin/foo
|
|
310
|
+
mock_to: /opt/test/mocks/foo.sh
|
|
311
|
+
exit_code: passthrough
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
The target receives the original argument vector unchanged, including empty
|
|
315
|
+
arguments and arguments containing spaces. Its stdout and stderr remain visible.
|
|
316
|
+
Empeira does not install the target script.
|
|
317
|
+
|
|
318
|
+
All three fields are required in the effective configuration:
|
|
319
|
+
|
|
320
|
+
| Field | Meaning |
|
|
321
|
+
| --- | --- |
|
|
322
|
+
| `path` | Safe absolute file destination on the node |
|
|
323
|
+
| `mock_to` | `echo` or a safe absolute executable path on the node |
|
|
324
|
+
| `exit_code` | Integer `0`–`255`, or the string `passthrough` |
|
|
325
|
+
|
|
326
|
+
**There is no default for `exit_code`.** A numeric value always overrides the
|
|
327
|
+
target's status, including failure to execute the target. `passthrough` returns
|
|
328
|
+
the target's actual exit status. Command names contain letters, digits, `_`, `.`
|
|
329
|
+
and `-`, beginning with a letter, digit or `_`.
|
|
330
|
+
|
|
331
|
+
The normal YAML parser, duplicate-key checks, schema and deep merge apply.
|
|
332
|
+
Named command mappings merge by key, and fields merge within each command.
|
|
333
|
+
Remove a command from the effective configuration to remove its managed stub;
|
|
334
|
+
with the built-in empty mapping, deleting its project entry is sufficient.
|
|
335
|
+
`null` is not a removal directive. Missing fields, unsupported keys, invalid
|
|
336
|
+
statuses, relative/traversing paths and overlapping managed destinations fail
|
|
337
|
+
validation.
|
|
338
|
+
|
|
339
|
+
Mocks reconcile during initial node provisioning, on `node start`, and on `up`
|
|
340
|
+
for running nodes. Repeated `node puppet` runs use the existing guest stubs.
|
|
341
|
+
Stopped nodes retain their files until the next start. Unchanged configuration
|
|
342
|
+
and files preserve file identity and timestamps. Changing a path removes the old
|
|
343
|
+
owned stub; changing `mock_to` or `exit_code` replaces only the affected stub.
|
|
344
|
+
Node/workspace destruction removes the node's storage and its mocks together.
|
|
345
|
+
|
|
346
|
+
While configured, the mock takes precedence at its exact `path`. Empeira
|
|
347
|
+
atomically replaces an existing regular file or symlink there and restores the
|
|
348
|
+
mock during the next reconciliation if another program overwrites it. The
|
|
349
|
+
original file is not retained. Parent directories must be real directories;
|
|
350
|
+
a directory at the target path is rejected. Removing a mock deletes only a
|
|
351
|
+
file that still matches its recorded content and ownership. Empeira does not
|
|
352
|
+
change packages, package databases, `PATH`, aliases or bind mounts, and the
|
|
353
|
+
mechanism does not simulate a cluster.
|
|
354
|
+
|
|
355
|
+
### Server images and runtime contract
|
|
356
|
+
|
|
357
|
+
An empty `.empeira.yaml` selects the OpenVox Server, OpenVoxDB and PostgreSQL
|
|
358
|
+
images from [the defaults](../config/defaults.yaml). Their OCI references are
|
|
359
|
+
independent. A project can replace any one without changing the agent:
|
|
360
|
+
|
|
361
|
+
```yaml
|
|
362
|
+
images:
|
|
363
|
+
server:
|
|
364
|
+
reference: registry.example.org/custom/server:1
|
|
365
|
+
puppetdb:
|
|
366
|
+
reference: registry.example.org/custom/puppetdb:1
|
|
367
|
+
postgres:
|
|
368
|
+
reference: registry.example.org/custom/postgres:1
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
Empeira does not identify or classify an image from its name. Docker or Podman
|
|
372
|
+
owns image authentication. The user supplies and licenses custom images and
|
|
373
|
+
must ensure that they implement the Puppet-compatible CA, server, catalog and
|
|
374
|
+
PuppetDB interfaces expected by Empeira. Empeira does not provide a complete
|
|
375
|
+
Puppet Enterprise simulation or bundle proprietary software.
|
|
376
|
+
|
|
377
|
+
`server.runtime` contains the internally managed OpenVox startup contract.
|
|
378
|
+
For another image, override only the fields that differ. `startup.entrypoint`
|
|
379
|
+
and `startup.arguments` select its normal foreground command, including when
|
|
380
|
+
PuppetDB and EYAML are disabled;
|
|
381
|
+
`startup.eyaml_keys` is `direct` or `staged`; `paths.puppetdb_config`
|
|
382
|
+
identifies the standard PuppetDB configuration file; `environment_keys` maps
|
|
383
|
+
semantic settings to environment variable names. For example:
|
|
384
|
+
|
|
385
|
+
```yaml
|
|
386
|
+
server:
|
|
387
|
+
runtime:
|
|
388
|
+
startup:
|
|
389
|
+
entrypoint: /opt/custom/start
|
|
390
|
+
arguments: [foreground]
|
|
391
|
+
paths:
|
|
392
|
+
puppetdb_config: /etc/puppetlabs/puppet/puppetdb.conf
|
|
393
|
+
environment_keys:
|
|
394
|
+
server_hostname: CUSTOM_SERVER_HOSTNAME
|
|
395
|
+
images:
|
|
396
|
+
server:
|
|
397
|
+
reference: registry.example.org/custom/server:1
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
The mapping deep-merges with OpenVox defaults. An alternative image using
|
|
401
|
+
other variable names must override each affected key. Empeira mounts standard
|
|
402
|
+
Puppet configuration, including `puppetdb.conf`, and supplies the configured
|
|
403
|
+
runtime values without inferring them from the image name. Missing or unsafe
|
|
404
|
+
runtime fields fail configuration validation. Managed servers use
|
|
405
|
+
`environment_timeout = 0` in the native `[server]` section. The startup wrapper
|
|
406
|
+
uses `puppet config set` before the configured entrypoint, independently of image
|
|
407
|
+
environment-variable mappings. Startup and `up` read Puppet's native server
|
|
408
|
+
settings without selecting an environment override, against the
|
|
409
|
+
confdir containing `server.runtime.paths.puppetdb_config`; custom Puppetserver
|
|
410
|
+
`jruby-puppet.master-conf-dir` must refer to that same directory. Puppetserver
|
|
411
|
+
HOCON master directories take precedence over Puppet CLI defaults. A changed
|
|
412
|
+
effective timeout updates only that key and restarts the same owned server; an
|
|
413
|
+
entrypoint that overwrites it fails verification. CA, SSL and database storage
|
|
414
|
+
are preserved. The next catalog request reloads live code without
|
|
415
|
+
an Empeira content scan or admin API invalidation. An explicit `environment.conf`
|
|
416
|
+
can override this server setting; keep its timeout at zero for immediate edits.
|
|
417
|
+
Such overrides are preserved and do not prevent server startup or cause repeated
|
|
418
|
+
restarts. `puppet config print environment_timeout --section server` includes the
|
|
419
|
+
selected environment's override, so it can report `unlimited` while the native
|
|
420
|
+
server setting is zero. Inspect both configuration layers when diagnosing caching.
|
|
421
|
+
|
|
422
|
+
`puppetdb.runtime` holds the independent OpenVoxDB process contract. Custom
|
|
423
|
+
images may override its executable, numeric user, Java and main arguments,
|
|
424
|
+
`paths.jar`, `paths.config`, `paths.bootstrap_config`, and `paths.data`.
|
|
425
|
+
`java_arguments` is the sole JVM argument source. Empeira mounts the generated database files into
|
|
426
|
+
`paths.config` and retains persistent data at `paths.data`. For example:
|
|
427
|
+
|
|
428
|
+
```yaml
|
|
429
|
+
puppetdb:
|
|
430
|
+
runtime:
|
|
431
|
+
entrypoint: /opt/custom/java
|
|
432
|
+
user: '1000'
|
|
433
|
+
paths:
|
|
434
|
+
jar: /opt/custom/puppetdb.jar
|
|
435
|
+
config: /opt/custom/conf
|
|
436
|
+
bootstrap_config: /opt/custom/bootstrap.cfg
|
|
437
|
+
data: /opt/custom/data
|
|
438
|
+
java_arguments: [-Xms128m, -Xmx512m]
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
The custom image must accept the configured JVM and PuppetDB CLI arguments.
|
|
442
|
+
|
|
443
|
+
`--container-engine podman|docker` may override `runtime.container_engine` on
|
|
444
|
+
configuration, infrastructure, and node commands. `node run` additionally accepts `--os`,
|
|
445
|
+
`--version`, `--memory`, and `--cpus`. Omitted flags preserve project settings.
|
|
446
|
+
|
|
447
|
+
```console
|
|
448
|
+
cd ../control-repo
|
|
449
|
+
empeira config show --container-engine docker
|
|
450
|
+
empeira config validate
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
Validation failures exit with status 1 and identify the complete path, for example
|
|
454
|
+
`node_defaults.memory must be a positive integer`. Configuration display applies
|
|
455
|
+
recursive redaction to sensitive key names. `vm.console.root_password` and sensitive EYAML paths are redacted.
|
|
456
|
+
Never commit real passwords or private keys into a control repository.
|
|
457
|
+
|
|
458
|
+
### Project Empeira requirements
|
|
459
|
+
|
|
460
|
+
`requirements.empeira` accepts a RubyGems requirement such as `">= 0.4.0, < 1.0"`.
|
|
461
|
+
The default is `null`, meaning no application version restriction.
|
|
462
|
+
Invalid expressions fail validation at `requirements.empeira`.
|
|
463
|
+
|
|
464
|
+
Before `up`, `down` or `destroy` takes a lock or mutates infrastructure/state, the central
|
|
465
|
+
build abstraction verifies this requirement. Incompatible releases fail with the
|
|
466
|
+
required and installed versions and the `empeira self-update` command. Self-update
|
|
467
|
+
itself is not implemented yet, so install a compatible build through your existing
|
|
468
|
+
installation method. Infrastructure operations never update Empeira automatically.
|
|
469
|
+
`--version`, `config show`, `config validate`, and `status` remain usable on mismatch.
|
|
470
|
+
If project or user configuration cannot be loaded, `destroy` uses built-in defaults
|
|
471
|
+
and the validated workspace inventory for recovery. An unreadable requirement cannot
|
|
472
|
+
be enforced in that case. Other infrastructure commands continue to reject invalid
|
|
473
|
+
configuration.
|
|
474
|
+
|
|
475
|
+
A `development` build has no verifiable release version. It can operate when
|
|
476
|
+
`requirements.empeira` is absent or null. An explicit requirement fails closed as
|
|
477
|
+
unverifiable. Use a compatible release build for a version-constrained project,
|
|
478
|
+
or a dedicated local development control repository without a release requirement.
|
|
479
|
+
The numeric gem packaging fallback is never used to bypass this check.
|
|
480
|
+
|
|
481
|
+
## Policy and mounts
|
|
482
|
+
|
|
483
|
+
```yaml
|
|
484
|
+
network:
|
|
485
|
+
egress:
|
|
486
|
+
- host: api.example.com
|
|
487
|
+
ports: [443]
|
|
488
|
+
proxy:
|
|
489
|
+
enabled: true
|
|
490
|
+
global: [forgeapi.puppet.com]
|
|
491
|
+
rules:
|
|
492
|
+
- hosts: ["*-web-*"]
|
|
493
|
+
allow: [github.com, "*.github.com"]
|
|
494
|
+
hiera:
|
|
495
|
+
mounts:
|
|
496
|
+
- source: ../hieradata
|
|
497
|
+
type: module
|
|
498
|
+
name: hieradata
|
|
499
|
+
vm:
|
|
500
|
+
disk: 30
|
|
501
|
+
console:
|
|
502
|
+
root_password: null
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
When `proxy.enabled` is true, every node may use its matching destination policy.
|
|
506
|
+
After bootstrap cleanup, Empeira reconciles normal proxy settings on running,
|
|
507
|
+
provisioned nodes during `up` and `node start`. Repeated Puppet runs use the
|
|
508
|
+
existing guest configuration. No
|
|
509
|
+
node recreation or restart is needed to apply allowlist changes. Disabling the
|
|
510
|
+
proxy removes owned package-manager settings. The owned login environment clears
|
|
511
|
+
stale creation-time container variables; it never retains bootstrap credentials.
|
|
512
|
+
See [proxy policy](proxy.md),
|
|
513
|
+
[Hiera and EYAML](hiera-and-eyaml.md), [DNS](networking.md), and [console recovery](nodes.md#vm-console-recovery).
|
|
514
|
+
Mounts are optional unless `required: true`. The console password is used only on
|
|
515
|
+
initial VM creation. Changing it does not reset an existing node.
|
|
516
|
+
`vm.disk` applies only when creating a VM. Existing disks keep their capacity across
|
|
517
|
+
`up` and `node start`; changing the setting does not resize or migrate them.
|
|
518
|
+
|
|
519
|
+
VM management uses private VirtIO-Serial with numeric root execution; it does not
|
|
520
|
+
use personal SSH settings, root login or sudo. `node ssh` reaches the regular
|
|
521
|
+
system SSH daemon through the owned peer attachment, with default guest port 22.
|
|
522
|
+
The selected cloud image must include Python 3 before package bootstrap. There is
|
|
523
|
+
no transport selector or additional management YAML configuration. See
|
|
524
|
+
[VM access and recovery](nodes.md#shell-and-ssh).
|
|
525
|
+
|
|
526
|
+
## Images and bootstrap
|
|
527
|
+
|
|
528
|
+
`images.nodes` selects container recipes and base images. VM image sources currently
|
|
529
|
+
resolve reviewed Ubuntu/Rocky upstream URLs in the image-source adapter; they are
|
|
530
|
+
not configurable through an `images.vm` namespace. A custom adapter can be injected
|
|
531
|
+
at the provider boundary. `bootstrap.guests` records whether an agent is preinstalled
|
|
532
|
+
and the reviewed destination domains that the temporary bootstrap proxy may reach.
|
|
533
|
+
Rocky metadata also supplies the stable `baseurl` needed to avoid arbitrary mirror
|
|
534
|
+
selection. Ubuntu and Debian package source URLs come exclusively from the base
|
|
535
|
+
image. For the reviewed Ubuntu images, amd64 permits archive/security domains and arm64
|
|
536
|
+
permits the ports domain. Do not mark stock cloud images as agent-preinstalled.
|
|
537
|
+
See [node images](nodes.md#node-images-and-fidelity) for fidelity and licensing.
|
|
538
|
+
|
|
539
|
+
### Agent sources and shared package cache
|
|
540
|
+
|
|
541
|
+
With an empty project marker, the pinned OpenVox release packages, agent version,
|
|
542
|
+
server and database images remain the defaults. Release packages configure the
|
|
543
|
+
signed source inside a disposable host-side helper, never on the test node.
|
|
544
|
+
The helper uses the selected runtime's default bridge and target OS image; APT/DNF
|
|
545
|
+
need not be installed on the host. No agent is installed on the host or helper.
|
|
546
|
+
|
|
547
|
+
A generic source can serve all supported releases of its package-manager family:
|
|
548
|
+
|
|
549
|
+
```yaml
|
|
550
|
+
agent:
|
|
551
|
+
package: puppet-agent
|
|
552
|
+
version: "8.20.0"
|
|
553
|
+
cache:
|
|
554
|
+
enabled: true
|
|
555
|
+
install:
|
|
556
|
+
method: repository
|
|
557
|
+
apt:
|
|
558
|
+
default:
|
|
559
|
+
url: https://packages.example.org/apt
|
|
560
|
+
component: main
|
|
561
|
+
ubuntu24.04:
|
|
562
|
+
suite: noble-special
|
|
563
|
+
dnf:
|
|
564
|
+
default:
|
|
565
|
+
url: https://packages.example.org/yum/$releasever/$basearch
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
Configure only the manager you use. A project `apt.default` or `dnf.default`
|
|
569
|
+
supersedes the built-in release sources for that family. OS-specific entries
|
|
570
|
+
merge over the generic default; existing complete source definitions and `suffix`
|
|
571
|
+
overrides remain supported. APT suites default to `jammy` for Ubuntu 22.04 and
|
|
572
|
+
`noble` for Ubuntu 24.04. RPM keys remain `el8`/`el9` for Rocky, AlmaLinux and
|
|
573
|
+
Oracle Linux's existing supported releases. Architecture comes from the target
|
|
574
|
+
node: `amd64`/`arm64` for DEB and `x86_64`/`aarch64` for RPM. Only `$suite`,
|
|
575
|
+
`$releasever` and `$basearch` URL placeholders are expanded; arbitrary environment
|
|
576
|
+
interpolation is rejected.
|
|
577
|
+
|
|
578
|
+
Native source metadata resolves the exact software version to a complete native
|
|
579
|
+
version. No newest-version fallback is used, and ambiguous releases require an
|
|
580
|
+
explicit native version or `suffix`. Resolution excludes unrelated repositories.
|
|
581
|
+
The downloaded package's name, version and architecture must match the target.
|
|
582
|
+
|
|
583
|
+
Direct HTTPS artifacts use the same acquisition and installation path:
|
|
584
|
+
|
|
585
|
+
```yaml
|
|
586
|
+
agent:
|
|
587
|
+
package: puppet-agent
|
|
588
|
+
version: "8.20.0"
|
|
589
|
+
install:
|
|
590
|
+
method: package
|
|
591
|
+
packages:
|
|
592
|
+
ubuntu24.04:
|
|
593
|
+
amd64:
|
|
594
|
+
url: https://packages.example.org/puppet-agent.deb
|
|
595
|
+
# Optional; if present, the pin is mandatory on downloads and cache hits.
|
|
596
|
+
sha256: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
Direct files remain explicit by distribution and architecture; Empeira does not
|
|
600
|
+
invent download URLs. A software version is accepted when package metadata
|
|
601
|
+
matches it exactly; a complete native version pins the release as well.
|
|
602
|
+
|
|
603
|
+
`sha256` is optional for custom release/key artifacts and direct packages.
|
|
604
|
+
Built-in OpenVox release checksums remain pinned. A configured pin is always
|
|
605
|
+
verified. Changing a source or key URL clears its inherited checksum unless
|
|
606
|
+
the override supplies a new pin. Signed APT metadata supplies package checksums;
|
|
607
|
+
RPM signatures are checked natively. Local DEBs have no repository signature chain: HTTPS and an
|
|
608
|
+
optional independent checksum pin are their verification mechanisms.
|
|
609
|
+
The cache's calculated checksum detects corruption, not publisher provenance.
|
|
610
|
+
|
|
611
|
+
Native signature checks stay enabled. Existing trusted keys may be used; an
|
|
612
|
+
optional `key: {url: https://..., sha256: ...}` supplies an additional public key.
|
|
613
|
+
An APT source can also retain its existing `release` artifact. Set
|
|
614
|
+
`verify_signatures: false` on an APT/DNF source or direct package only when you
|
|
615
|
+
intend to use an unsigned source. The exception is scoped to that source or local
|
|
616
|
+
RPM; base-source signature checks and HTTPS verification remain active. Temporarily
|
|
617
|
+
imported RPM keys are removed after installation without removing preexisting keys.
|
|
618
|
+
|
|
619
|
+
Packages are shared across workspaces under the current user's cache:
|
|
620
|
+
|
|
621
|
+
| Host | Agent cache |
|
|
622
|
+
| --- | --- |
|
|
623
|
+
| Linux / WSL2 | `$XDG_CACHE_HOME/empeira/agents` or `~/.cache/empeira/agents` |
|
|
624
|
+
| macOS | `~/Library/Caches/empeira/agents` |
|
|
625
|
+
|
|
626
|
+
Only packages and necessary nonsecret metadata, including public signing keys,
|
|
627
|
+
are retained. Identity includes package name, full native version, OS family,
|
|
628
|
+
distribution/release, target architecture, format and source/verification policy.
|
|
629
|
+
Private directories, per-request filesystem locks, temporary downloads and atomic
|
|
630
|
+
publication protect concurrent callers. Hits validate local metadata, package hashes
|
|
631
|
+
and any configured package SHA-256 pin. A valid hit is fully usable offline, including
|
|
632
|
+
packages acquired from private APT/DNF repositories or direct authenticated HTTPS
|
|
633
|
+
downloads: no HTTP request, credential validation or login is needed for reuse.
|
|
634
|
+
Damaged owned entries are reacquired. Foreign, symlinked or insecure entries fail
|
|
635
|
+
closed. `agent.cache.enabled: false` bypasses the persistent cache entirely, uses
|
|
636
|
+
temporary host storage with the same acquisition path, removes it after use and
|
|
637
|
+
leaves existing cache entries intact. There is no cache-cleanup command.
|
|
638
|
+
|
|
639
|
+
HTTP authentication occurs only when acquisition is necessary, such as a cache miss,
|
|
640
|
+
a damaged artifact or disabled caching. It uses `EMPEIRA_AGENT_REPO_USERNAME` and
|
|
641
|
+
`EMPEIRA_AGENT_REPO_PASSWORD` when both are set. Invalid explicit credentials fail
|
|
642
|
+
without an interactive fallback. Otherwise an HTTP 401 can prompt in a TTY:
|
|
643
|
+
confirm login, enter the username and enter the password without echo. Progress
|
|
644
|
+
is suspended during the prompt. There is one retry; cancellation or another
|
|
645
|
+
failure stops provisioning. Without a TTY, the error names the two environment
|
|
646
|
+
variables for CI. HTTP 403 and proxy HTTP 407 do not trigger repository login.
|
|
647
|
+
ENV credentials take precedence. A rejected interactive login is identified as
|
|
648
|
+
such and includes the last HTTP diagnosis. During acquisition, the login is reused
|
|
649
|
+
for related metadata, signing-key and package requests to the same HTTPS origin
|
|
650
|
+
(case-insensitive hostname and matching port). Credentials are not forwarded to
|
|
651
|
+
other origins; a 401 there names the failing URL rather than asking for the source's
|
|
652
|
+
login again.
|
|
653
|
+
|
|
654
|
+
Credentials stay in memory or temporary 0600 helper files, never in YAML, cache
|
|
655
|
+
keys, cache metadata, workspace inventory or process arguments. Host downloads
|
|
656
|
+
do not follow redirects, and credentials are scoped to the source HTTPS origin.
|
|
657
|
+
Registry authentication continues to use native `docker login` / `podman login`.
|
|
658
|
+
|
|
659
|
+
After configured bootstrap packages are handled using the guest's base sources,
|
|
660
|
+
the host artifact is uploaded through existing container/VM file transport and
|
|
661
|
+
installed locally by APT/DNF. The agent repository is not added to the node.
|
|
662
|
+
Dependencies can still require the unchanged guest base repositories and existing
|
|
663
|
+
bootstrap-proxy grants: this is an agent-artifact cache, not an offline package
|
|
664
|
+
mirror. No additional node egress is granted. Dependency failure blocks the first
|
|
665
|
+
catalog. Uploaded artifacts, temporary keys and proxy files are removed, and the
|
|
666
|
+
original package-manager configuration is restored and verified before bootstrap
|
|
667
|
+
access is removed, enrollment completes and Puppet runs. Unverifiable cleanup
|
|
668
|
+
leaves the node incomplete for diagnostics.
|
|
669
|
+
|
|
670
|
+
APT loads the private proxy file explicitly after the guest's normal configuration
|
|
671
|
+
so existing proxy fragments cannot override the controlled bootstrap endpoint.
|
|
672
|
+
Credentials are redacted before diagnostic truncation, including native errors
|
|
673
|
+
that print a raw credential rather than a URL.
|
|
674
|
+
|
|
675
|
+
`bootstrap.enabled: true` runs `bootstrap.scripts` once during VM cloud-init.
|
|
676
|
+
Scripts must be project-local UTF-8 files below 1 MB, including after symlink
|
|
677
|
+
resolution. This does not control the built-in agent installation, which works
|
|
678
|
+
without project bootstrap scripts or normal Internet access. Remote project
|
|
679
|
+
scripts are not implemented. Keep secrets out of bootstrap scripts.
|
|
680
|
+
|
|
681
|
+
`bootstrap.packages` is a separate, provider-independent package bootstrap for a
|
|
682
|
+
new node instance. Empeira concatenates `default` with the detected distribution
|
|
683
|
+
family for each action. Ubuntu and Debian select `debian`; RHEL, Rocky Linux,
|
|
684
|
+
AlmaLinux and Oracle Linux select `redhat`. Package names remain literal YAML values;
|
|
685
|
+
Empeira has no package-name translation table. The native manager removes packages
|
|
686
|
+
first, then refreshes package metadata when installation is needed, then installs.
|
|
687
|
+
APT is used for the Debian family and DNF for the Red Hat family.
|
|
688
|
+
|
|
689
|
+
```yaml
|
|
690
|
+
bootstrap:
|
|
691
|
+
packages:
|
|
692
|
+
install:
|
|
693
|
+
default: [git, curl]
|
|
694
|
+
debian: [libxml2-dev]
|
|
695
|
+
redhat: [libxml2-devel]
|
|
696
|
+
remove:
|
|
697
|
+
default: [telnet]
|
|
698
|
+
```
|
|
699
|
+
|
|
700
|
+
The operation uses the temporary authenticated bootstrap proxy and reviewed active
|
|
701
|
+
agent and distribution package destinations. For Ubuntu and Debian VMs, Empeira
|
|
702
|
+
archives the complete `/etc/apt` tree before package and agent bootstrap, then
|
|
703
|
+
restores that tree and verifies the
|
|
704
|
+
restored archive before removing bootstrap access. The read-only active-source check
|
|
705
|
+
then runs against the restored configuration before certificate enrollment and the
|
|
706
|
+
first Puppet catalog. Empty lists cause no package-manager call.
|
|
707
|
+
A failed remove, metadata refresh or install retains the node and prevents Puppet.
|
|
708
|
+
Empeira also verifies that its required agent executable and Ruby remain available
|
|
709
|
+
after these package operations. Choose the agent through `agent.install`; do not install a replacement agent through
|
|
710
|
+
`bootstrap.packages`.
|
|
711
|
+
Stop/start, later Puppet runs and repeated `up` do not repeat it. Destroying and
|
|
712
|
+
creating a new node instance runs it again. This is initial preparation, not Puppet
|
|
713
|
+
desired state; Puppet owns package state after the first catalog.
|
|
714
|
+
|
|
715
|
+
## Direct egress
|
|
716
|
+
|
|
717
|
+
`network.egress` contains destination TCP grants, independent of HTTP/HTTPS proxy
|
|
718
|
+
policy. Entries have exactly one `host` or IPv4 `ip` and a nonempty unique `ports`
|
|
719
|
+
array (1–65535). `up` resolves all A records and replaces the complete policy;
|
|
720
|
+
resolution/apply failure blocks egress. IPv6 and external UDP grants are unsupported.
|
|
721
|
+
|
|
722
|
+
```yaml
|
|
723
|
+
network:
|
|
724
|
+
egress:
|
|
725
|
+
- host: repository.example.net
|
|
726
|
+
ports: [443]
|
|
727
|
+
- ip: 203.0.113.10
|
|
728
|
+
ports: [443, 8443]
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
Named direct destinations enter generated `NO_PROXY`; applications choose DIRECT
|
|
732
|
+
or proxy themselves. See [networking](networking.md#one-gateway-one-direct-egress-policy)
|
|
733
|
+
for routing, revocation and privilege boundaries.
|
|
734
|
+
|
|
735
|
+
## Additional VM interfaces
|
|
736
|
+
|
|
737
|
+
`vm.interfaces` supplies real Linux devices for ordinary Facter and Puppet network
|
|
738
|
+
lookups. Container nodes ignore these rules. Arrays replace earlier arrays through
|
|
739
|
+
the normal configuration merge; there is no automatic address assignment. Configure
|
|
740
|
+
`vm.disk` independently in the same mapping; growth is verified before package
|
|
741
|
+
bootstrap and interface creation on new VMs.
|
|
742
|
+
|
|
743
|
+
```yaml
|
|
744
|
+
vm:
|
|
745
|
+
disk: 32
|
|
746
|
+
interfaces:
|
|
747
|
+
- hosts: ["web-*.example.test", "app-*"]
|
|
748
|
+
devices:
|
|
749
|
+
ens192:
|
|
750
|
+
network: 192.0.2.10/32
|
|
751
|
+
vlan_id: 123
|
|
752
|
+
ens224:
|
|
753
|
+
network: 198.51.100.10/24
|
|
754
|
+
vlan_id: 456
|
|
755
|
+
dummy0:
|
|
756
|
+
network: 203.0.113.10/32
|
|
757
|
+
- hosts: ["db-*"]
|
|
758
|
+
devices:
|
|
759
|
+
ens192:
|
|
760
|
+
network: 192.0.2.20/32
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
Patterns use the same `*`/`?` glob matcher as `proxy.rules`, against the full stored
|
|
764
|
+
node hostname, case-insensitively. Patterns within a rule are alternatives. All
|
|
765
|
+
matching rules contribute devices; identical definitions merge once. A conflicting
|
|
766
|
+
definition names the hostname, device and both configuration paths. No match creates
|
|
767
|
+
no devices. A short pattern does not implicitly match a fully qualified hostname.
|
|
768
|
+
|
|
769
|
+
Each device requires `network`: a canonical IPv4 **host** address with a CIDR
|
|
770
|
+
prefix from 0 through 32, subject to the unicast/routing checks below. `vlan_id` is
|
|
771
|
+
optional, and must be an integer from 1 through 4094. Without it, Empeira creates a
|
|
772
|
+
Linux dummy device. With it, Empeira creates an 802.1Q VLAN over its private dummy
|
|
773
|
+
parent `empeira-vlan`. Each VLAN ID may occur only once on this shared parent.
|
|
774
|
+
The parent has no IP addresses or external attachment. These are real VLAN devices,
|
|
775
|
+
but they do not simulate a connected production VLAN segment or transmit packets
|
|
776
|
+
to other nodes. No QEMU NIC, DHCP, bridge, forwarding, gateway grant or proxy rule
|
|
777
|
+
is added.
|
|
778
|
+
|
|
779
|
+
Device names use 1–15 ASCII letters, digits, underscores, dots or hyphens, beginning
|
|
780
|
+
with a letter or digit. `lo`, `eth0`, `peer` and `empeira-vlan`
|
|
781
|
+
are reserved. Unknown keys, IPv6, duplicate addresses/VLAN IDs and overlapping
|
|
782
|
+
device networks are rejected. Network/broadcast addresses within prefixes below
|
|
783
|
+
/31 are rejected, as are subnets overlapping unspecified, loopback, link-local,
|
|
784
|
+
shared-address, protocol-assignment, deprecated relay, multicast or reserved ranges.
|
|
785
|
+
Private and RFC documentation addresses are permitted. `/31` endpoints and `/32`
|
|
786
|
+
hosts are permitted; separate `prefix`/`netmask` keys are unsupported.
|
|
787
|
+
|
|
788
|
+
Prefer `/32` for Facter tests. Other prefixes create connected routes, so Empeira
|
|
789
|
+
checks all guest IPv4 routing tables and existing interface addresses first. The
|
|
790
|
+
workspace subnet and `network.redirects` source addresses
|
|
791
|
+
are protected even if their routes are absent. Overlap is refused, including a /32
|
|
792
|
+
inside an existing connected network. Automatically generated routes of owned test
|
|
793
|
+
devices are recognized during reconciliation; manually added routes on those devices
|
|
794
|
+
block mutation. Default routes are compared after reconciliation and never edited.
|
|
795
|
+
|
|
796
|
+
The guest requires JSON-capable `iproute2`, `modprobe` when modules are not already
|
|
797
|
+
loaded, and kernel `dummy`/`8021q` support. Empeira loads an absent dummy module with
|
|
798
|
+
`numdummies=0` to avoid creating an unowned default `dummy0`. An already existing
|
|
799
|
+
device, including a kernel-created `dummy0`, is a collision and is never adopted.
|
|
800
|
+
Failures preserve the VM and report native guest diagnostics.
|
|
801
|
+
|
|
802
|
+
See [VM interface lifecycle](nodes.md#additional-vm-interface-lifecycle) for updates,
|
|
803
|
+
ownership, recovery and the regular Facter structure.
|
|
804
|
+
|
|
805
|
+
## Transparent TCP redirects
|
|
806
|
+
|
|
807
|
+
Use `network.redirects` to exercise production Puppet/Hiera endpoints against a
|
|
808
|
+
local service while preserving the original IP and port. For example, a PowerDNS
|
|
809
|
+
API compatibility service can receive these two endpoints:
|
|
810
|
+
|
|
811
|
+
```yaml
|
|
812
|
+
network:
|
|
813
|
+
redirects:
|
|
814
|
+
- from:
|
|
815
|
+
ip: 192.0.2.8
|
|
816
|
+
port: 8080
|
|
817
|
+
to:
|
|
818
|
+
service: api-compat
|
|
819
|
+
port: 8081
|
|
820
|
+
- from:
|
|
821
|
+
ip: 192.0.2.9
|
|
822
|
+
port: 8080
|
|
823
|
+
to:
|
|
824
|
+
service: api-compat
|
|
825
|
+
port: 8081
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
Define `api-compat` under `containers.additional` using your test service image.
|
|
829
|
+
The example IPs are documentation addresses; substitute the endpoints used by your
|
|
830
|
+
Puppet code. `from` accepts `ip`, `port` and optional `protocol` (`tcp` by default).
|
|
831
|
+
`to` accepts only `service` and `port`. Both ports are integers from 1 through 65535.
|
|
832
|
+
Sources must be exact
|
|
833
|
+
routable unicast IPv4 addresses outside the allocated workspace subnet. CIDRs,
|
|
834
|
+
wildcards, duplicate IP/protocol/port tuples, IPv6 and external target addresses are
|
|
835
|
+
rejected. Omitting `protocol` and specifying `tcp` describe the same source.
|
|
836
|
+
Service names are lowercase internal names, without `.empeira.internal`.
|
|
837
|
+
Enabled control-plane application services and additional services are supported;
|
|
838
|
+
nodes, the gateway, the browser UI relay and temporary bootstrap helpers are excluded.
|
|
839
|
+
`coredns` is an alias for the built-in `dns` service and is reserved against additional
|
|
840
|
+
service names.
|
|
841
|
+
|
|
842
|
+
Run `empeira up` after edits. It resolves owned service addresses, replaces gateway
|
|
843
|
+
policy and preserves existing nodes and the workspace network. Unknown/disabled
|
|
844
|
+
targets fail validation. Temporarily absent targets stay blocked until the owned
|
|
845
|
+
service is reconciled; unreachable target ports fail without contacting the external
|
|
846
|
+
endpoint, even when that endpoint also has an explicit egress grant.
|
|
847
|
+
|
|
848
|
+
Direct connections work from container/VM nodes, the Puppet server (including
|
|
849
|
+
catalog compilation) and internal services. HTTP methods, paths, headers and bodies
|
|
850
|
+
are unchanged. No DNS rewrite, egress grant, proxy exception or TLS termination is
|
|
851
|
+
created. Explicit proxy users connect to the proxy first and remain subject to its
|
|
852
|
+
allowlist; use the application's direct-connection settings when testing redirects,
|
|
853
|
+
for example `curl --noproxy '*' http://192.0.2.8:8080/test`.
|
|
854
|
+
See [redirect routing](networking.md#transparent-tcp-redirects) for connection
|
|
855
|
+
revocation and runtime boundaries.
|
|
856
|
+
|
|
857
|
+
### Virtual DNS endpoint
|
|
858
|
+
|
|
859
|
+
UDP is supported specifically for DNS: source and target port 53, targeting the
|
|
860
|
+
built-in `coredns` (or `dns`) service. Configure both transports for large responses
|
|
861
|
+
and TCP fallback:
|
|
862
|
+
|
|
863
|
+
```yaml
|
|
864
|
+
network:
|
|
865
|
+
redirects:
|
|
866
|
+
- from: {ip: 198.18.0.53, port: 53, protocol: udp}
|
|
867
|
+
to: {service: coredns, port: 53}
|
|
868
|
+
- from: {ip: 198.18.0.53, port: 53, protocol: tcp}
|
|
869
|
+
to: {service: coredns, port: 53}
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
Use `198.18.0.53` in ordinary Puppet/Hiera DNS test data. It is a virtual destination,
|
|
873
|
+
never assigned to an interface. CoreDNS keeps its dynamic workspace address and
|
|
874
|
+
forwards external names to the configured `dns.upstream`; internal names remain
|
|
875
|
+
authoritative. Redirects do not edit `/etc/resolv.conf`, create another DNS service
|
|
876
|
+
or grant external UDP access. NXDOMAIN and TCP fallback retain normal DNS semantics.
|
|
877
|
+
The benchmark range `198.18.0.0/15` is accepted only for validated redirect sources,
|
|
878
|
+
never direct-egress grants. Before mutation, `up` rejects source collisions with
|
|
879
|
+
host/VPN routes, engine networks and the workspace subnet. A default route alone
|
|
880
|
+
is not a collision. Legacy TCP source destinations retain their existing semantics.
|
|
881
|
+
|
|
882
|
+
## Control-plane images and provenance
|
|
883
|
+
|
|
884
|
+
[Built-in YAML defaults](../config/defaults.yaml) are the sole authoritative source
|
|
885
|
+
for default image repositories, software tags, immutable digests, agent versions
|
|
886
|
+
and release-package checksums. The server, database and PostgreSQL defaults use OCI
|
|
887
|
+
index digests covering both `linux/amd64` and `linux/arm64`. The runtime executes
|
|
888
|
+
`repository@sha256:...`; the accompanying tag describes the selected software.
|
|
889
|
+
Project configuration may independently replace each image. For example:
|
|
890
|
+
|
|
891
|
+
```yaml
|
|
892
|
+
images:
|
|
893
|
+
server:
|
|
894
|
+
reference: registry.example.org/custom/server:1
|
|
895
|
+
puppetdb:
|
|
896
|
+
repository: registry.example.org/custom/puppetdb
|
|
897
|
+
tag: "1"
|
|
898
|
+
```
|
|
899
|
+
|
|
900
|
+
Server, PuppetDB and PostgreSQL images are independent. Image descriptors accept
|
|
901
|
+
`repository` plus `tag`, an optional `digest: sha256:...`, or a complete
|
|
902
|
+
`reference`. An explicit repository or tag clears an inherited default digest
|
|
903
|
+
unless the override also supplies a digest. A full reference replaces inherited
|
|
904
|
+
descriptor fields; combining it with repository, tag, digest or build in the same
|
|
905
|
+
configuration source is rejected. An explicitly supplied digest determines the
|
|
906
|
+
revision even if a descriptive tag is also supplied. Custom images need not be
|
|
907
|
+
digest-pinned. Validation is local and does not contact registries.
|
|
908
|
+
Compatibility of project-selected software is the project's responsibility.
|
|
909
|
+
|
|
910
|
+
OCI digests identify exact manifest/index bytes; descriptive tags identify software
|
|
911
|
+
releases. Default pin changes require verification of official registry indexes and
|
|
912
|
+
both platform manifests. Digest integrity does not establish publisher signatures.
|
|
913
|
+
Empeira does not promise verified signatures or attestations for its selected images.
|
|
914
|
+
|
|
915
|
+
The proxy is built locally from [resources/proxy/Containerfile](../resources/proxy/Containerfile).
|
|
916
|
+
Its reviewed base, Squid package version and Ubuntu snapshot are recorded in that recipe.
|
|
917
|
+
A signed current-archive package install bootstraps public CA trust, so the entire
|
|
918
|
+
build dependency closure is not byte-for-byte pinned. Recipe contents determine the
|
|
919
|
+
local image tag and verification label. Builds send only the generated Containerfile,
|
|
920
|
+
never control code or credentials. Changed recipes create new local image identities.
|
|
921
|
+
Existing tagged images are reused without automatic refresh. Package/image acquisition
|
|
922
|
+
uses engine networking during the build; running nodes remain isolated.
|
|
923
|
+
|
|
924
|
+
| Component | Selected version | Authoritative source / license |
|
|
925
|
+
| --- | --- | --- |
|
|
926
|
+
| OpenVox server | Default software tag and index digest | [OpenVoxProject](https://github.com/OpenVoxProject/container-openvoxserver), AGPL-3.0 container recipes |
|
|
927
|
+
| OpenVoxDB | Default software tag and index digest | [OpenVoxProject](https://github.com/OpenVoxProject/container-openvoxdb), AGPL-3.0 container recipes |
|
|
928
|
+
| PostgreSQL | Independent default software tag and index digest | [Docker Official Image](https://github.com/docker-library/postgres), MIT recipes and [PostgreSQL license](https://www.postgresql.org/about/licence/) |
|
|
929
|
+
| CoreDNS | Default software tag | [CoreDNS](https://github.com/coredns/coredns), Apache-2.0 |
|
|
930
|
+
| Squid | Reviewed package and snapshot in the local recipe | [Ubuntu snapshot service](https://snapshot.ubuntu.com/), Squid GPL-2.0-or-later and distribution package licenses |
|
|
931
|
+
|
|
932
|
+
Third-party image
|
|
933
|
+
contents retain their own licenses and notices. Empeira references and pulls these
|
|
934
|
+
public images and locally builds the proxy, but does not bundle or redistribute image contents. No Puppet Enterprise
|
|
935
|
+
artifact is used. Selecting a version is not a claim that an image has
|
|
936
|
+
no vulnerabilities; image refreshes need renewed upstream/security review.
|
|
937
|
+
Review [CoreDNS advisories](https://github.com/coredns/coredns/security/advisories)
|
|
938
|
+
and distribution security updates when selecting new artifacts. Locally built
|
|
939
|
+
helpers preserve rootless-compatible UID mappings and upstream notices.
|
|
940
|
+
|
|
941
|
+
The default control plane has six containers, or seven with the proxy, plus the
|
|
942
|
+
runtime's peer-network adapter. Requested limits
|
|
943
|
+
are 1536 MiB for the server (768 MiB JVM heap), 768 MiB for PuppetDB (256 MiB heap),
|
|
944
|
+
256 MiB for PostgreSQL, 64 MiB for DNS, 96 MiB for the database relay, 64 MiB
|
|
945
|
+
for the gateway and 128 MiB for Squid. The control-plane memory ceiling is about
|
|
946
|
+
2.7 GiB without the proxy, excluding the peer adapter and nodes. The server gets two CPUs and each
|
|
947
|
+
other service one. Actual idle use is lower and varies by provider and platform.
|
|
948
|
+
`up` automatically pulls missing remote images and builds missing recipe images.
|
|
949
|
+
Existing images are reused without any remote freshness check. Use `update images`
|
|
950
|
+
to explicitly check remote metadata and retrieve changed artifacts. A pinned image
|
|
951
|
+
is checked and acquired by its exact digest; updates never follow its descriptive
|
|
952
|
+
tag to a different build. Unchanged pins cause no pull. Changing an image reference
|
|
953
|
+
or digest changes its managed component fingerprint for selective reconciliation
|
|
954
|
+
on the next `up`. PostgreSQL version changes remain explicit; no database migration
|
|
955
|
+
is performed. No service is exposed on a host
|
|
956
|
+
port by default.
|
|
957
|
+
|
|
958
|
+
## Default image registry
|
|
959
|
+
|
|
960
|
+
```yaml
|
|
961
|
+
images:
|
|
962
|
+
registry: null # explicit docker.io for hostless repositories
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
To use a Docker Hub cache, set `images.registry: registry.example.net`
|
|
966
|
+
(or `registry.example.net:5000`). This optional value is a registry host,
|
|
967
|
+
with no scheme, path or credentials. Use an unambiguous host containing a dot,
|
|
968
|
+
`localhost`, or a host with a port. Repository paths remain unchanged:
|
|
969
|
+
|
|
970
|
+
| Repository | With `images.registry: registry.example.net` |
|
|
971
|
+
| --- | --- |
|
|
972
|
+
| `library/postgres` | `registry.example.net/library/postgres` |
|
|
973
|
+
| `linuxserver/chromium` | `registry.example.net/linuxserver/chromium` |
|
|
974
|
+
| `registry.example.org/team/server` | `registry.example.org/team/server` |
|
|
975
|
+
| `docker.io/library/postgres` | `docker.io/library/postgres` |
|
|
976
|
+
|
|
977
|
+
Without an override, hostless repositories explicitly resolve through `docker.io`;
|
|
978
|
+
Empeira never relies on runtime short-name search rules. A first path segment
|
|
979
|
+
containing `.` or `:`, or equal to `localhost`, is an explicit registry and stays
|
|
980
|
+
unchanged. Exact `reference` overrides also stay unchanged, including digest pins.
|
|
981
|
+
Tags and digest fields still work normally.
|
|
982
|
+
|
|
983
|
+
Docker Hub defaults for PostgreSQL, CoreDNS, Ubuntu, RockyLinux, AlmaLinux,
|
|
984
|
+
OracleLinux, the Go builder and Chromium are hostless. Explicit OpenVox, OpenVoxDB,
|
|
985
|
+
OpenVox View GHCR repositories remain direct. Reviewed Ruby/Ubuntu
|
|
986
|
+
build bases use the same resolver; resolved bases enter the recipe hash, so a
|
|
987
|
+
registry change gives those local images a new identity. Build dependencies are
|
|
988
|
+
explicit reserved `EMPEIRA_BASE_*` arguments, not arbitrary Dockerfile rewriting.
|
|
989
|
+
|
|
990
|
+
Docker/Podman supply their normal login, credential-helper and auth-file behavior
|
|
991
|
+
for metadata, pulls and builds. No registry credentials are stored in Empeira YAML
|
|
992
|
+
or state. A cache must expose the same repository paths and configured versions.
|
|
993
|
+
Registry authentication belongs to the selected container runtime, not to Empeira
|
|
994
|
+
configuration. Authenticate directly with the runtime you selected:
|
|
995
|
+
|
|
996
|
+
```bash
|
|
997
|
+
docker login registry.example.net
|
|
998
|
+
# Or, when using Podman:
|
|
999
|
+
podman login registry.example.net
|
|
1000
|
+
```
|
|
1001
|
+
|
|
1002
|
+
Use `docker login docker.io` or `podman login docker.io` for Docker Hub, and the
|
|
1003
|
+
actual explicit host for GHCR or another registry. Native credential helpers and
|
|
1004
|
+
auth files remain owned by Docker/Podman. Empeira does not prompt for passwords,
|
|
1005
|
+
copy auth files, persist tokens, or provide a `registry login` command. Never put
|
|
1006
|
+
registry usernames, passwords, tokens, auth-file paths or credential structures in
|
|
1007
|
+
either Empeira YAML file. Probable authentication/authorization failures include
|
|
1008
|
+
the appropriate native login command; missing tags, network and TLS errors have
|
|
1009
|
+
separate diagnostics and do not receive a blanket login suggestion.
|
|
1010
|
+
|
|
1011
|
+
## Browser and additional infrastructure services
|
|
1012
|
+
|
|
1013
|
+
```yaml
|
|
1014
|
+
browser:
|
|
1015
|
+
start_url: "about:blank"
|
|
1016
|
+
image:
|
|
1017
|
+
repository: linuxserver/chromium
|
|
1018
|
+
tag: "latest"
|
|
1019
|
+
containers:
|
|
1020
|
+
additional:
|
|
1021
|
+
- name: custom-service
|
|
1022
|
+
image:
|
|
1023
|
+
repository: registry.example.org/team/web-helper
|
|
1024
|
+
tag: "1.2.3"
|
|
1025
|
+
environment:
|
|
1026
|
+
KEY: "value"
|
|
1027
|
+
command: ["serve", "--port", "8080"]
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
The helper image above is a schema illustration; substitute your actual image/tag.
|
|
1031
|
+
Both browser image fields may be overridden independently, including internal/private
|
|
1032
|
+
registries. Authenticate using the selected runtime's normal registry tooling.
|
|
1033
|
+
Browser-compatible images must provide the same HTTPS desktop UI on container port
|
|
1034
|
+
3001, support `/config` as a disposable profile and operate without direct Internet.
|
|
1035
|
+
No custom browser image is built by Empeira. Run `empeira up` before
|
|
1036
|
+
`empeira browser`. The browser command validates the existing workspace and CoreDNS,
|
|
1037
|
+
starts or reconciles only the disposable browser and its UI relay, and prints
|
|
1038
|
+
`https://127.0.0.1:<dynamic-port>/`. It never starts or reconciles the configuration
|
|
1039
|
+
server, PuppetDB, CoreDNS, gateways, additional services, or nodes. A missing or
|
|
1040
|
+
stopped required workspace service produces an error that asks you to run
|
|
1041
|
+
`empeira up`. The platform currently has no host-browser opener. The UI may take a
|
|
1042
|
+
few seconds to initialize. Its default certificate is self-signed: accept it only
|
|
1043
|
+
for the printed local endpoint. Browse `http://custom-service.empeira.internal:8080`
|
|
1044
|
+
or node hostnames inside Chromium. No startup URL CLI argument or browser Internet
|
|
1045
|
+
access is currently provided.
|
|
1046
|
+
|
|
1047
|
+
`browser.start_url` selects only the page initially opened in Chromium; it defaults
|
|
1048
|
+
to `about:blank`. Supply a nonempty string without control characters. Empeira passes
|
|
1049
|
+
the value unchanged as one `CHROME_CLI` environment value, without shell evaluation
|
|
1050
|
+
or a network/HTTP readiness check. The destination must be reachable from the
|
|
1051
|
+
isolated browser network. If the application is not ready when Chromium starts,
|
|
1052
|
+
reload the page after it becomes available. Changing the value recreates an existing
|
|
1053
|
+
browser on the next `empeira browser` or `up` reconciliation, using the new start page
|
|
1054
|
+
and a fresh disposable profile.
|
|
1055
|
+
|
|
1056
|
+
Additional services automatically join `up`, `status`, `down`, and `destroy`.
|
|
1057
|
+
Each has ownership labels, an inventory ID, a component fingerprint and the DNS name
|
|
1058
|
+
`<name>.empeira.internal` (plus short name). Configuration changes recreate only the
|
|
1059
|
+
affected service; removing a definition removes its owned container on the next `up`.
|
|
1060
|
+
`down`/`destroy` also remove services no longer present in configuration. Writable
|
|
1061
|
+
container layers are disposable; no helper data persistence is promised.
|
|
1062
|
+
|
|
1063
|
+
The only fields are `name`, `image.repository`, `image.tag`, optional `environment`
|
|
1064
|
+
(string values), optional `command` (nonempty literal argument array), and optional
|
|
1065
|
+
`configuration` (a generated YAML file, described below). Names are
|
|
1066
|
+
unique lowercase DNS labels, up to 63 characters, and cannot collide with built-in
|
|
1067
|
+
services, gateway identities or nodes. There are no host ports, volumes, privileged
|
|
1068
|
+
options, devices, capabilities, arbitrary runtime arguments, dependency graphs,
|
|
1069
|
+
restart policies or healthchecks. Status reports container state, not application
|
|
1070
|
+
readiness. This is deliberately **not a Compose replacement**. Environment changes
|
|
1071
|
+
are fingerprinted; inventory stores their hash rather than plaintext values. Runtime
|
|
1072
|
+
administrators can still inspect container environments. Keep real secrets out of Git.
|
|
1073
|
+
|
|
1074
|
+
### Generated service configuration
|
|
1075
|
+
|
|
1076
|
+
An additional service can receive a configuration file directly from `.empeira.yaml`:
|
|
1077
|
+
|
|
1078
|
+
```yaml
|
|
1079
|
+
containers:
|
|
1080
|
+
additional:
|
|
1081
|
+
- name: example-api
|
|
1082
|
+
image:
|
|
1083
|
+
repository: example/api
|
|
1084
|
+
tag: "1.0"
|
|
1085
|
+
configuration:
|
|
1086
|
+
target: /etc/example/config.yaml
|
|
1087
|
+
content:
|
|
1088
|
+
version: 1
|
|
1089
|
+
listen:
|
|
1090
|
+
port: 8080
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
This synthetic image is a schema example. Empeira serializes the parsed `content`
|
|
1094
|
+
as YAML, generates a separate file for each service in the managed workspace, and
|
|
1095
|
+
bind-mounts it **read-only** at `target`. No separate file in the control repository
|
|
1096
|
+
is required. Maps, arrays, strings, integers, floats, booleans and `null` are supported,
|
|
1097
|
+
including nested structures. Strings remain literal strings: Empeira adds no template,
|
|
1098
|
+
environment-variable or other interpolation. YAML tags, anchors, aliases and Ruby
|
|
1099
|
+
objects are rejected.
|
|
1100
|
+
|
|
1101
|
+
`target` must be an absolute file path, with nonempty path components containing only
|
|
1102
|
+
letters, digits, `_`, `-` and `.`; `/`, trailing slashes, `.`/`..` components and unsafe
|
|
1103
|
+
mount syntax are rejected. It must not overlap another managed mount, including the
|
|
1104
|
+
runtime's `/etc/hosts`, `/etc/hostname` and `/etc/resolv.conf` files.
|
|
1105
|
+
|
|
1106
|
+
Changing `content` or `target` recreates the affected service on the next `up`.
|
|
1107
|
+
Repeated `up` with unchanged configuration preserves the container and generated file.
|
|
1108
|
+
`down` retains generated files; `destroy` removes them. Removing `configuration` or
|
|
1109
|
+
the service removes its unused file after successful reconciliation. Host files are
|
|
1110
|
+
readable by the container's service user but kept in a private workspace directory.
|
|
1111
|
+
This is ordinary configuration storage, with no special handling for secrets; users
|
|
1112
|
+
remain responsible for sensitive content. Omitting `configuration` preserves the
|
|
1113
|
+
existing additional-service behavior.
|
|
1114
|
+
|
|
1115
|
+
### OpenVox View example
|
|
1116
|
+
|
|
1117
|
+
OpenVox View is the preferred example web viewer for OpenVoxDB/PuppetDB. It is an
|
|
1118
|
+
ordinary `containers.additional` service, with no special Empeira orchestration.
|
|
1119
|
+
Use this configuration to connect it to the internal HTTP API:
|
|
1120
|
+
|
|
1121
|
+
```yaml
|
|
1122
|
+
browser:
|
|
1123
|
+
start_url: "http://openvoxview.empeira.internal:5000"
|
|
1124
|
+
|
|
1125
|
+
containers:
|
|
1126
|
+
additional:
|
|
1127
|
+
- name: openvoxview
|
|
1128
|
+
image:
|
|
1129
|
+
repository: ghcr.io/voxpupuli/openvoxview
|
|
1130
|
+
tag: "v1.8.0"
|
|
1131
|
+
environment:
|
|
1132
|
+
LISTEN: "0.0.0.0"
|
|
1133
|
+
PORT: "5000"
|
|
1134
|
+
PUPPETDB_HOST: "puppetdb.empeira.internal"
|
|
1135
|
+
PUPPETDB_PORT: "8080"
|
|
1136
|
+
PUPPETDB_TLS: "false"
|
|
1137
|
+
```
|
|
1138
|
+
|
|
1139
|
+
The official image starts `/openvoxview` itself; no `command` is needed.
|
|
1140
|
+
`LISTEN=0.0.0.0` is required because the application defaults to `localhost`.
|
|
1141
|
+
Run `empeira up`, then `empeira browser`. Inside Chromium,
|
|
1142
|
+
open `http://openvoxview.empeira.internal:5000`. No host port is published.
|
|
1143
|
+
|
|
1144
|
+
OpenVox View uses Empeira's internal PuppetDB HTTP relay at
|
|
1145
|
+
`puppetdb.empeira.internal:8080`, with `PUPPETDB_TLS=false` and no TLS client
|
|
1146
|
+
certificates. This API is intentionally unauthenticated inside the isolated network;
|
|
1147
|
+
every node or service with access can use it. This is a disposable local test
|
|
1148
|
+
configuration, not production security.
|
|
1149
|
+
|
|
1150
|
+
The optional Puppet CA interface is not enabled. It requires client key/certificate
|
|
1151
|
+
material with `pp_cli_auth` and a CA certificate. The generic additional-service
|
|
1152
|
+
schema intentionally offers no mounts for these files; the PuppetDB viewer needs
|
|
1153
|
+
none of them. Leave `PUPPETCA_HOST` unset.
|
|
1154
|
+
See the [upstream project](https://github.com/voxpupuli/openvoxview) and
|
|
1155
|
+
[configuration reference](https://github.com/voxpupuli/openvoxview/blob/main/CONFIGURATION.md).
|
|
1156
|
+
|
|
1157
|
+
### Browser and example image provenance
|
|
1158
|
+
|
|
1159
|
+
- [LinuxServer Chromium](https://docs.linuxserver.io/images/docker-chromium/) is
|
|
1160
|
+
referenced as `linuxserver/chromium:latest`, resolved to Docker Hub by default.
|
|
1161
|
+
[Upstream packaging](https://github.com/linuxserver/docker-chromium) is GPL-3.0;
|
|
1162
|
+
Chromium is BSD-style with separately licensed components. Debian, Selkies and
|
|
1163
|
+
other bundled components retain their notices. Empeira does not redistribute
|
|
1164
|
+
image contents. The mutable `latest` tag is deliberate: `up` reuses the local
|
|
1165
|
+
image, while `update images` checks the selected platform manifest for changes.
|
|
1166
|
+
- The upstream UI is **Selkies HTTPS on 3001**, with HTTP 3000 intended for reverse
|
|
1167
|
+
proxy use. Empeira publishes only HTTPS through a fixed TLS byte relay using the
|
|
1168
|
+
dedicated recipe-hashed Empeira relay image, with no custom browser image. Shared Docker/Podman
|
|
1169
|
+
adapters supply the same arguments; no privileged or unconfined mode is added.
|
|
1170
|
+
See [networking](networking.md) and [development](development.md) for smoke commands
|
|
1171
|
+
and actual platform validation scope.
|
|
1172
|
+
- [Vox Pupuli OpenVox View](https://github.com/voxpupuli/openvoxview) uses
|
|
1173
|
+
[Apache-2.0](https://github.com/voxpupuli/openvoxview/blob/main/LICENSE), compatible
|
|
1174
|
+
with Empeira's AGPL-3.0-only license. The example references the official
|
|
1175
|
+
`ghcr.io/voxpupuli/openvoxview:v1.8.0` release image. The explicit GHCR repository is unaffected by `images.registry`.
|
|
1176
|
+
A release tag is not a digest lock. The upstream
|
|
1177
|
+
[container entrypoint](https://github.com/voxpupuli/openvoxview/blob/main/Containerfile.release)
|
|
1178
|
+
starts `/openvoxview` on port 5000. No upstream source, binary or image is bundled
|
|
1179
|
+
or redistributed by Empeira.
|
|
1180
|
+
|
|
1181
|
+
### Dedicated relay utility image
|
|
1182
|
+
|
|
1183
|
+
`images.relay.build: relay/Containerfile` selects the packaged recipe. The local
|
|
1184
|
+
image is `localhost/empeira-relay:<SHA256-of-recipe>` and is verified by its recipe
|
|
1185
|
+
label. Builds use an isolated temporary context containing only the recipe, never
|
|
1186
|
+
control code or credentials. `images.relay.reference` may select an independently
|
|
1187
|
+
prepared equivalent Ruby image. Browser relay scripts remain reviewed read-only
|
|
1188
|
+
packaged mounts and their contents participate in service fingerprints.
|
|
1189
|
+
|
|
1190
|
+
The recipe uses the [Docker Official Ruby image](https://github.com/docker-library/ruby)
|
|
1191
|
+
(MIT recipes), [Ruby](https://www.ruby-lang.org/en/about/license/) (Ruby/BSD terms)
|
|
1192
|
+
and Alpine packages with their own notices. It adds no packages and runs as UID/GID
|
|
1193
|
+
65534. It is built locally, not published or included in the gem as a binary.
|
|
1194
|
+
A version tag is not an immutable digest; arm64 execution needs separate validation.
|
|
1195
|
+
|
|
1196
|
+
## Shared peer network internals
|
|
1197
|
+
|
|
1198
|
+
The selected container runtime and CLI host choose the peer backend automatically.
|
|
1199
|
+
There are no user settings for subnet, VM IP/MAC, TAP, bridge, socket or adapter.
|
|
1200
|
+
Application configuration uses logical names; additional services need no `ports`
|
|
1201
|
+
or `expose` schema. `images.network_adapter_builder` selects the reviewed Go builder
|
|
1202
|
+
image used by the existing recipe-hash image cache; Go is not a host prerequisite.
|
|
1203
|
+
Node IP/MAC leases survive stop/start and are released on destroy. See
|
|
1204
|
+
[networking](networking.md) for address pools, isolation and platform validation.
|