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
data/docs/addons.md
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
# Standalone Git addons (API 1)
|
|
2
|
+
|
|
3
|
+
Empeira remains a local Puppet/OpenVox test environment. Addons expose independent
|
|
4
|
+
helper programs through its CLI, for example a converter, data synchronization
|
|
5
|
+
tool or Git hook installer. Core does not import their Ruby classes or know their
|
|
6
|
+
functionality. There is no plugin runtime, registry, package manager, dependency
|
|
7
|
+
installer or lifecycle hook. No production helper tools ship with Empeira.
|
|
8
|
+
|
|
9
|
+
## Companion addons
|
|
10
|
+
|
|
11
|
+
These independently maintained addons can be installed through Empeira but are
|
|
12
|
+
not bundled with the core application. See each repository for installation and
|
|
13
|
+
usage details.
|
|
14
|
+
|
|
15
|
+
| Addon | Description |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| [Convert](https://github.com/c8m6/empeira-addon-convert) | Convert YAML, JSON, XML, Java Properties and Puppet hashes, and generate EPP templates with typed defaults. |
|
|
18
|
+
| [Pre-Commit](https://github.com/c8m6/empeira-addon-pre-commit) | Manage Git pre-commit hooks for control and Hiera repositories using locally built Docker or Podman images. |
|
|
19
|
+
| [Sync](https://github.com/c8m6/empeira-addon-sync) | Synchronize configured files and directories with host rsync, using source and destination to define direction. |
|
|
20
|
+
|
|
21
|
+
## Configuration and commands
|
|
22
|
+
|
|
23
|
+
Declare addons in the existing effective configuration, normally the control
|
|
24
|
+
repository's `.empeira.yaml`:
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
addons:
|
|
28
|
+
converter:
|
|
29
|
+
git: https://github.com/example/empeira-converter.git
|
|
30
|
+
ref: v1.2.0
|
|
31
|
+
config:
|
|
32
|
+
output_format: yaml
|
|
33
|
+
paths: [data, defaults]
|
|
34
|
+
git-hooks:
|
|
35
|
+
git: git@example.org:team/empeira-git-hooks.git
|
|
36
|
+
ref: main
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Each entry requires `git` and `ref` and may optionally contain `config`, a mapping
|
|
40
|
+
of addon-specific settings. The addon itself interprets those settings; the
|
|
41
|
+
`converter` example above is illustrative, not a built-in Empeira option.
|
|
42
|
+
Config keys use lowercase letters, digits and underscores, starting with a letter;
|
|
43
|
+
values may be nested mappings, arrays or simple YAML scalars. Do not put secrets
|
|
44
|
+
in addon config: it is visible in project configuration and the addon's environment.
|
|
45
|
+
`git` and `ref` must be nonempty strings after merging. Names start with a lowercase letter and contain lowercase letters,
|
|
46
|
+
digits, underscores or hyphens, up to 63 characters. Built-in defaults contain
|
|
47
|
+
`addons: {}`. Mappings deep-merge and project overrides may replace just a ref.
|
|
48
|
+
Normal defaults/project/user/CLI precedence and validation remain in force.
|
|
49
|
+
The existing user preference file does **not** accept addon definitions. There is
|
|
50
|
+
no additional user configuration file and no executable or completion settings
|
|
51
|
+
in Empeira configuration.
|
|
52
|
+
|
|
53
|
+
```console
|
|
54
|
+
empeira addons list
|
|
55
|
+
empeira addons info converter
|
|
56
|
+
empeira addons sync
|
|
57
|
+
empeira addons update
|
|
58
|
+
empeira addon converter convert input.xml output.json
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
`addons list` inspects configured names and reports missing, installed or invalid
|
|
62
|
+
local installations. `addons info NAME` shows the source, configured ref, resolved
|
|
63
|
+
commit, absolute installation path and complete validated manifest. Neither
|
|
64
|
+
command downloads anything. Invalid installations are reported explicitly.
|
|
65
|
+
|
|
66
|
+
`addons sync` and `addons update` synchronize all configured sources and refs.
|
|
67
|
+
Both use the same explicit refresh semantics as `update modules`: branches and
|
|
68
|
+
moved tags follow the fetched source; a commit reference selects that commit.
|
|
69
|
+
They attempt every configured addon and return failure if any cannot be installed.
|
|
70
|
+
Already published versions survive failed updates. They need host Git and network
|
|
71
|
+
access to the configured sources, but no container engine, server, node, network,
|
|
72
|
+
proxy or infrastructure inventory.
|
|
73
|
+
|
|
74
|
+
`addon NAME ...` runs exactly one executable. Everything after NAME, including
|
|
75
|
+
`--help`, `--version`, `--`, empty arguments and shell metacharacters, is passed
|
|
76
|
+
unchanged. Core options belong **before** `addon`, for example
|
|
77
|
+
`empeira --container-engine docker addon example ...`. Manifest commands describe
|
|
78
|
+
completion; they do not restrict the executable's argument parser or validate its
|
|
79
|
+
arguments. Singular `addon` executes; plural `addons` manages.
|
|
80
|
+
|
|
81
|
+
Direct execution automatically installs a missing ref. Subsequent executions use
|
|
82
|
+
the locally installed ref without network freshness checks. `up` also installs
|
|
83
|
+
missing refs, after the Puppet infrastructure is ready. An addon failure makes
|
|
84
|
+
`up` return failure with a separate addon diagnostic; the successfully prepared
|
|
85
|
+
Puppet infrastructure remains usable. Invalid addon manifests do not affect Core
|
|
86
|
+
commands. Invalid Empeira configuration still follows normal configuration errors.
|
|
87
|
+
`update images`, `update modules` and the currently unavailable `update all` retain
|
|
88
|
+
their existing behavior; addon updates use `addons update`.
|
|
89
|
+
|
|
90
|
+
## Git references and storage
|
|
91
|
+
|
|
92
|
+
Empeira reuses the Puppetfile host Git acquisition boundary, including native
|
|
93
|
+
SSH configuration, agents, HTTPS credential helpers and sanitized Git diagnostics.
|
|
94
|
+
Sources support HTTP(S), SSH URLs and SSH scp syntax. Do not embed HTTP credentials,
|
|
95
|
+
URL query strings or fragments; authentication belongs to host Git. Local fixture
|
|
96
|
+
servers are used in tests, without external Git services.
|
|
97
|
+
|
|
98
|
+
`ref` uses the Puppetfile/r10k native Git resolution, `ref^{commit}`: branch, tag,
|
|
99
|
+
full or unambiguous abbreviated commit, or `HEAD`. It is not a semantic version
|
|
100
|
+
constraint. Unknown refs fail. API 1 requires an explicit ref (`HEAD` is the
|
|
101
|
+
explicit equivalent of Puppetfile's default). It does not support Forge versions
|
|
102
|
+
or Puppetfile Ruby symbols such as `:control_branch`.
|
|
103
|
+
|
|
104
|
+
Data lives under `~/.empeira/addons/`, resolved through the existing platform home
|
|
105
|
+
abstraction on Linux, macOS and WSL2. Each source has a SHA-256 namespace containing
|
|
106
|
+
a bare host mirror, immutable commit directories, hashed reference pointers and a
|
|
107
|
+
stable lock file. Equal source strings and commits can be reused across names,
|
|
108
|
+
refs and workspaces. Different URLs never collide simply because their addon names
|
|
109
|
+
match. Different versions remain available in parallel. No cache eviction is
|
|
110
|
+
automatic; do not remove a cache while an addon or synchronization is using it.
|
|
111
|
+
|
|
112
|
+
Acquisition and publication use an exclusive per-source lock. New mirrors and
|
|
113
|
+
revisions are staged privately, checked and atomically renamed. A reference is
|
|
114
|
+
published only after manifest and executable validation. Interrupted staging
|
|
115
|
+
directories are never considered installed. The control repository is not used as
|
|
116
|
+
an installation destination and its tracked files are not modified.
|
|
117
|
+
If the configured user home or a cache symlink would put the cache inside the
|
|
118
|
+
control repository, installation is rejected before writing there.
|
|
119
|
+
|
|
120
|
+
Snapshots are materialized by native Git with a disposable index, without a `.git`
|
|
121
|
+
working directory. Local checkout ignores inherited Git configuration and disables
|
|
122
|
+
hooks, so filters, submodules, addon entrypoints and install scripts are not run.
|
|
123
|
+
Tracked files keep their Git content and executable bits. Addons must ship
|
|
124
|
+
everything needed for execution or document prerequisites the user installs
|
|
125
|
+
separately.
|
|
126
|
+
|
|
127
|
+
## Manifest contract
|
|
128
|
+
|
|
129
|
+
Every addon repository has exactly one root-level `empeira-addon.yaml` and one
|
|
130
|
+
executable entrypoint:
|
|
131
|
+
|
|
132
|
+
```text
|
|
133
|
+
empeira-addon-example/
|
|
134
|
+
├── empeira-addon.yaml
|
|
135
|
+
├── bin/
|
|
136
|
+
│ └── example
|
|
137
|
+
└── README.md
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
schema: 1
|
|
142
|
+
description: Convert configuration files
|
|
143
|
+
executable: bin/example
|
|
144
|
+
commands:
|
|
145
|
+
convert:
|
|
146
|
+
description: Convert a file
|
|
147
|
+
arguments:
|
|
148
|
+
- name: input
|
|
149
|
+
completion: file
|
|
150
|
+
- name: output
|
|
151
|
+
completion: file
|
|
152
|
+
options:
|
|
153
|
+
--format:
|
|
154
|
+
description: Output format
|
|
155
|
+
completion: enum
|
|
156
|
+
values: [yaml, text]
|
|
157
|
+
--input:
|
|
158
|
+
completion: file
|
|
159
|
+
--directory:
|
|
160
|
+
completion: directory
|
|
161
|
+
--verbose:
|
|
162
|
+
completion: none
|
|
163
|
+
validate:
|
|
164
|
+
description: Validate input
|
|
165
|
+
arguments:
|
|
166
|
+
- name: input
|
|
167
|
+
completion: file
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Required root fields are `schema` (integer 1), `description`, `executable` and
|
|
171
|
+
`commands` (a mapping, possibly empty). Every command requires a description;
|
|
172
|
+
`arguments` (ordered array) and `options` (mapping) are optional. Arguments require
|
|
173
|
+
`name` and `completion`. Option names are explicit `-x` or `--long-name` spellings,
|
|
174
|
+
with optional descriptions. An option has one value when its completion is `file`,
|
|
175
|
+
`directory` or `enum`; `none` declares a flag without a value. To provide short and
|
|
176
|
+
long forms, declare each spelling. `enum` requires a nonempty string list `values`;
|
|
177
|
+
other types must not have `values`. `none` on an argument disables its completion.
|
|
178
|
+
Names and descriptions cannot contain control characters. Unknown fields, YAML
|
|
179
|
+
object tags, aliases, duplicate keys and unsupported schema versions are rejected.
|
|
180
|
+
|
|
181
|
+
There is no nested command framework, dynamic completion, option bundling or
|
|
182
|
+
variadic argument schema. The program may implement its own richer CLI; Empeira
|
|
183
|
+
offers completion only for the declared interface.
|
|
184
|
+
|
|
185
|
+
The entrypoint must be a regular executable inside the addon directory. Absolute
|
|
186
|
+
paths, `.`/`..` path components, and symlinks escaping that directory are rejected,
|
|
187
|
+
including an escaping manifest symlink. Keep the executable bit in Git. Scripts
|
|
188
|
+
need a shebang naming an installed interpreter; native binaries must be compatible
|
|
189
|
+
with the host. Empeira does not invoke a shell command string or interpolate argv.
|
|
190
|
+
|
|
191
|
+
## Environment API
|
|
192
|
+
|
|
193
|
+
Configuration is freshly loaded and merged for every invocation. Empeira exports
|
|
194
|
+
its approved fields as `EMPEIRA_CONFIG_*`, without JSON export or temporary
|
|
195
|
+
configuration files. Keys become uppercase, with punctuation replaced by `_`.
|
|
196
|
+
|
|
197
|
+
| Value | Export |
|
|
198
|
+
| --- | --- |
|
|
199
|
+
| String | Original value, including an empty string |
|
|
200
|
+
| Integer/float | String representation |
|
|
201
|
+
| Boolean | `true` / `false` |
|
|
202
|
+
| Mapping | Recursively flattened keys |
|
|
203
|
+
| Array | `_COUNT` and zero-based indexed elements |
|
|
204
|
+
| Empty array | `_COUNT=0` |
|
|
205
|
+
| Null | No variable |
|
|
206
|
+
|
|
207
|
+
Array elements can be mappings, arrays or scalars. For example:
|
|
208
|
+
|
|
209
|
+
```yaml
|
|
210
|
+
proxy:
|
|
211
|
+
enabled: true
|
|
212
|
+
global: [forge.puppet.com, github.com]
|
|
213
|
+
server:
|
|
214
|
+
mounts:
|
|
215
|
+
- source: /home/user/data
|
|
216
|
+
target: /mnt/data
|
|
217
|
+
readonly: true
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
produces `EMPEIRA_CONFIG_PROXY_ENABLED=true`,
|
|
221
|
+
`EMPEIRA_CONFIG_PROXY_GLOBAL_COUNT=2`,
|
|
222
|
+
`EMPEIRA_CONFIG_PROXY_GLOBAL_0=forge.puppet.com`,
|
|
223
|
+
`EMPEIRA_CONFIG_PROXY_GLOBAL_1=github.com`,
|
|
224
|
+
`EMPEIRA_CONFIG_SERVER_MOUNTS_COUNT=1`, and the variables
|
|
225
|
+
`EMPEIRA_CONFIG_SERVER_MOUNTS_0_SOURCE`, `_TARGET`, `_READONLY`.
|
|
226
|
+
|
|
227
|
+
### Per-addon configuration
|
|
228
|
+
|
|
229
|
+
Only the selected addon's `config` mapping is additionally exported as
|
|
230
|
+
`EMPEIRA_ADDON_CONFIG_*`. It uses the same flattening rules as the effective
|
|
231
|
+
configuration above. For the example, `converter` receives:
|
|
232
|
+
|
|
233
|
+
```text
|
|
234
|
+
EMPEIRA_ADDON_CONFIG_OUTPUT_FORMAT=yaml
|
|
235
|
+
EMPEIRA_ADDON_CONFIG_PATHS_COUNT=2
|
|
236
|
+
EMPEIRA_ADDON_CONFIG_PATHS_0=data
|
|
237
|
+
EMPEIRA_ADDON_CONFIG_PATHS_1=defaults
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
Other addons' `config` values are **not** included in the general
|
|
241
|
+
`EMPEIRA_CONFIG_*` export or the selected addon's export. The optional
|
|
242
|
+
`config` mapping deep-merges like other project mappings; arrays replace.
|
|
243
|
+
No new addon API version, configuration file or install hook is needed.
|
|
244
|
+
|
|
245
|
+
Runtime context is separate:
|
|
246
|
+
|
|
247
|
+
| Variable | Meaning |
|
|
248
|
+
| --- | --- |
|
|
249
|
+
| `EMPEIRA_VERSION` | Installed build version, or `development` |
|
|
250
|
+
| `EMPEIRA_ADDON_API_VERSION` | `1` |
|
|
251
|
+
| `EMPEIRA_ADDON_NAME` | Configured logical name |
|
|
252
|
+
| `EMPEIRA_ADDON_VERSION` | Configured Git ref |
|
|
253
|
+
| `EMPEIRA_ADDON_PATH` | Absolute resolved commit snapshot directory |
|
|
254
|
+
| `EMPEIRA_WORKSPACE` | Absolute canonical workspace project directory |
|
|
255
|
+
| `EMPEIRA_CONTROL_REPO` | Absolute canonical control repository root |
|
|
256
|
+
|
|
257
|
+
Workspace means the existing project identity, not a running lab. Project-bound
|
|
258
|
+
CLI calls require the existing Git-root `.empeira.yaml` marker, including when
|
|
259
|
+
invoked from a subdirectory. No workspace infrastructure is created for an addon.
|
|
260
|
+
Context variables are omitted if a caller has no such context.
|
|
261
|
+
|
|
262
|
+
The schema explicitly excludes `vm.console.root_password`, `eyaml.private_key`,
|
|
263
|
+
`browser.start_url`, `server.runtime.startup.arguments`,
|
|
264
|
+
`puppetdb.runtime.java_arguments`, `puppetdb.runtime.main_arguments`, and each
|
|
265
|
+
additional container's `environment`, `command` and `configuration.content`.
|
|
266
|
+
These include opaque content which may contain secrets under ordinary names; this
|
|
267
|
+
is not a suspicious-key-name filter. Other validated configuration is exported.
|
|
268
|
+
No private key files are read for export.
|
|
269
|
+
|
|
270
|
+
Normal inherited user variables remain available. All inherited `EMPEIRA_*` names
|
|
271
|
+
are cleared before the authoritative configuration and runtime values are set, so
|
|
272
|
+
stale, forged or excluded values cannot leak through that namespace. Environment
|
|
273
|
+
plus argv size is checked against the OS limit, with pointer/headroom allowance
|
|
274
|
+
and a conservative 128-KiB per-string limit. Oversized data or null bytes fail
|
|
275
|
+
before execution without printing values; there is no file-based fallback.
|
|
276
|
+
|
|
277
|
+
## Bash completion
|
|
278
|
+
|
|
279
|
+
Use the existing registration:
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
source <(empeira completion bash)
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
It completes `addons list/info/sync/update`, names after `addons info` and `addon`,
|
|
286
|
+
then local manifest commands, options and enum values. Positional and option
|
|
287
|
+
`file`/`directory` arguments use native Bash filename completion, including relative
|
|
288
|
+
and absolute paths, subdirectories, spaces and shell punctuation. `--option=value`
|
|
289
|
+
is supported as well as a separate value. `--` ends option parsing.
|
|
290
|
+
|
|
291
|
+
Completion reads only configuration and installed manifests. It never fetches Git
|
|
292
|
+
sources or calls an addon executable. A configured missing addon name is offered,
|
|
293
|
+
but its commands become available only after installation. Missing or invalid
|
|
294
|
+
manifests produce no addon candidates and leave Core completion usable. There is
|
|
295
|
+
no additional completion executable, script to install or cached file list.
|
|
296
|
+
|
|
297
|
+
## Development, trust and troubleshooting
|
|
298
|
+
|
|
299
|
+
The complete [minimal fixture](../spec/fixtures/addon/README.md) can be copied into
|
|
300
|
+
a separate Git repository. It prints arguments and demonstrates all completion
|
|
301
|
+
types. It does not implement a production converter, data sync or Git hook tool.
|
|
302
|
+
Keep runtime dependencies and platform instructions in the addon's README. An
|
|
303
|
+
addon can read the environment in any language and uses the caller's current
|
|
304
|
+
directory and inherited stdin/stdout/stderr. Terminal colors and interactive input
|
|
305
|
+
remain available. The CLI process is replaced by the executable: exit statuses and
|
|
306
|
+
signal termination remain native, without an intermediary process swallowing them.
|
|
307
|
+
Start failures distinguish 126 (not executable) and 127 (entrypoint/interpreter
|
|
308
|
+
not found); actual addon failure exits are returned unchanged.
|
|
309
|
+
|
|
310
|
+
Addons run as the invoking user. They are trusted local programs, **not sandboxed**.
|
|
311
|
+
The export filter limits what Core supplies; it cannot prevent a trusted program
|
|
312
|
+
from reading files or credentials already accessible to the user. Review sources
|
|
313
|
+
before execution and prefer immutable commits for reproducibility. Git source
|
|
314
|
+
authentication continues to use the user's existing Git/SSH tools; credentials
|
|
315
|
+
are not copied into an addon cache by Empeira. Git diagnostics use Core redaction;
|
|
316
|
+
addon stdout/stderr are direct program output and remain the addon's responsibility.
|
|
317
|
+
|
|
318
|
+
Supported platforms are native Linux, native macOS and Linux in WSL2. Native
|
|
319
|
+
Windows is unsupported. Host Git, the normal Empeira Ruby requirements and any
|
|
320
|
+
addon interpreter/binary prerequisites must be installed. No Docker or Podman is
|
|
321
|
+
needed to install, manage or execute addons.
|
|
322
|
+
|
|
323
|
+
For a missing addon, check the effective `addons` mapping and run `addons sync`.
|
|
324
|
+
For an unknown ref, verify it with the source owner and correct `ref`. For Git
|
|
325
|
+
authentication failures, use the normal host Git/SSH configuration. For a missing
|
|
326
|
+
or invalid manifest, fix it upstream and update to a valid revision. For 126/127,
|
|
327
|
+
check the executable bit, shebang, interpreter and host architecture. If a cache
|
|
328
|
+
is incomplete, stop users of that source and remove only its affected source
|
|
329
|
+
namespace before synchronizing again; never delete a live lock as recovery.
|
|
330
|
+
For missing command completion, inspect `addons info NAME` and source the current
|
|
331
|
+
Bash completion again after an Empeira upgrade.
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# Architecture
|
|
2
|
+
|
|
3
|
+
Empeira has one control-plane lifecycle and interchangeable infrastructure adapters.
|
|
4
|
+
The CLI presents output and calls `Application`; the core loads without Thor.
|
|
5
|
+
`Application` composes a canonical Git project, immutable effective configuration,
|
|
6
|
+
workspace identity, platform locations and the central execution runner. Constructing
|
|
7
|
+
it does not start infrastructure. Registries expose names without constructing providers.
|
|
8
|
+
The loader validates personal SSH preferences separately from the effective project
|
|
9
|
+
configuration. `Application` passes them only to the node-service login resolver;
|
|
10
|
+
that resolver selects user/identity fields for interactive SSH before dispatching
|
|
11
|
+
to the recorded provider. Internal VM transport retains its managed credentials.
|
|
12
|
+
A shared hostname-pattern helper supplies matching semantics without coupling SSH
|
|
13
|
+
preferences to proxy destination policy. Personal login values never enter context
|
|
14
|
+
configuration, definitions, fingerprints or inventory.
|
|
15
|
+
|
|
16
|
+
```mermaid
|
|
17
|
+
flowchart TD
|
|
18
|
+
CLI[CLI and completion] --> App[Application and context]
|
|
19
|
+
App --> Config[Configuration and version gate]
|
|
20
|
+
App --> State[Inventory and mutation lock]
|
|
21
|
+
App --> Plane[Control-plane lifecycle]
|
|
22
|
+
App --> Nodes[Node lifecycle]
|
|
23
|
+
Plane --> Runtime[Docker / Podman]
|
|
24
|
+
Nodes --> Container[Container provider]
|
|
25
|
+
Nodes --> VM[VM provider]
|
|
26
|
+
Container --> Runtime
|
|
27
|
+
VM --> QEMU[QEMU: KVM / HVF]
|
|
28
|
+
VM --> Images[Immutable image cache and QCOW2 overlays]
|
|
29
|
+
VM --> Peer[Replaceable peer-network backend]
|
|
30
|
+
Peer --> Runtime
|
|
31
|
+
Runtime --> Runner[Execution runner]
|
|
32
|
+
QEMU --> Runner
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Software and provider boundaries
|
|
36
|
+
|
|
37
|
+
| Boundary | Responsibility |
|
|
38
|
+
| --- | --- |
|
|
39
|
+
| Configuration | Safe YAML, deep merge, complete-path validation and permitted overrides |
|
|
40
|
+
| Platform | Host capabilities, architecture, home, state/cache locations and DNS discovery |
|
|
41
|
+
| Container runtime | Owned OCI containers, networks, volumes, images and runtime transport |
|
|
42
|
+
| Server runtime | Validated startup, paths and semantic environment mapping |
|
|
43
|
+
| Node provider | Common identity, bootstrap, enrollment and lifecycle for `container` or `vm` |
|
|
44
|
+
| VM engine | QEMU process, acceleration, console and overlay lifecycle |
|
|
45
|
+
| Image source | Upstream metadata, integrity verification and immutable VM base images |
|
|
46
|
+
| Execution | Argument-array processes, timeouts, streaming and diagnostic redaction |
|
|
47
|
+
| Addons | Declarative manifests, user Git snapshots and standalone process handoff; no infrastructure dependency |
|
|
48
|
+
|
|
49
|
+
VM interface rules resolve through Configuration using the shared hostname glob
|
|
50
|
+
matcher. The VM provider invokes the guest interface reconciler through its existing
|
|
51
|
+
VirtIO management channel after agent installation and on start/up. Device intent
|
|
52
|
+
and recovery definitions live in the locked node inventory;
|
|
53
|
+
atomically assigned locally administered MAC addresses and verified aliases bind
|
|
54
|
+
devices to workspace/node ownership. Guest observations establish device type,
|
|
55
|
+
parent, address and routes before mutation. The VM engine,
|
|
56
|
+
QEMU NIC topology, peer adapters and gateway policy remain independent of these
|
|
57
|
+
guest-only devices. See [interface lifecycle](nodes.md#additional-vm-interface-lifecycle).
|
|
58
|
+
|
|
59
|
+
OpenVox is the default software. `images.server`, `images.puppetdb` and
|
|
60
|
+
`images.postgres` select OCI images independently. `server.runtime` and
|
|
61
|
+
`puppetdb.runtime` describe compatible startup contracts without classifying image
|
|
62
|
+
names. Agent selection is independent of those images. Container recipes add base
|
|
63
|
+
tools. A shared agent acquisition component resolves native source metadata in an
|
|
64
|
+
owned, short-lived runtime helper, validates the package and publishes it atomically
|
|
65
|
+
in the user cache. Cache identity includes the native version, target and source.
|
|
66
|
+
Valid hits use local integrity and configured checksum checks and work offline,
|
|
67
|
+
including artifacts from authenticated sources. HTTP authentication and login occur
|
|
68
|
+
only during acquisition. Both node providers upload the same host artifact and
|
|
69
|
+
install it locally through native guest package managers. Bootstrap verifies cleanup
|
|
70
|
+
and enrolls certificates before Puppet runs. Cloud-Init is a VM delivery mechanism only.
|
|
71
|
+
VM disk preparation creates and resizes a private QCOW2 overlay, verifies its exact
|
|
72
|
+
backing image and configured virtual capacity, then publishes it atomically. The
|
|
73
|
+
immutable base is unchanged. First-boot readiness observes the actual mounted root
|
|
74
|
+
partition and filesystem after cloud-init growth, before managed package bootstrap.
|
|
75
|
+
Resume and workspace reconciliation preserve existing disk capacities.
|
|
76
|
+
|
|
77
|
+
Both providers reconcile normal guest proxy intent in the existing node inventory
|
|
78
|
+
after bootstrap cleanup. The shared reconciler uses the public control-plane
|
|
79
|
+
proxy environment, owned APT files and a bounded DNF block; provider transports
|
|
80
|
+
only execute guest operations. Managed Puppet receives explicit `env` arguments
|
|
81
|
+
inside the root guest command, preserving the runtime proxy policy.
|
|
82
|
+
|
|
83
|
+
Interactive tool PATH uses the same provider guest transports and node inventory.
|
|
84
|
+
Its startup fragments apply only to interactive Bash, with a small owned block
|
|
85
|
+
in the distribution's global initializer. Personal dotfiles and non-interactive
|
|
86
|
+
process environments stay under their existing owners.
|
|
87
|
+
|
|
88
|
+
VMs seed a Python 3 standard-library execution adapter through Cloud-Init, before
|
|
89
|
+
project scripts and package bootstrap. The private VirtIO-Serial channel has no
|
|
90
|
+
network listener or guest account authentication. A systemd service runs with
|
|
91
|
+
numeric UID/GID 0, independently of root shadow, PAM, NSS login policy, sudoers and
|
|
92
|
+
system SSH. Guest commands use argument arrays and owned process groups; stdout
|
|
93
|
+
and stderr stream in bounded frames without truncation. Timeouts, interrupts and
|
|
94
|
+
host disconnects terminate those groups. Binary uploads are SHA-256 verified,
|
|
95
|
+
staged privately and atomically installed in the real guest filesystem.
|
|
96
|
+
|
|
97
|
+
The QEMU monitor verifies workspace/node/instance identity before management.
|
|
98
|
+
A 0700 host directory and 0600 Unix socket restrict access; recorded device/inode
|
|
99
|
+
identity rejects replaced sockets. Sessions also verify the instance identity and
|
|
100
|
+
operation ID. No management NIC, host port, additional privileged host helper or
|
|
101
|
+
SSH credentials are needed. Existing workspace locks and VM session guards apply.
|
|
102
|
+
`node puppet` uses this targeted path without server readiness or full guest
|
|
103
|
+
reconciliation.
|
|
104
|
+
|
|
105
|
+
The user SSH adapter connects directly to the guest's peer IP through the owned
|
|
106
|
+
peer attachment and its isolated TCP client, independently of management. Personal
|
|
107
|
+
user/key/port resolution
|
|
108
|
+
applies only to `node ssh`; the default guest port is 22. The locked `empeira`
|
|
109
|
+
system account and `/var/lib/empeira` home are seeded once for regular SSH, without
|
|
110
|
+
sudo. Puppet may remove or change them. Empeira never unlocks root or restores
|
|
111
|
+
Puppet-managed authentication. Unsupported VM layouts require explicit recreation;
|
|
112
|
+
there is no migration, fallback transport or automatic resource deletion.
|
|
113
|
+
|
|
114
|
+
Nodes share lifecycle contracts: create rejects an existing name, stop preserves
|
|
115
|
+
state, start resumes it, and destroy removes owned state. Already satisfied lifecycle
|
|
116
|
+
operations return `changed: false`; absent start/stop and ownership conflicts fail.
|
|
117
|
+
Names are unique across both providers under the shared workspace transaction.
|
|
118
|
+
The structured Empeira classification fact contains `facts.empeira.provider` and
|
|
119
|
+
the fixed `facts.empeira.hierarchy: empeira` Hiera selector.
|
|
120
|
+
|
|
121
|
+
## Persistent state and ownership
|
|
122
|
+
|
|
123
|
+
| Location | Linux / WSL2 | macOS |
|
|
124
|
+
| --- | --- | --- |
|
|
125
|
+
| Cache | `$XDG_CACHE_HOME/empeira` or `~/.cache/empeira` | `~/Library/Caches/empeira` |
|
|
126
|
+
| State | `$XDG_STATE_HOME/empeira` or `~/.local/state/empeira` | `~/Library/Application Support/empeira` |
|
|
127
|
+
| Temporary work | Ruby `Dir.tmpdir` | Ruby `Dir.tmpdir` |
|
|
128
|
+
|
|
129
|
+
Relative XDG locations are ignored. Workspace identity hashes the canonical checkout
|
|
130
|
+
and user-home paths; moving a checkout changes its identity. Destroy needed resources
|
|
131
|
+
before moving it, or preserve its original path for cleanup.
|
|
132
|
+
|
|
133
|
+
`workspaces/ID/infrastructure.json` records the owning runtime, logical resources,
|
|
134
|
+
observed backend IDs, service/volume/node inventories, peer allocation and definition
|
|
135
|
+
fingerprints. Only the current schema is accepted. Atomic mode-0600 writes use
|
|
136
|
+
flush/fsync and rename. Invalid or unreadable state fails closed.
|
|
137
|
+
|
|
138
|
+
Resources carry `io.empeira.managed-by`, `io.empeira.workspace` and purpose labels.
|
|
139
|
+
Volumes also have a random identity label. Names alone never authorize adoption or
|
|
140
|
+
deletion. Mutations validate recorded IDs, labels and isolation, and persist creation
|
|
141
|
+
intent before changing runtime resources. Uncertain outcomes are inspected before
|
|
142
|
+
retry. Missing retained storage or database credentials never initialize replacement
|
|
143
|
+
data implicitly.
|
|
144
|
+
|
|
145
|
+
The runtime is authoritative for observed existence; inventory supplies ownership
|
|
146
|
+
and recovery context. Runtime migration is explicit: destroy with the owning engine,
|
|
147
|
+
then change configuration. `down` preserves CA and database storage; `destroy`
|
|
148
|
+
removes them. Both preserve control code, modules and caches.
|
|
149
|
+
|
|
150
|
+
All mutations share a nonblocking filesystem `flock` and version gate. Read-only
|
|
151
|
+
status takes no exclusive lock. The lock inode stays stable; never delete its file
|
|
152
|
+
as stale-lock recovery. Unsupported state has no automatic migration.
|
|
153
|
+
|
|
154
|
+
## Definitions and live code
|
|
155
|
+
|
|
156
|
+
Canonical SHA-256 fingerprints cover relevant managed definitions, independently
|
|
157
|
+
of application versions, YAML formatting and unrelated node defaults. Component
|
|
158
|
+
fingerprints allow selective service reconciliation while preserving owned storage.
|
|
159
|
+
Each `up` batches service and volume observations and reuses them only within that
|
|
160
|
+
locked transaction. Starts, replacements and network attachments are inspected
|
|
161
|
+
again; destructive operations verify fresh ownership and recorded IDs. Later CLI
|
|
162
|
+
invocations never inherit these observations. Local image inspection results are
|
|
163
|
+
shared by availability, reviewed-recipe, ID and architecture checks within one
|
|
164
|
+
image-preparation block. A pull or build discards the old result before the new
|
|
165
|
+
image is inspected. `up` performs no remote freshness check or full image-content
|
|
166
|
+
hash; native image storage and immutable IDs remain the source of metadata.
|
|
167
|
+
A recorded container is inspected directly by ID; a missing ID falls back to
|
|
168
|
+
name inventory to detect replacements and renamed resources. DNS discovery uses the complete service observation and
|
|
169
|
+
one node snapshot, preserving unchanged generated files. Proxy allowlist changes
|
|
170
|
+
reload Squid after readiness without replacing its container; unchanged policy
|
|
171
|
+
and bindings do not trigger HUP. The existing inventory records a validated
|
|
172
|
+
proxy ID and small-file digest only after native reload success; failed reloads
|
|
173
|
+
are retried even if generated files are already current. Gateway lockdown is
|
|
174
|
+
reused only while the same instance remains locked in that transaction. Policy apply clears that checkpoint
|
|
175
|
+
before execution so every uncertain outcome attempts fresh lockdown. Firewall
|
|
176
|
+
policy and namespace routing are still reconciled on every `up`.
|
|
177
|
+
Node access verifies network ownership and isolation with one bounded native network inspection; membership counts are collected separately
|
|
178
|
+
for lifecycle observations and deletion, never inferred from the access check.
|
|
179
|
+
VM acquisition and restart still read the complete immutable base and verify its
|
|
180
|
+
SHA-256 pin, using the existing OpenSSL implementation. Neither file timestamps
|
|
181
|
+
nor cached fingerprints replace these integrity checks.
|
|
182
|
+
Network changes and unsafe storage transitions require explicit lifecycle operations;
|
|
183
|
+
there are no implicit database-major migrations or automatic node replacements.
|
|
184
|
+
|
|
185
|
+
Managed servers disable environment caching through native Puppet configuration
|
|
186
|
+
(`environment_timeout = 0` in `[server]`), applied by the startup wrapper before
|
|
187
|
+
the configured image entrypoint. `up` checks the actual native setting and restarts
|
|
188
|
+
only a server whose setting changed; it preserves every other configuration key
|
|
189
|
+
and retained storage. The configured Puppet confdir must agree with Puppetserver
|
|
190
|
+
HOCON `master-conf-dir`. Catalog
|
|
191
|
+
requests reload live code without repository hashes or environment-cache checkpoints.
|
|
192
|
+
See [nodes](nodes.md#environment-cache-and-live-code).
|
|
193
|
+
|
|
194
|
+
Command mocks use the same node inventory, generated-file mechanism and mutation
|
|
195
|
+
lock. They reconcile atomically during initial node provisioning and start/up, preserving
|
|
196
|
+
unchanged files and removing only verified owned stubs.
|
|
197
|
+
|
|
198
|
+
## Runtime and update planes
|
|
199
|
+
|
|
200
|
+
The control plane manages the server, database, DNS, workspace gateway and optional
|
|
201
|
+
proxy, browser and additional infrastructure services. Readiness probes test real
|
|
202
|
+
DNS, server, SQL and PuppetDB responses. Shared naming and peer backends preserve
|
|
203
|
+
container/VM connectivity and isolation. Network capabilities and isolation must
|
|
204
|
+
be verifiable; there is no host-network or software-emulation fallback.
|
|
205
|
+
See [networking](networking.md) for the privilege and trust boundaries.
|
|
206
|
+
|
|
207
|
+
`browser` validates existing infrastructure and reconciles only Chromium and its
|
|
208
|
+
fixed loopback UI relay. Additional services use ordinary ownership, DNS and
|
|
209
|
+
fingerprints, with a deliberately narrow configuration schema.
|
|
210
|
+
|
|
211
|
+
Exact DNS rewrites share the existing CoreDNS configuration and service-discovery
|
|
212
|
+
hosts file. Reloadable rewrite policy stays outside the DNS container definition
|
|
213
|
+
fingerprint, so `up` can reload it without invalidating container/VM resolver
|
|
214
|
+
bindings. Target lookups remain authoritative for `empeira.internal` and never
|
|
215
|
+
fall through externally. No separate DNS inventory or provider-specific state is
|
|
216
|
+
introduced. DNS image/definition replacement retains its existing node protection.
|
|
217
|
+
|
|
218
|
+
Transparent TCP and UDP DNS redirects reuse the same gateway policy, fingerprint
|
|
219
|
+
and discovery boundary. Exact IP/protocol/port tuples are translated to observed
|
|
220
|
+
internal services
|
|
221
|
+
with DNAT/SNAT; unresolved targets remain denied. Reconciliation blocks stale targets
|
|
222
|
+
before recreation and publishes their new addresses after service startup. Changed
|
|
223
|
+
NAT revokes namespace-local connection state while DROP is active. Unchanged rules
|
|
224
|
+
preserve connections and node identities. DNS and proxy policy are independent;
|
|
225
|
+
there is no additional service-IP inventory or provider-specific redirect plane.
|
|
226
|
+
|
|
227
|
+
Updates form a separate plane. `update modules` uses host Git acquisition and a
|
|
228
|
+
disposable r10k helper; `update images` uses native registry metadata and cached
|
|
229
|
+
pulls/builds. Helpers use the runtime's normal bridge, require no infrastructure
|
|
230
|
+
inventory or workspace services, and are removed after each invocation. Git/SSH and
|
|
231
|
+
registry credentials remain owned by their native tools. `up` acquires missing
|
|
232
|
+
images only and never synchronizes modules. See [Hiera and modules](hiera-and-eyaml.md).
|
|
233
|
+
|
|
234
|
+
Standalone [addons](addons.md) reuse `Application`'s configuration and project
|
|
235
|
+
context without constructing runtime services. `Modules::HostGit` acquires mirrors
|
|
236
|
+
with the user's native authentication; addon acquisition disables hooks and
|
|
237
|
+
submodules. Native Git resolves the same `ref^{commit}` expression used by r10k,
|
|
238
|
+
without its container helper. Native Git materializes local snapshots using a
|
|
239
|
+
disposable index with configured filters and hooks disabled; publication is atomic
|
|
240
|
+
under a per-source user-cache lock.
|
|
241
|
+
They do not participate in infrastructure inventory or component fingerprints.
|
|
242
|
+
The execution runner hands off directly to the entrypoint, and the existing
|
|
243
|
+
completion catalog/Bash adapter reads its manifest. `up` prepares missing addons
|
|
244
|
+
after infrastructure readiness and reports addon failures independently.
|
|
245
|
+
|
|
246
|
+
## Diagnostic access and recovery
|
|
247
|
+
|
|
248
|
+
Exec and VM PTY shells extend the existing framed VirtIO guest adapter. Eight private
|
|
249
|
+
VirtIO-Serial ports have pinned socket identities and exclusive session slots; each
|
|
250
|
+
bounded worker owns its process session and PTY. Idle workers block on I/O. Commands,
|
|
251
|
+
uploads and interactive sessions retain one instance token and per-session identity
|
|
252
|
+
without a management network or host daemon. A local raw terminal forwards bytes,
|
|
253
|
+
resize and normal guest job control; cancellation kills the owned session groups.
|
|
254
|
+
Container exec uses native numeric-root execution and a guest Ruby supervisor with a
|
|
255
|
+
private completion receipt so native-client errors cannot impersonate guest exits.
|
|
256
|
+
|
|
257
|
+
Recovery uses the same workspace lock/inventory and existing runtime, QEMU monitor
|
|
258
|
+
and peer teardown adapters. It reads ownership fields without operational schema,
|
|
259
|
+
version, guest, base-image or current configuration gates. Every mutation still
|
|
260
|
+
checks native identity and safe paths. Resource records are removed only after confirmed
|
|
261
|
+
removal; partial failures retain evidence and continue independent cleanup. Retired
|
|
262
|
+
public certificate fingerprints permit later verified hostname reuse without requiring
|
|
263
|
+
a live CA during node removal. The mutation-lock inode remains stable after destroy.
|
|
264
|
+
|
|
265
|
+
## Execution and secrets
|
|
266
|
+
|
|
267
|
+
All external processes use `Execution::Runner` with explicit arguments, environment,
|
|
268
|
+
directory and timeout. Capture and streaming share owned-process cleanup on Linux,
|
|
269
|
+
macOS and WSL2. Debug logs redact sensitive values; captured output is untrusted and
|
|
270
|
+
failure diagnostics are filtered and bounded. Interactive shell, SSH and console
|
|
271
|
+
operations suspend progress rendering.
|
|
272
|
+
|
|
273
|
+
Keys and generated credentials stay in private external workspace storage or owned
|
|
274
|
+
volumes. Agent repository credentials use only the two documented process variables;
|
|
275
|
+
bootstrap delivers them through temporary 0600 files and verifies their removal.
|
|
276
|
+
Repository/proxy credentials and private keys stay out of image layers, inventories,
|
|
277
|
+
fingerprints and public release assets.
|