empeira 0.1.0.pre.alpha.1 → 0.1.0.pre.alpha.4
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 +4 -4
- data/README.md +22 -18
- data/docs/addons.md +12 -0
- data/docs/architecture.md +6 -3
- data/docs/configuration.md +16 -11
- data/docs/development.md +109 -20
- data/docs/hiera-and-eyaml.md +4 -2
- data/docs/installation.md +59 -28
- data/docs/nodes.md +10 -6
- data/docs/troubleshooting.md +16 -5
- data/lib/empeira/agent/native_commands.rb +3 -3
- data/lib/empeira/build.json +3 -3
- data/lib/empeira/compatibility/data.rb +61 -0
- data/lib/empeira/control_plane/controller.rb +4 -3
- data/lib/empeira/control_plane/environment.rb +25 -5
- data/lib/empeira/network/peer/backend.rb +2 -2
- data/lib/empeira/network/peer/linux_podman.rb +2 -2
- data/lib/empeira/network/peer/podman_machine.rb +5 -5
- data/lib/empeira/node/definition.rb +2 -2
- data/lib/empeira/server/environment_configuration.rb +8 -2
- data/lib/empeira/updates/images.rb +2 -2
- data/lib/empeira.rb +1 -0
- data/resources/modules/Containerfile +1 -1
- data/resources/modules/Gemfile +6 -0
- data/resources/modules/Gemfile.lock +7 -7
- data/resources/nodes/management/guest_agent.py +5 -2
- data/resources/proxy/Containerfile +3 -6
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4e4e7094658b9e3d8f4ee0edbafa3e4e45be28921900cce8eb4af7d66096cee6
|
|
4
|
+
data.tar.gz: 7f062dc35a9cef14ad52f55362beba6c4a5a0ab1b57225ce27a191123dc01fc9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8410139aeffa1ccaab90f3ddac57a809a86420e385f1354f801f8181c936ecf5653762cc4dbade0178d6df99b2dad1cc8b68cb8d537013132ec09e2ed65aefa1
|
|
7
|
+
data.tar.gz: 52ba2b37546bc90263d9834193b5080440e2a66425c9f9403b19800e791bf5f26b895d4c4e1af4bc218951b3a0e433437c07c550f493f4577e4e8dfd156a06bb
|
data/README.md
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
[](https://github.com/c8m6/empeira/actions/workflows/ci.yml)
|
|
6
6
|
[](https://github.com/c8m6/empeira/actions/workflows/openvox.yml)
|
|
7
7
|
[](https://github.com/c8m6/empeira/releases)
|
|
8
|
-
[](docs/installation.md)
|
|
9
|
+
[](LICENSE)
|
|
10
10
|
|
|
11
11
|
**ἐμπειρία (empeiría)** — experience gained through practice. The name reflects
|
|
12
12
|
learning about infrastructure by experimenting, testing and seeing what happens.
|
|
@@ -46,35 +46,37 @@ signed repositories or verified package artifacts are selected separately.
|
|
|
46
46
|
- An internal Chromium desktop and small additional infrastructure services.
|
|
47
47
|
- Explicit Puppetfile module and image updates.
|
|
48
48
|
|
|
49
|
-
Hosts: Linux, macOS and Windows through WSL2/Linux. Ruby 3.
|
|
50
|
-
|
|
49
|
+
Hosts: Linux, macOS and Windows through WSL2/Linux. Ruby 3.1 is the minimum; Ruby 3.1, 3.2, 3.3, 3.4 and 4.0 are supported;
|
|
50
|
+
CI runs deterministic tests and official addon/Core acceptance on all five versions
|
|
51
|
+
on Linux and macOS, plus the existing Linux Docker/OpenVox smoke on every Ruby.
|
|
51
52
|
Podman with Netavark is the default; Docker requires a Linux engine 28+ with
|
|
52
53
|
isolated bridge support. VMs require usable KVM or HVF. Platform setup and
|
|
53
54
|
validation limits are in [installation](docs/installation.md).
|
|
54
55
|
|
|
55
56
|
## Installation
|
|
56
57
|
|
|
57
|
-
|
|
58
|
+
The [Empeira gem on RubyGems.org](https://rubygems.org/gems/empeira) is the
|
|
59
|
+
recommended installation. With Ruby 3.1, 3.2, 3.3, 3.4 or 4.0 already installed:
|
|
58
60
|
|
|
59
61
|
```bash
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
bundle install
|
|
63
|
-
export EMPEIRA_SOURCE="$PWD"
|
|
64
|
-
empeira() { BUNDLE_GEMFILE="$EMPEIRA_SOURCE/Gemfile" bundle exec ruby "$EMPEIRA_SOURCE/bin/empeira" "$@"; }
|
|
62
|
+
gem install --user-install empeira --pre
|
|
63
|
+
export PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin:$PATH"
|
|
65
64
|
empeira --version
|
|
66
65
|
```
|
|
67
66
|
|
|
68
|
-
|
|
69
|
-
[
|
|
70
|
-
|
|
67
|
+
`--pre` enables prerelease installation, including the first alpha
|
|
68
|
+
[`v0.1.0-alpha.1`](https://github.com/c8m6/empeira/releases/tag/v0.1.0-alpha.1).
|
|
69
|
+
No source checkout or Bundler is needed for a gem installation. Install Git,
|
|
70
|
+
a supported container runtime and any optional VM tools separately; see
|
|
71
|
+
[installation](docs/installation.md) for host prerequisites, exact-version
|
|
72
|
+
installation and Bash completion. Developers can also
|
|
73
|
+
[run from source](docs/installation.md#source-installation-and-project-opt-in).
|
|
71
74
|
|
|
72
75
|
## Quickstart
|
|
73
76
|
|
|
74
77
|
Use a dedicated Git control repository and an empty configuration marker:
|
|
75
78
|
|
|
76
79
|
```bash
|
|
77
|
-
cd ..
|
|
78
80
|
mkdir control-repo
|
|
79
81
|
cd control-repo
|
|
80
82
|
git init
|
|
@@ -126,8 +128,10 @@ See [diagnostic access and recovery](docs/nodes.md#root-diagnostic-commands-and-
|
|
|
126
128
|
|
|
127
129
|
## Alpha status
|
|
128
130
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
+
The first public alpha, [`v0.1.0-alpha.1`](https://github.com/c8m6/empeira/releases/tag/v0.1.0-alpha.1),
|
|
132
|
+
is available on [RubyGems.org](https://rubygems.org/gems/empeira). Interfaces
|
|
133
|
+
and inventory schemas may change; unsupported inventory fails closed without
|
|
134
|
+
automatic migration.
|
|
131
135
|
Use synthetic control code and disposable credentials. The shared network is a
|
|
132
136
|
cooperative lab, and its internal PuppetDB API is unauthenticated.
|
|
133
137
|
|
|
@@ -135,7 +139,7 @@ Container process mode does not provide a full booted OS. Systemd requires Podma
|
|
|
135
139
|
and cgroup v2. VM and shared-network support require actual host capabilities;
|
|
136
140
|
macOS/HVF and arm64 runtime validation are manual gates. Native Windows, automatic
|
|
137
141
|
self-update, aggregate `update all` and standalone platform binaries are unavailable.
|
|
138
|
-
|
|
142
|
+
Distribution is through RubyGems.org and the matching GitHub Release gem asset.
|
|
139
143
|
|
|
140
144
|
## Community and license
|
|
141
145
|
|
|
@@ -145,6 +149,6 @@ and [pull requests](https://github.com/c8m6/empeira/pulls) are welcome. Follow t
|
|
|
145
149
|
[security policy](SECURITY.md).
|
|
146
150
|
|
|
147
151
|
Project-owned code and documentation are licensed under
|
|
148
|
-
[AGPL-3.0-
|
|
152
|
+
[AGPL-3.0-or-later](LICENSE). Third-party packages and images retain their own licenses
|
|
149
153
|
and notices and are obtained from upstream; empeira does not bundle them or
|
|
150
154
|
redistribute proprietary Puppet Enterprise software.
|
data/docs/addons.md
CHANGED
|
@@ -329,3 +329,15 @@ is incomplete, stop users of that source and remove only its affected source
|
|
|
329
329
|
namespace before synchronizing again; never delete a live lock as recovery.
|
|
330
330
|
For missing command completion, inspect `addons info NAME` and source the current
|
|
331
331
|
Bash completion again after an Empeira upgrade.
|
|
332
|
+
|
|
333
|
+
## Ruby support and addon development
|
|
334
|
+
|
|
335
|
+
Core and the official Convert, Pre-Commit and Sync addons support Ruby 3.1, 3.2,
|
|
336
|
+
3.3, 3.4 and 4.0 on Linux, macOS and WSL2. Ruby 3.1 is the minimum. Keep API 1
|
|
337
|
+
entrypoints runnable directly, preserve argv, terminal streams, environment and
|
|
338
|
+
exit status, and explicitly require libraries that newer Rubies no longer ship.
|
|
339
|
+
Do not install gems implicitly. Convert's XML support needs user-installed REXML.
|
|
340
|
+
Test complete standalone behavior and actual execution through Core on all five
|
|
341
|
+
Rubies; syntax checks alone are insufficient. See the [development gate](development.md#ruby-compatibility)
|
|
342
|
+
for the required Linux/macOS matrix, pinned source checkouts and local commands.
|
|
343
|
+
Real container/VM and WSL2 capabilities require their own integration gates.
|
data/docs/architecture.md
CHANGED
|
@@ -184,9 +184,12 @@ there are no implicit database-major migrations or automatic node replacements.
|
|
|
184
184
|
|
|
185
185
|
Managed servers disable environment caching through native Puppet configuration
|
|
186
186
|
(`environment_timeout = 0` in `[server]`), applied by the startup wrapper before
|
|
187
|
-
the configured image entrypoint. `
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
the configured image entrypoint. An independent `environment.conf` copy in the
|
|
188
|
+
managed environment enforces zero even when the control repository specifies
|
|
189
|
+
`unlimited`; the original remains unchanged and read-only. `up` refreshes the copy,
|
|
190
|
+
checks both native and selected-environment settings, and restarts only a server
|
|
191
|
+
whose native setting changed. It preserves every other configuration key and
|
|
192
|
+
retained storage. The configured Puppet confdir must agree with Puppetserver
|
|
190
193
|
HOCON `master-conf-dir`. Catalog
|
|
191
194
|
requests reload live code without repository hashes or environment-cache checkpoints.
|
|
192
195
|
See [nodes](nodes.md#environment-cache-and-live-code).
|
data/docs/configuration.md
CHANGED
|
@@ -404,20 +404,25 @@ runtime values without inferring them from the image name. Missing or unsafe
|
|
|
404
404
|
runtime fields fail configuration validation. Managed servers use
|
|
405
405
|
`environment_timeout = 0` in the native `[server]` section. The startup wrapper
|
|
406
406
|
uses `puppet config set` before the configured entrypoint, independently of image
|
|
407
|
-
environment-variable mappings.
|
|
408
|
-
|
|
409
|
-
|
|
407
|
+
environment-variable mappings. Empeira also prepares an independent copy of the
|
|
408
|
+
project's `environment.conf` in its managed environment directory, replacing or
|
|
409
|
+
adding only `environment_timeout = 0`. Other settings, including `modulepath` and
|
|
410
|
+
`config_version`, are preserved. The original file and the control repository
|
|
411
|
+
remain read-only in the server. The copy is refreshed during `up`, including when
|
|
412
|
+
the project has no `environment.conf` or Hiera mounts.
|
|
413
|
+
|
|
414
|
+
`up` verifies both the native server setting and the effective timeout for
|
|
415
|
+
`server.environment`, against the confdir containing
|
|
416
|
+
`server.runtime.paths.puppetdb_config`; custom Puppetserver
|
|
410
417
|
`jruby-puppet.master-conf-dir` must refer to that same directory. Puppetserver
|
|
411
|
-
HOCON master directories take precedence over Puppet CLI defaults.
|
|
412
|
-
|
|
418
|
+
HOCON master directories take precedence over Puppet CLI defaults. Native setting
|
|
419
|
+
drift updates only that key and restarts the same owned server; an
|
|
413
420
|
entrypoint that overwrites it fails verification. CA, SSL and database storage
|
|
414
421
|
are preserved. The next catalog request reloads live code without
|
|
415
|
-
an Empeira content scan or admin API invalidation.
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
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.
|
|
422
|
+
an Empeira content scan or admin API invalidation. A project timeout of `unlimited`
|
|
423
|
+
therefore stays unchanged in the checkout while the managed server uses zero.
|
|
424
|
+
To verify it, run `puppet config print environment_timeout --section server
|
|
425
|
+
--environment ENVIRONMENT` inside the server with the configured environment name.
|
|
421
426
|
|
|
422
427
|
`puppetdb.runtime` holds the independent OpenVoxDB process contract. Custom
|
|
423
428
|
images may override its executable, numeric user, Java and main arguments,
|
data/docs/development.md
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
## Environment and quality checks
|
|
4
4
|
|
|
5
|
-
Install Git, Ruby 3.
|
|
6
|
-
[installation](installation.md). The gem requires Ruby 3.
|
|
7
|
-
|
|
8
|
-
RuboCop and both dependency audits only on Ruby 3.4. Release builds use Ruby 3.4.
|
|
5
|
+
Install Git, Ruby 3.1+, Bundler and the platform prerequisites in
|
|
6
|
+
[installation](installation.md). The gem requires Ruby 3.1+; normal Ubuntu and macOS CI
|
|
7
|
+
runs deterministic RSpec on Ruby 3.1, 3.2, 3.3, 3.4 and 4.0, with
|
|
8
|
+
RuboCop and both dependency audits only on Ubuntu with Ruby 3.4. Release builds use Ruby 3.4.
|
|
9
9
|
Use synthetic control repositories and disposable credentials.
|
|
10
10
|
|
|
11
11
|
```console
|
|
@@ -20,7 +20,7 @@ bundle exec bundler-audit check --gemfile-lock resources/modules/Gemfile.lock
|
|
|
20
20
|
local child processes and loopback fixtures. Explicit integration gates are pending
|
|
21
21
|
unless enabled; a pending test is not a successful runtime check. Security auditing
|
|
22
22
|
covers known Ruby advisories in both resolutions, not all container OS packages.
|
|
23
|
-
To reproduce
|
|
23
|
+
To reproduce a CI test job, activate the corresponding Ruby, install the locked
|
|
24
24
|
bundle and run `bundle exec rspec --exclude-pattern 'spec/integration/**/*_spec.rb'`.
|
|
25
25
|
Runtime and VM compatibility remain separate manual gates.
|
|
26
26
|
|
|
@@ -93,18 +93,73 @@ For workflow changes, parse `.github/workflows/*.yml` and run `actionlint` when
|
|
|
93
93
|
available. Review action pins, triggers and permissions as well as YAML syntax.
|
|
94
94
|
See [contributing](../CONTRIBUTING.md) for review, commit and label conventions.
|
|
95
95
|
|
|
96
|
-
### Ruby
|
|
96
|
+
### Ruby compatibility
|
|
97
97
|
|
|
98
|
-
Ruby 3.
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
Ruby 3.1 is the minimum. Ruby 3.1, 3.2, 3.3, 3.4 and 4.0 run the complete
|
|
99
|
+
deterministic suite on Ubuntu 24.04 and native macOS 15 in regular CI. Every
|
|
100
|
+
combination is required, including Ruby 4.0. The suite covers the CLI, Bash
|
|
101
|
+
completion, providers, networking, bootstrap, updates, addon contracts and gem
|
|
102
|
+
build/install/start. The existing Docker/OpenVox node smoke also runs on all five
|
|
103
|
+
Rubies on Ubuntu, with at most two concurrent jobs. Broader manual runtime
|
|
104
|
+
integrations and release builds remain on Ruby 3.4;
|
|
105
|
+
a unit test does not establish Docker, rootless Podman, KVM/HVF or WSL2 results.
|
|
101
106
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
107
|
+
Both committed lockfiles use Bundler 2.6.9, compatible with Ruby 3.1. Ruby 4.0
|
|
108
|
+
requires the explicit Bundler 4.0.22 selection to avoid RubyGems platform-constant
|
|
109
|
+
warnings. Frozen installation keeps the same dependencies and lockfiles on every
|
|
110
|
+
Ruby. To reproduce Ruby 4 CI without editing either lockfile:
|
|
111
|
+
|
|
112
|
+
```sh
|
|
113
|
+
gem install bundler -v 4.0.22 --no-document
|
|
114
|
+
export BUNDLER_VERSION=4.0.22 BUNDLE_FROZEN=true
|
|
115
|
+
bundle install
|
|
116
|
+
bundle exec rspec --exclude-pattern 'spec/integration/**/*_spec.rb'
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For Ruby 3.x, use `BUNDLER_VERSION=2.6.9` instead. The module-helper image uses
|
|
120
|
+
Bundler 2.6.9 on its separately pinned Ruby base. r10k's transitive dependencies
|
|
121
|
+
`fast_gettext` and `multi_json` remain on 3.1.x and 1.18.0 respectively because
|
|
122
|
+
newer versions require Ruby 3.2. Other locked gem versions are retained. Ruby 3.1's
|
|
123
|
+
internal Data compatibility implementation preserves positional and keyword
|
|
124
|
+
constructors (including `[]` and custom initializers), frozen copies and empty
|
|
125
|
+
record value semantics. Newer Rubies retain their native Data implementation. Both
|
|
126
|
+
locks contain registry SHA-256 checksums generated by Bundler, not hand-entered:
|
|
127
|
+
|
|
128
|
+
```sh
|
|
129
|
+
bundle _2.6.9_ lock --add-checksums
|
|
130
|
+
BUNDLE_GEMFILE=resources/modules/Gemfile bundle _2.6.9_ lock --add-checksums
|
|
131
|
+
git diff -- Gemfile.lock resources/modules/Gemfile.lock
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The real official addon acceptance gate is also required in every Linux/macOS
|
|
135
|
+
matrix job. CI checks out reviewed addon commits, then installs them through
|
|
136
|
+
Core's actual local Git acquisition, cache, manifest, configuration and execution
|
|
137
|
+
paths. Synthetic control/Hiera repositories, a real PTY and a local rsync stub
|
|
138
|
+
cover revision updates, failed-update retention, argv, inherited environment,
|
|
139
|
+
configuration exports, native errors and signal-derived status. No real data or
|
|
140
|
+
external synchronization endpoints are used. With the three addon checkouts
|
|
141
|
+
under a common directory, run:
|
|
142
|
+
|
|
143
|
+
```sh
|
|
144
|
+
EMPEIRA_OFFICIAL_ADDON_ROOT=/path/to/checkouts \
|
|
145
|
+
bundle exec rspec spec/acceptance/official_addons.rb
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Each checkout must be named `empeira-addon-convert`, `empeira-addon-pre-commit`
|
|
149
|
+
or `empeira-addon-sync`. Set `EMPEIRA_OFFICIAL_ADDONS=sync` (or a comma-separated
|
|
150
|
+
subset) to select checkouts; absent sources fail the gate. Addon CI uses the
|
|
151
|
+
same gate against a pinned Core revision. Update the reviewed commit pins in
|
|
152
|
+
CI when changing either side of API 1. Standalone addon unit tests remain in
|
|
153
|
+
each addon's matrix. macOS installs GNU coreutils and GNU tar for fixtures that
|
|
154
|
+
execute Linux guest package-manager commands against synthetic roots; these are
|
|
155
|
+
test dependencies, not macOS product prerequisites. Fixtures canonicalize temporary
|
|
156
|
+
paths, keep Unix socket names short and declare synthetic CPU architectures.
|
|
157
|
+
The single Python Linux-guest adapter probe requires Linux `epoll` and `waitid`;
|
|
158
|
+
it is explicitly unavailable on Darwin and remains required on every Ubuntu
|
|
159
|
+
Ruby job. All other deterministic examples and official addon acceptance run
|
|
160
|
+
natively on macOS. Pre-commit's real container integration remains required on
|
|
161
|
+
Linux; hosted macOS has no configured Docker/Podman engine. No native Windows
|
|
162
|
+
jobs are used, and WSL2 runtime validation remains a separate real-host gate.
|
|
108
163
|
|
|
109
164
|
The test checkout must be writable: the QEMU monitor-directory cleanup fixture
|
|
110
165
|
uses the checkout as a synthetic home. A read-only container bind mount caused one
|
|
@@ -198,6 +253,7 @@ The APT authentication regression uses a local HTTPS repository with synthetic B
|
|
|
198
253
|
credentials and an ephemeral GPG signing key. It checks the helper's effective
|
|
199
254
|
`auth.conf.d` configuration, private file mode and exact credential bytes, then
|
|
200
255
|
verifies metadata returns 401 before one interactive login and 200 after the retry.
|
|
256
|
+
The fixture omits the 401 reason phrase to exercise APT's bare status/IP diagnostic.
|
|
201
257
|
The selected package download must reuse that login and pass its SHA-256 check.
|
|
202
258
|
It requires host `gpg`/`gpgconf` and a locally reachable container engine; helper and
|
|
203
259
|
host TLS verification remain enabled. Run it explicitly for either engine:
|
|
@@ -390,8 +446,35 @@ Title and release-note edits do not repair incorrect immutable assets.
|
|
|
390
446
|
|
|
391
447
|
Release notes use merged PR labels from `.github/release.yml`, independently of
|
|
392
448
|
Conventional Commit types. See [label conventions](../CONTRIBUTING.md#release-note-labels).
|
|
393
|
-
The first
|
|
394
|
-
|
|
449
|
+
The first alpha is distributed as a verified GitHub Release gem and published
|
|
450
|
+
unchanged to [RubyGems.org](https://rubygems.org/gems/empeira) via OIDC Trusted
|
|
451
|
+
Publishing. Standalone Linux/macOS binaries and automatic self-update are not
|
|
452
|
+
implemented.
|
|
453
|
+
|
|
454
|
+
### RubyGems.org distribution (manual)
|
|
455
|
+
|
|
456
|
+
After a verified GitHub Release exists, use
|
|
457
|
+
`.github/workflows/publish-rubygems.yml` via **Actions → Publish existing release to RubyGems.org → Run workflow**.
|
|
458
|
+
Run it from `main`, entering the existing release tag (for example `v0.1.0-alpha.1`).
|
|
459
|
+
The default `dry_run: true` checks the existing GitHub release, tag ancestry,
|
|
460
|
+
uploaded gem SHA-256 and embedded build metadata; it never creates a tag,
|
|
461
|
+
rebuilds a gem or contacts RubyGems with publishing credentials.
|
|
462
|
+
|
|
463
|
+
For a new gem that has not yet been published, the owner must first configure a
|
|
464
|
+
[Pending Trusted Publisher](https://rubygems.org/profile/oidc/pending_trusted_publishers)
|
|
465
|
+
on RubyGems.org. Empeira's publisher is already configured for gem `empeira`,
|
|
466
|
+
repository owner `c8m6`, repository `empeira`, workflow filename
|
|
467
|
+
`publish-rubygems.yml` and no GitHub Environment. After a successful dry-run,
|
|
468
|
+
run the same workflow with `dry_run: false`. Only its upload step receives
|
|
469
|
+
short-lived RubyGems credentials via GitHub OIDC; no persistent API key is required.
|
|
470
|
+
|
|
471
|
+
Publishing uploads the exact previously verified GitHub Release asset, not a
|
|
472
|
+
second build, and does not modify GitHub Releases or source. It fails closed
|
|
473
|
+
if the asset differs, the tag is not on `main`, or RubyGems rejects the upload.
|
|
474
|
+
RubyGems does not allow uploading the same gem name/version twice; inspect
|
|
475
|
+
the existing published version before rerunning a failed push. After success,
|
|
476
|
+
install the alpha with `gem install empeira --pre`. GitHub Releases remain
|
|
477
|
+
the authoritative archive of release artifacts.
|
|
395
478
|
|
|
396
479
|
## Dependency and image provenance
|
|
397
480
|
|
|
@@ -429,9 +512,10 @@ Run `EMPEIRA_INTEGRATION=server-environment bundle exec rspec spec/integration/s
|
|
|
429
512
|
to check native timeout 0, live edits, CA retention, PuppetDB and idempotent up
|
|
430
513
|
under Docker/rootless Podman with the default server and a custom entrypoint
|
|
431
514
|
that ignores timeout environment mapping.
|
|
432
|
-
The same gate verifies
|
|
433
|
-
|
|
434
|
-
|
|
515
|
+
The same gate verifies that an explicit `environment.conf` timeout of `unlimited`
|
|
516
|
+
is zero in the managed copy while the original stays unchanged. It edits a Ruby
|
|
517
|
+
Puppet function between catalogs and checks the changed result without `up` or a
|
|
518
|
+
restart, followed by an idempotent `up`.
|
|
435
519
|
|
|
436
520
|
Run the isolated diagnostics/recovery gate with each native runtime:
|
|
437
521
|
|
|
@@ -470,3 +554,8 @@ The DNS gate checks UDP/TCP, internal/external names, NXDOMAIN, large-answer fal
|
|
|
470
554
|
unavailable/recreated CoreDNS, a second workspace with a different subnet and
|
|
471
555
|
CoreDNS address, rule removal and idempotent reconciliation. Node identity also
|
|
472
556
|
checks both virtual DNS transports before and after node stop/start.
|
|
557
|
+
|
|
558
|
+
The VirtIO upload regression deliberately delays staged-file unlinking. Successful
|
|
559
|
+
completion must follow both atomic installation and temporary-file cleanup; a
|
|
560
|
+
cleanup failure cannot acknowledge success. The unchanged binary-upload/empty-stage
|
|
561
|
+
assertions cover this ordering on Linux, independently from the real KVM gate.
|
data/docs/hiera-and-eyaml.md
CHANGED
|
@@ -105,7 +105,8 @@ An optional mount is not permission to ignore unsafe configuration.
|
|
|
105
105
|
Puppet's [default modulepath](https://help.puppet.com/core/current/Content/PuppetCore/config_file_environment.htm)
|
|
106
106
|
includes the environment's `modules` directory. Empeira checks explicit
|
|
107
107
|
`environment.conf` modulepaths and reports a known exclusion before startup. It
|
|
108
|
-
never rewrites
|
|
108
|
+
never rewrites the original file. Its managed copy changes only
|
|
109
|
+
`environment_timeout` to zero. Expressions containing unresolved Puppet variables cannot
|
|
109
110
|
be verified completely from the CLI host; ensure the effective server modulepath
|
|
110
111
|
includes the mount destination. Environment mounts can be referenced by ordinary
|
|
111
112
|
relative paths in `hiera.yaml`, such as `data/external` or `external` when the datadir
|
|
@@ -117,7 +118,8 @@ an image rebuild, `up`, or a service restart.
|
|
|
117
118
|
Empeira neither copies their data nor writes probe files into them. It uses a managed
|
|
118
119
|
environment directory containing links to the read-only control repository so nested
|
|
119
120
|
mount targets can exist without modifying control code. Existing control files and
|
|
120
|
-
linked directories remain live
|
|
121
|
+
linked directories remain live; `environment.conf` is an independent copy refreshed
|
|
122
|
+
by `up`. `up` also refreshes links for new top-level control entries and entries under
|
|
121
123
|
projected ancestor directories. EYAML keys remain configured separately in `eyaml`,
|
|
122
124
|
and decryption runs on the server.
|
|
123
125
|
|
data/docs/installation.md
CHANGED
|
@@ -1,36 +1,63 @@
|
|
|
1
1
|
# Installation
|
|
2
2
|
|
|
3
3
|
Empeira runs natively on Linux and macOS. Windows uses **WSL2 → Linux → Empeira**;
|
|
4
|
-
native Windows Ruby is unsupported. The gemspec requires **Ruby >= 3.
|
|
5
|
-
|
|
6
|
-
release gems are built with Ruby 3.4.
|
|
7
|
-
|
|
4
|
+
native Windows Ruby is unsupported. The gemspec requires **Ruby >= 3.1**; supported Ruby versions are **3.1, 3.2,
|
|
5
|
+
3.3, 3.4 and 4.0**. Normal CI tests all five on Ubuntu and native macOS;
|
|
6
|
+
release gems are built with Ruby 3.4. The first public alpha is
|
|
7
|
+
[`v0.1.0-alpha.1`](https://github.com/c8m6/empeira/releases/tag/v0.1.0-alpha.1)
|
|
8
|
+
and is available on [RubyGems.org](https://rubygems.org/gems/empeira).
|
|
9
|
+
|
|
10
|
+
## Install from RubyGems.org (recommended)
|
|
11
|
+
|
|
12
|
+
After installing Ruby 3.1+ and the appropriate host tools/container runtime
|
|
13
|
+
described below, install Empeira from RubyGems.org:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
gem install --user-install empeira --pre
|
|
17
|
+
export PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin:$PATH"
|
|
18
|
+
empeira --version
|
|
19
|
+
empeira help
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
The `--pre` flag is needed while Empeira is available as a prerelease. For an
|
|
23
|
+
exact installation of the first alpha, use:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
gem install --user-install empeira --version 0.1.0.pre.alpha.1
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
A gem installation needs neither Bundler nor a Git checkout of Empeira. It
|
|
30
|
+
installs the `thor` runtime dependency automatically; it does **not** install
|
|
31
|
+
Git, Podman/Docker, QEMU, or Puppet/OpenVox node images. Do not use `sudo gem install` for a normal user installation. Keep the gem user's `bin` directory
|
|
32
|
+
in your shell `PATH` to retain the command across new terminal sessions.
|
|
33
|
+
|
|
34
|
+
If you previously used the source-installation `empeira()` shell function,
|
|
35
|
+
remove that function from your shell configuration and start a new shell before
|
|
36
|
+
testing the installed executable. The source function otherwise takes precedence.
|
|
8
37
|
|
|
9
38
|
## Linux and WSL2
|
|
10
39
|
|
|
11
|
-
These commands target **Ubuntu 24.04 LTS** and **Debian 13 trixie**.
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
default `ruby` package does not satisfy the gemspec on these hosts.
|
|
40
|
+
These commands target **Ubuntu 24.04 LTS** and **Debian 13 trixie**. Use Ruby 3.1+ from the distribution or your established Ruby version manager.
|
|
41
|
+
Check `ruby --version` before installing the gem. The distribution's default
|
|
42
|
+
`ruby` package is suitable only when it meets the minimum; otherwise activate
|
|
43
|
+
a compatible Ruby before proceeding.
|
|
16
44
|
|
|
17
|
-
|
|
45
|
+
Host utilities and SSH access:
|
|
18
46
|
|
|
19
47
|
```bash
|
|
20
48
|
sudo apt-get update
|
|
21
|
-
sudo apt-get install -y git
|
|
22
|
-
# Activate Ruby 3.
|
|
23
|
-
gem install bundler
|
|
49
|
+
sudo apt-get install -y git openssh-client iproute2
|
|
50
|
+
# Activate Ruby 3.1+ when the distribution's Ruby is too old.
|
|
24
51
|
ruby --version
|
|
25
52
|
gem --version
|
|
26
|
-
bundle --version
|
|
27
53
|
git --version
|
|
28
54
|
ssh -V
|
|
29
55
|
```
|
|
30
56
|
|
|
31
|
-
The selected Ruby installation must supply `gem
|
|
32
|
-
|
|
33
|
-
|
|
57
|
+
The selected Ruby installation must supply `gem`. Bundler, a source checkout and
|
|
58
|
+
a C/C++ build toolchain are not required to install the published Empeira gem.
|
|
59
|
+
They may be needed for source development or for setting up your Ruby environment;
|
|
60
|
+
see [source installation](#source-installation-and-project-opt-in).
|
|
34
61
|
`openssh-client` supplies `ssh` and `ssh-keygen` for regular node SSH. VM management
|
|
35
62
|
uses private VirtIO-Serial and Python 3 already present in the selected cloud image.
|
|
36
63
|
`iproute2` supplies host route inspection for automatic workspace subnet allocation. Coreutils supplies
|
|
@@ -131,11 +158,8 @@ Install Homebrew using its [official instructions](https://brew.sh/), then core:
|
|
|
131
158
|
```bash
|
|
132
159
|
brew install git ruby@3.4 openssh
|
|
133
160
|
export PATH="$(brew --prefix ruby@3.4)/bin:$PATH"
|
|
134
|
-
gem install --user-install bundler
|
|
135
|
-
export PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin:$PATH"
|
|
136
161
|
ruby --version
|
|
137
162
|
gem --version
|
|
138
|
-
bundle --version
|
|
139
163
|
git --version
|
|
140
164
|
ssh -V
|
|
141
165
|
```
|
|
@@ -189,7 +213,13 @@ not establish those results. See the [VM validation gates](development.md#vm-and
|
|
|
189
213
|
|
|
190
214
|
## Source installation and project opt-in
|
|
191
215
|
|
|
216
|
+
For development or unreleased changes, run Empeira directly from a Git checkout.
|
|
217
|
+
This alternative requires Bundler and the development dependencies (including a
|
|
218
|
+
build toolchain where native gems need it). Set up Bundler first, then:
|
|
219
|
+
|
|
192
220
|
```bash
|
|
221
|
+
gem install --user-install bundler
|
|
222
|
+
export PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin:$PATH"
|
|
193
223
|
git clone https://github.com/c8m6/empeira.git
|
|
194
224
|
cd empeira
|
|
195
225
|
bundle config set --local path vendor/bundle
|
|
@@ -213,21 +243,22 @@ invocation and paths with spaces work. No Puppet-file heuristic or `--project`
|
|
|
213
243
|
selector exists. The source shell function preserves the current directory.
|
|
214
244
|
Version/help/self-update work outside Git (self-update currently reports unavailable).
|
|
215
245
|
|
|
216
|
-
## Release gem
|
|
246
|
+
## Install the GitHub Release gem (alternative)
|
|
217
247
|
|
|
218
|
-
|
|
219
|
-
|
|
248
|
+
The [GitHub Releases](https://github.com/c8m6/empeira/releases) page also
|
|
249
|
+
provides the exact `.gem` asset built and verified by the release pipeline.
|
|
250
|
+
For example, after downloading the first alpha:
|
|
220
251
|
|
|
221
252
|
```bash
|
|
222
|
-
gem install --user-install ./empeira-
|
|
253
|
+
gem install --user-install ./empeira-0.1.0.pre.alpha.1.gem
|
|
223
254
|
export PATH="$(ruby -r rubygems -e 'puts Gem.user_dir')/bin:$PATH"
|
|
224
255
|
empeira --version
|
|
225
256
|
```
|
|
226
257
|
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
258
|
+
Both distribution paths use the same verified gem for the corresponding release.
|
|
259
|
+
The release version is embedded in BuildInfo. No third-party agents, images or
|
|
260
|
+
binaries are bundled. Standalone platform binaries and automatic self-update
|
|
261
|
+
remain unavailable.
|
|
231
262
|
|
|
232
263
|
For other Linux distributions, install equivalent Ruby/Git/runtime packages through
|
|
233
264
|
your established host setup. Guest OS support does not imply a tested host recipe.
|
data/docs/nodes.md
CHANGED
|
@@ -87,18 +87,22 @@ Managed servers enforce native `[server] environment_timeout = 0` before startup
|
|
|
87
87
|
and verify the effective setting during `up`, independently of image environment
|
|
88
88
|
variable support. Existing workspaces adopt it on
|
|
89
89
|
their next `up`; run that once after updating from a version that enabled caching.
|
|
90
|
+
Adopting the managed environment copy changes the server mount and recreates its
|
|
91
|
+
container once, retaining CA, SSL and database storage.
|
|
90
92
|
Each catalog request reloads live control code, modules and mounted Hiera data.
|
|
91
93
|
Empeira does not hash these trees,
|
|
92
94
|
persist content checkpoints or call the environment-cache admin API. Code edits
|
|
93
95
|
need neither `up` nor a server restart, including for agents invoked manually.
|
|
94
96
|
Empeira does not enable `use_cached_catalog`.
|
|
95
97
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
Empeira copies `environment.conf` into its managed environment and sets its timeout
|
|
99
|
+
to zero there, preserving all other settings and the original file. Run `up` to
|
|
100
|
+
refresh this copy after editing other environment settings. Avoid concurrent edits
|
|
101
|
+
during a catalog run. Existing files and directories stay live through read-only
|
|
102
|
+
links. New top-level entries and new siblings under ancestors projected for nested
|
|
103
|
+
Hiera mounts require `up` to create their links. `node start` resumes the node
|
|
104
|
+
without invoking Puppet; Puppet services enabled by a catalog may run independently
|
|
105
|
+
on startup.
|
|
102
106
|
|
|
103
107
|
## Distribution package sources
|
|
104
108
|
|
data/docs/troubleshooting.md
CHANGED
|
@@ -33,6 +33,14 @@ HTTP 403 does not trigger login, and HTTP 407 identifies proxy authentication. R
|
|
|
33
33
|
authentication continues to use native `docker login` / `podman login` and the reported
|
|
34
34
|
registry host; Empeira does not log into registries automatically.
|
|
35
35
|
|
|
36
|
+
APT can report an HTTP status without a reason phrase, for example
|
|
37
|
+
`401 [IP: 192.0.2.1 443]`. This still triggers the single repository login attempt
|
|
38
|
+
when no ENV credentials are set and both standard input and standard error are
|
|
39
|
+
connected to a TTY. The corresponding `403` and `407` forms retain their access-denied
|
|
40
|
+
and proxy-authentication diagnoses without prompting. A node retained as `incomplete`
|
|
41
|
+
after an acquisition failure must be destroyed with `empeira node destroy HOSTNAME`
|
|
42
|
+
and recreated with the original `empeira node run` arguments after resolving the cause.
|
|
43
|
+
|
|
36
44
|
APT helper credentials use literal `login` and `password` tokens in a temporary
|
|
37
45
|
0600 file under `/etc/apt/auth.conf.d`. APT treats surrounding quotes and added
|
|
38
46
|
backslashes as credential bytes, so Empeira does not add them. A successful login
|
|
@@ -140,11 +148,14 @@ problem. A successful probe with different directory listings indicates a
|
|
|
140
148
|
different engine view of the source. Empeira does not weaken mount checks or
|
|
141
149
|
change host permissions automatically.
|
|
142
150
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
151
|
+
Empeira enforces `environment_timeout = 0` in both the native server setting and
|
|
152
|
+
its independent copy of `environment.conf`. The project's original file remains
|
|
153
|
+
unchanged, even when it specifies `unlimited`. Run `up` after updating Empeira or
|
|
154
|
+
editing other settings in `environment.conf` to refresh the managed copy. Inside
|
|
155
|
+
the server, `puppet config print environment_timeout --section server --environment
|
|
156
|
+
ENVIRONMENT` must report `0` for the configured environment. A different value
|
|
157
|
+
fails startup verification; check the custom server's confdir and environmentpath.
|
|
158
|
+
No explicit cache invalidation is performed.
|
|
148
159
|
|
|
149
160
|
`config show` includes `effective_hiera_mounts`. A skipped optional source is
|
|
150
161
|
reported during `up`; mount it locally or correct the source path, then run `up`
|
|
@@ -39,11 +39,11 @@ module Empeira
|
|
|
39
39
|
diagnostic = Execution::Diagnostics.native(result.with(stderr: text, stdout: ''),
|
|
40
40
|
operation: "Agent #{operation}", tool: arguments.first)
|
|
41
41
|
case text
|
|
42
|
-
when /407\s+Proxy Authentication Required|(?:HTTP|Status code|HTTP code)\s*:?\s*407\b
|
|
42
|
+
when /407\s+Proxy Authentication Required|(?:HTTP|Status code|HTTP code)\s*:?\s*407\b|\b407[ \t]+\[IP:/i
|
|
43
43
|
raise Error, "Host helper proxy authentication failed\n#{diagnostic}", cause: nil
|
|
44
|
-
when /401\s+Unauthorized|(?:HTTP|Status code|HTTP code)\s*:?\s*401\b
|
|
44
|
+
when /401\s+Unauthorized|(?:HTTP|Status code|HTTP code)\s*:?\s*401\b|\b401[ \t]+\[IP:/i
|
|
45
45
|
raise Agent::AuthenticationRequired, diagnostic, cause: nil
|
|
46
|
-
when /403\s+Forbidden|(?:HTTP|Status code|HTTP code)\s*:?\s*403\b
|
|
46
|
+
when /403\s+Forbidden|(?:HTTP|Status code|HTTP code)\s*:?\s*403\b|\b403[ \t]+\[IP:/i
|
|
47
47
|
raise Error, "Agent repository access denied\n#{diagnostic}", cause: nil
|
|
48
48
|
end
|
|
49
49
|
raise Error, "Agent #{operation} failed\n#{diagnostic}", cause: nil
|
data/lib/empeira/build.json
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Ruby 3.2 introduced immutable Data value objects. Keep Ruby 3.1 support
|
|
4
|
+
# without replacing the native Data implementation on newer Rubies.
|
|
5
|
+
module Empeira
|
|
6
|
+
module Compatibility
|
|
7
|
+
module DataFactory
|
|
8
|
+
module_function
|
|
9
|
+
|
|
10
|
+
# rubocop:disable-next Metrics/AbcSize, Metrics/MethodLength -- Ruby 3.1 must emulate Data initializer semantics.
|
|
11
|
+
def define(*members, &definition)
|
|
12
|
+
# The explicit nil class name also permits zero members and preserves
|
|
13
|
+
# Struct's value equality, hashing and pattern matching for empty records.
|
|
14
|
+
base_class = Struct.new(nil, *members, keyword_init: true)
|
|
15
|
+
base_class.class_eval do
|
|
16
|
+
def initialize(*positional, **keywords)
|
|
17
|
+
fields = self.class.members
|
|
18
|
+
raise ArgumentError, 'too many positional arguments' if positional.size > fields.size
|
|
19
|
+
|
|
20
|
+
supplied = fields.take(positional.size).zip(positional).to_h.merge(keywords)
|
|
21
|
+
missing = fields - supplied.keys
|
|
22
|
+
unexpected = supplied.keys - fields
|
|
23
|
+
raise ArgumentError, "missing keywords: #{missing.join(', ')}" unless missing.empty?
|
|
24
|
+
raise ArgumentError, "unknown keywords: #{unexpected.join(', ')}" unless unexpected.empty?
|
|
25
|
+
|
|
26
|
+
super(**supplied)
|
|
27
|
+
freeze
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def with(**changes)
|
|
31
|
+
self.class.new(**to_h, **changes)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def initialize_copy(other)
|
|
35
|
+
super
|
|
36
|
+
freeze
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
value_class = Class.new(base_class)
|
|
40
|
+
define_constructors(value_class)
|
|
41
|
+
value_class.include(self)
|
|
42
|
+
value_class.class_eval(&definition) if definition
|
|
43
|
+
value_class
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# rubocop:disable-next Metrics/AbcSize -- Normalize native Data constructors before custom initialization.
|
|
47
|
+
def define_constructors(value_class)
|
|
48
|
+
value_class.define_singleton_method(:new) do |*positional, **keywords|
|
|
49
|
+
raise ArgumentError, 'cannot mix positional and keyword arguments' unless positional.empty? || keywords.empty?
|
|
50
|
+
raise ArgumentError, 'too many positional arguments' if positional.size > members.size
|
|
51
|
+
|
|
52
|
+
keywords = members.take(positional.size).zip(positional).to_h unless positional.empty?
|
|
53
|
+
super(**keywords).freeze
|
|
54
|
+
end
|
|
55
|
+
value_class.define_singleton_method(:[]) { |*positional, **keywords| new(*positional, **keywords) }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
Data = Empeira::Compatibility::DataFactory unless defined?(Data)
|
|
@@ -350,10 +350,11 @@ module Empeira
|
|
|
350
350
|
|
|
351
351
|
def reconcile_server_environment
|
|
352
352
|
environment = Server::EnvironmentConfiguration.new(runtime: @runtime, plan: @plan)
|
|
353
|
-
|
|
353
|
+
if environment.reconcile(@observed.fetch('server'))
|
|
354
|
+
@changed = true
|
|
355
|
+
@health.wait('server', @observed)
|
|
356
|
+
end
|
|
354
357
|
|
|
355
|
-
@changed = true
|
|
356
|
-
@health.wait('server', @observed)
|
|
357
358
|
environment.verify!(@observed.fetch('server'))
|
|
358
359
|
end
|
|
359
360
|
|
|
@@ -9,7 +9,7 @@ module Empeira
|
|
|
9
9
|
def initialize(context:, hiera:)
|
|
10
10
|
@project = context.project.path
|
|
11
11
|
@root = root(context)
|
|
12
|
-
@targets = mount_targets(hiera)
|
|
12
|
+
@targets = ['environment.conf', *mount_targets(hiera)]
|
|
13
13
|
@modules = Modules::Storage.new(context: context).root if @project.join('Puppetfile').file?
|
|
14
14
|
@targets |= ['modules'] if @modules
|
|
15
15
|
@base = context.locations.workspace(context.workspace).join('environments')
|
|
@@ -17,14 +17,11 @@ module Empeira
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def mounts
|
|
20
|
-
return [bind(@project, @root)] if @targets.empty?
|
|
21
|
-
|
|
22
20
|
[bind(@project, CONTROL), bind(@directory, @root),
|
|
23
21
|
*(@modules ? [bind(@modules, "#{@root}/modules")] : [])]
|
|
24
22
|
end
|
|
25
23
|
|
|
26
24
|
def prepare
|
|
27
|
-
return if @targets.empty?
|
|
28
25
|
raise Error, 'Managed environment directory must not be a symlink' if @directory.symlink?
|
|
29
26
|
|
|
30
27
|
FileUtils.mkdir_p(@directory, mode: 0o755)
|
|
@@ -81,13 +78,36 @@ module Empeira
|
|
|
81
78
|
end
|
|
82
79
|
|
|
83
80
|
def create_entry(relative, destination)
|
|
84
|
-
if
|
|
81
|
+
if relative == 'environment.conf'
|
|
82
|
+
prepare_configuration(destination)
|
|
83
|
+
elsif @targets.any? { |target| target == relative || target.start_with?("#{relative}/") }
|
|
85
84
|
create_target(relative, destination)
|
|
86
85
|
else
|
|
87
86
|
create_link(relative, destination)
|
|
88
87
|
end
|
|
89
88
|
end
|
|
90
89
|
|
|
90
|
+
def prepare_configuration(destination)
|
|
91
|
+
content = environment_configuration
|
|
92
|
+
return if !destination.symlink? && destination.file? && destination.binread == content
|
|
93
|
+
|
|
94
|
+
Tempfile.create('environment-', @directory) do |file|
|
|
95
|
+
file.chmod(0o644)
|
|
96
|
+
file.write(content)
|
|
97
|
+
file.flush
|
|
98
|
+
File.rename(file.path, destination)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def environment_configuration
|
|
103
|
+
source = @project.join('environment.conf')
|
|
104
|
+
content = source.exist? ? source.binread : ''
|
|
105
|
+
content = content.gsub(/^[ \t]*environment_timeout[ \t]*=[^\r\n]*/, 'environment_timeout = 0')
|
|
106
|
+
content += "\n" unless content.empty? || content.end_with?("\n")
|
|
107
|
+
content += "environment_timeout = 0\n" unless content.match?(/^environment_timeout = 0\r?$/)
|
|
108
|
+
content
|
|
109
|
+
end
|
|
110
|
+
|
|
91
111
|
def create_target(relative, destination)
|
|
92
112
|
raise Error, 'Managed environment destination is unsafe' if destination.symlink?
|
|
93
113
|
|
|
@@ -6,7 +6,7 @@ module Empeira
|
|
|
6
6
|
class Backend
|
|
7
7
|
attr_reader :context, :runtime, :runner, :store
|
|
8
8
|
|
|
9
|
-
def self.build(context:, **)
|
|
9
|
+
def self.build(context:, **options)
|
|
10
10
|
klass = if context.container_engine == 'docker'
|
|
11
11
|
DockerAdapter
|
|
12
12
|
elsif context.platform.os == :macos
|
|
@@ -14,7 +14,7 @@ module Empeira
|
|
|
14
14
|
else
|
|
15
15
|
LinuxPodman
|
|
16
16
|
end
|
|
17
|
-
klass.new(context: context, **)
|
|
17
|
+
klass.new(context: context, **options)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def initialize(context:, runtime:, runner:, store:)
|
|
@@ -92,8 +92,8 @@ module Empeira
|
|
|
92
92
|
raise Providers::OwnershipError, 'VM TAP already exists; inspect its owning process'
|
|
93
93
|
end
|
|
94
94
|
|
|
95
|
-
def namespace(
|
|
96
|
-
command('podman', '--remote=false', 'unshare', '--rootless-netns',
|
|
95
|
+
def namespace(*arguments, **options)
|
|
96
|
+
command('podman', '--remote=false', 'unshare', '--rootless-netns', *arguments, **options)
|
|
97
97
|
end
|
|
98
98
|
|
|
99
99
|
def attached?(record, links)
|
|
@@ -98,13 +98,13 @@ module Empeira
|
|
|
98
98
|
raise Error, 'Podman Machine cannot verify the peer helper at its host path; configure its shared mount'
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
-
def namespace(*)
|
|
102
|
-
executable, *
|
|
103
|
-
command(executable, *
|
|
101
|
+
def namespace(*arguments)
|
|
102
|
+
executable, *command_arguments = namespace_command(@machine, *arguments)
|
|
103
|
+
command(executable, *command_arguments)
|
|
104
104
|
end
|
|
105
105
|
|
|
106
|
-
def namespace_command(machine, *)
|
|
107
|
-
['podman', 'machine', 'ssh', machine, Shellwords.join(['podman', 'unshare', '--rootless-netns', *])]
|
|
106
|
+
def namespace_command(machine, *arguments)
|
|
107
|
+
['podman', 'machine', 'ssh', machine, Shellwords.join(['podman', 'unshare', '--rootless-netns', *arguments])]
|
|
108
108
|
end
|
|
109
109
|
end
|
|
110
110
|
end
|
|
@@ -5,10 +5,10 @@ module Empeira
|
|
|
5
5
|
class Definition < Services::Definition
|
|
6
6
|
attr_reader :hostname
|
|
7
7
|
|
|
8
|
-
def initialize(hostname:, workspace:, **)
|
|
8
|
+
def initialize(hostname:, workspace:, **options)
|
|
9
9
|
@hostname = hostname
|
|
10
10
|
super(key: "node-#{Digest::SHA256.hexdigest(hostname)[0, 24]}", workspace: workspace,
|
|
11
|
-
hostname: hostname, **)
|
|
11
|
+
hostname: hostname, **options)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def ownership_labels
|
|
@@ -24,10 +24,10 @@ module Empeira
|
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def verify!(resource)
|
|
27
|
-
return if current(resource) == '0'
|
|
27
|
+
return if current(resource) == '0' && effective(resource) == '0'
|
|
28
28
|
|
|
29
29
|
raise Error, 'Puppetserver environment_timeout is not 0 after startup; the custom entrypoint or ' \
|
|
30
|
-
'server confdir overrides the managed setting; inspect the server runtime contract'
|
|
30
|
+
'server confdir/environment overrides the managed setting; inspect the server runtime contract'
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
private
|
|
@@ -36,6 +36,12 @@ module Empeira
|
|
|
36
36
|
execute(resource, [ControlPlane::Health::RUBY, READER, '--confdir', confdir]).stdout.strip
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
+
def effective(resource)
|
|
40
|
+
arguments = [PUPPET, 'config', 'print', 'environment_timeout', '--section', 'server',
|
|
41
|
+
'--confdir', confdir, '--environment', @plan.config.dig('server', 'environment')]
|
|
42
|
+
execute(resource, arguments).stdout.strip
|
|
43
|
+
end
|
|
44
|
+
|
|
39
45
|
def execute(resource, arguments)
|
|
40
46
|
result = @runtime.service_exec(resource, arguments)
|
|
41
47
|
return result if result.success?
|
|
@@ -73,9 +73,9 @@ module Empeira
|
|
|
73
73
|
{ label: 'VM network helper', image: adapter.image, recipe: adapter.recipe, files: adapter.files }]
|
|
74
74
|
end
|
|
75
75
|
|
|
76
|
-
def utility_artifact(key, label, **)
|
|
76
|
+
def utility_artifact(key, label, **options)
|
|
77
77
|
Empeira::Images::Configuration.artifact(
|
|
78
|
-
@config.dig('images', key), registry: @config.dig('images', 'registry'), **
|
|
78
|
+
@config.dig('images', key), registry: @config.dig('images', 'registry'), **options
|
|
79
79
|
).merge(label: label)
|
|
80
80
|
end
|
|
81
81
|
|
data/lib/empeira.rb
CHANGED
|
@@ -5,7 +5,7 @@ RUN apk add --no-cache git ca-certificates
|
|
|
5
5
|
WORKDIR /opt/empeira-modules
|
|
6
6
|
COPY Gemfile Gemfile.lock ./
|
|
7
7
|
RUN apk add --no-cache --virtual .build-deps build-base libffi-dev \
|
|
8
|
-
&& gem install bundler -v
|
|
8
|
+
&& gem install bundler -v 2.6.9 --no-document \
|
|
9
9
|
&& bundle config set deployment true && bundle install --jobs 2 \
|
|
10
10
|
&& apk del .build-deps
|
|
11
11
|
COPY worker.rb ./
|
data/resources/modules/Gemfile
CHANGED
|
@@ -3,3 +3,9 @@
|
|
|
3
3
|
source 'https://rubygems.org'
|
|
4
4
|
|
|
5
5
|
gem 'r10k', '5.0.3'
|
|
6
|
+
|
|
7
|
+
# r10k's newer fast_gettext 4.x dependency requires Ruby >= 3.2.
|
|
8
|
+
# Keep the module helper usable with the oldest supported Ruby (3.1).
|
|
9
|
+
gem 'fast_gettext', '~> 3.1.0'
|
|
10
|
+
# Newer multi_json requires Ruby >= 3.2.
|
|
11
|
+
gem 'multi_json', '1.18.0'
|
|
@@ -13,9 +13,8 @@ GEM
|
|
|
13
13
|
faraday (>= 1, < 3)
|
|
14
14
|
faraday-net_http (3.4.4)
|
|
15
15
|
net-http (~> 0.5)
|
|
16
|
-
fast_gettext (
|
|
16
|
+
fast_gettext (3.1.0)
|
|
17
17
|
prime
|
|
18
|
-
racc
|
|
19
18
|
fiddle (1.1.8)
|
|
20
19
|
forwardable (1.4.0)
|
|
21
20
|
gettext (3.5.2)
|
|
@@ -36,7 +35,7 @@ GEM
|
|
|
36
35
|
log4r (1.1.10)
|
|
37
36
|
logger (1.7.0)
|
|
38
37
|
minitar (1.1.0)
|
|
39
|
-
multi_json (1.
|
|
38
|
+
multi_json (1.18.0)
|
|
40
39
|
net-http (0.9.1)
|
|
41
40
|
uri (>= 0.11.1)
|
|
42
41
|
prime (0.1.4)
|
|
@@ -68,18 +67,19 @@ PLATFORMS
|
|
|
68
67
|
x86_64-linux
|
|
69
68
|
|
|
70
69
|
DEPENDENCIES
|
|
70
|
+
fast_gettext (~> 3.1.0)
|
|
71
|
+
multi_json (= 1.18.0)
|
|
71
72
|
r10k (= 5.0.3)
|
|
72
73
|
|
|
73
74
|
CHECKSUMS
|
|
74
75
|
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
|
75
|
-
bundler (4.0.22) sha256=d8d5ec84c8555e0af71db63ed7aee4d1a8fb839ec46d84212d61979242a5d75a
|
|
76
76
|
colored2 (4.0.3) sha256=63e1038183976287efc43034f5cca17fb180b4deef207da8ba78d051cbce2b37
|
|
77
77
|
cri (2.15.12) sha256=8abfe924ef53e772a8e4ee907e791d3bfcfca78bc62a5859e3b9899ba29956e5
|
|
78
78
|
erubi (1.13.1) sha256=a082103b0885dbc5ecf1172fede897f9ebdb745a4b97a5e8dc63953db1ee4ad9
|
|
79
79
|
faraday (2.14.4) sha256=9bb4408c44621b0dbaaaa39e5dbfc4dbe58cc6751b6eb94d16ae9e1f2f2fab6e
|
|
80
80
|
faraday-follow_redirects (0.5.0) sha256=5cde93c894b30943a5d2b93c2fe9284216a6b756f7af406a1e55f211d97d10ad
|
|
81
81
|
faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588
|
|
82
|
-
fast_gettext (
|
|
82
|
+
fast_gettext (3.1.0) sha256=9c4c84c33a875cc9edc062179229f9d373179a624d3c961eed747cddbab72ac5
|
|
83
83
|
fiddle (1.1.8) sha256=7fa8ee3627271497f3add5503acdbc3f40b32f610fc1cf49634f083ef3f32eee
|
|
84
84
|
forwardable (1.4.0) sha256=f1cd40cc9812937980e1c76f1aa053660990a7c9b6a98fc37d945468afcce838
|
|
85
85
|
gettext (3.5.2) sha256=ada02c59aa7e9f56bd2522faedaed16421dd2f3ddb5fe28628c0be5abcbf3c74
|
|
@@ -90,7 +90,7 @@ CHECKSUMS
|
|
|
90
90
|
log4r (1.1.10) sha256=9b452928c964b7c54c09aeb25ff045b5a722b387b16c9ce37cb1baec00062966
|
|
91
91
|
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
|
92
92
|
minitar (1.1.0) sha256=38db0cfb6f3801017946cdcd8dc53f2cf3fd41ff752892312bf9a1639c9ea23e
|
|
93
|
-
multi_json (1.
|
|
93
|
+
multi_json (1.18.0) sha256=23f70cf73e2895a33e6d10f0ec955b28ef5627ca4bbad0f292e7d16f4675596f
|
|
94
94
|
net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
|
|
95
95
|
prime (0.1.4) sha256=4d755ebf7c2994a6f3a3fee0d072063be3fff2d4042ebff6cd5eebd4747a225e
|
|
96
96
|
puppet_forge (6.2.0) sha256=9cde4841a7a6950afeb0c4fec02449931179863918c0a6e6909cb2a6c6998a0c
|
|
@@ -102,4 +102,4 @@ CHECKSUMS
|
|
|
102
102
|
uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
|
|
103
103
|
|
|
104
104
|
BUNDLED WITH
|
|
105
|
-
|
|
105
|
+
2.6.9
|
|
@@ -316,6 +316,7 @@ def handle(message):
|
|
|
316
316
|
active['file'].close()
|
|
317
317
|
active = None
|
|
318
318
|
pending = None
|
|
319
|
+
status = 0
|
|
319
320
|
try:
|
|
320
321
|
with tempfile.NamedTemporaryFile(dir=os.path.dirname(destination), delete=False) as target:
|
|
321
322
|
pending = target.name
|
|
@@ -326,14 +327,16 @@ def handle(message):
|
|
|
326
327
|
os.fsync(target.fileno())
|
|
327
328
|
os.replace(pending, destination)
|
|
328
329
|
pending = None
|
|
329
|
-
send({'type': 'exit', 'status': 0, 'timed_out': False})
|
|
330
330
|
except OSError as error:
|
|
331
331
|
send({'type': 'stderr', 'data': base64.b64encode((os.strerror(error.errno) + '\n').encode()).decode()})
|
|
332
|
-
|
|
332
|
+
status = 1
|
|
333
333
|
finally:
|
|
334
334
|
os.unlink(staged)
|
|
335
335
|
if pending:
|
|
336
336
|
os.unlink(pending)
|
|
337
|
+
# Completion includes staging cleanup; an unlink failure must never
|
|
338
|
+
# acknowledge success to a controller that is already enrolling/Puppet.
|
|
339
|
+
send({'type': 'exit', 'status': status, 'timed_out': False})
|
|
337
340
|
else:
|
|
338
341
|
raise ValueError('Unexpected protocol operation')
|
|
339
342
|
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
ARG EMPEIRA_BASE_UBUNTU=library/ubuntu@sha256:da6fc2be547864451aa253836dd926da33623312df4a9a243e35dc877c378a78
|
|
2
2
|
FROM ${EMPEIRA_BASE_UBUNTU}
|
|
3
3
|
ENV DEBIAN_FRONTEND=noninteractive
|
|
4
|
-
RUN
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
RUN ["apt-get", "--snapshot", "20261001T000000Z", "-o", "APT::Update::Error-Mode=any", "update"]
|
|
8
|
-
RUN ["apt-get", "--snapshot", "20261001T000000Z", "install", "--yes", "--no-install-recommends", "squid=7.2-2ubuntu2.2"]
|
|
9
|
-
RUN ["apt-get", "clean"]
|
|
4
|
+
RUN apt-get -o APT::Update::Error-Mode=any update \
|
|
5
|
+
&& apt-get install --yes --no-install-recommends ca-certificates squid \
|
|
6
|
+
&& rm -rf /var/lib/apt/lists/*
|
|
10
7
|
USER proxy
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: empeira
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.0.pre.alpha.
|
|
4
|
+
version: 0.1.0.pre.alpha.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Christian Meißner (c8m6)
|
|
@@ -72,6 +72,7 @@ files:
|
|
|
72
72
|
- lib/empeira/cli/progress.rb
|
|
73
73
|
- lib/empeira/cli/proxy.rb
|
|
74
74
|
- lib/empeira/cli/update.rb
|
|
75
|
+
- lib/empeira/compatibility/data.rb
|
|
75
76
|
- lib/empeira/completion/addons.rb
|
|
76
77
|
- lib/empeira/completion/bash.rb
|
|
77
78
|
- lib/empeira/completion/catalog.rb
|
|
@@ -303,7 +304,7 @@ files:
|
|
|
303
304
|
- resources/relay/server_start.sh
|
|
304
305
|
homepage: https://github.com/c8m6/empeira
|
|
305
306
|
licenses:
|
|
306
|
-
- AGPL-3.0-
|
|
307
|
+
- AGPL-3.0-or-later
|
|
307
308
|
metadata:
|
|
308
309
|
rubygems_mfa_required: 'true'
|
|
309
310
|
rdoc_options: []
|
|
@@ -313,7 +314,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
313
314
|
requirements:
|
|
314
315
|
- - ">="
|
|
315
316
|
- !ruby/object:Gem::Version
|
|
316
|
-
version: '3.
|
|
317
|
+
version: '3.1'
|
|
317
318
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
318
319
|
requirements:
|
|
319
320
|
- - ">="
|