Skip to content

Commit 4cb52e0

Browse files
committed
refactor(test-guest): model OpenShell artifact sources
Signed-off-by: Evan Lezar <elezar@nvidia.com>
1 parent 31e6cc0 commit 4cb52e0

23 files changed

Lines changed: 300 additions & 241 deletions

File tree

.github/workflows/conformance.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,11 +173,11 @@ jobs:
173173
--distro fedora \
174174
--with podman-rootless \
175175
--with selinux \
176-
--copy "${candidate_cli_package[0]}:/var/lib/openshell-conformance/candidate/openshell.rpm" \
177-
--copy "${candidate_gateway_package[0]}:/var/lib/openshell-conformance/candidate/openshell-gateway.rpm" \
176+
--copy "${candidate_cli_package[0]}:/var/lib/openshell-test-guest/artifacts/openshell.rpm" \
177+
--copy "${candidate_gateway_package[0]}:/var/lib/openshell-test-guest/artifacts/openshell-gateway.rpm" \
178178
--copy conformance-input/openshell-conformance:/tmp/openshell-conformance \
179179
--copy nix/test-guest/conformance-plans/gateway-upgrade-restart.toml:/tmp/conformance-plan.toml \
180-
--provision openshell-rpm-latest-release \
180+
--provision openshell-latest-release-rpm-source \
181+
--provision openshell-candidate-rpm-source \
181182
--provision gateway-podman \
182-
--provision openshell-rpm-gateway-upgrade \
183183
-- /tmp/openshell-conformance run --plan /tmp/conformance-plan.toml

nix/test-guest/README.md

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,12 @@ nix/test-guest/
5151
└── provisioners/
5252
└── roles/
5353
├── gateway-podman/
54-
├── openshell-development/
55-
├── openshell-rpm/
56-
└── openshell-rpm-gateway-upgrade/
54+
├── openshell-candidate-binaries-source/
55+
├── openshell-binaries-contract/
56+
├── openshell-candidate-rpm-source/
57+
├── openshell-rpm-contract/
58+
├── openshell-latest-release-rpm-source/
59+
└── openshell-rpm-source/
5760
```
5861

5962
- `default.nix` assembles the guest and cache flake apps. It selects host architecture and acceleration, supplies the runtime tools, and exposes distro profiles and configuration playbooks as Nix-store catalogs.
@@ -144,18 +147,25 @@ nix run .#test-guest -- \
144147

145148
Configurations are Ansible playbooks stored under `nix/test-guest/configuration/`. Ansible runs on the host using the VM's ephemeral SSH key and loopback port. The guest does not install Ansible.
146149

147-
Configurations run in the order provided on the command line. OpenShell packages and copied files are installed after all configurations succeed.
148-
149-
`--install` packages and `--copy` files are applied by a dedicated per-run
150-
Ansible playbook. `--copy` preserves each source file's ordinary permission
151-
bits. They are not stored in prepared VM cache entries.
150+
Configurations run in the order provided on the command line. Package and file
151+
artifacts are applied after all configurations succeed. `--install` installs a
152+
generic Debian or RPM package directly; `--copy` stages a file at a guest path
153+
and preserves its ordinary permission bits. Neither is stored in prepared VM
154+
cache entries.
152155

153156
## System provisioners
154157

155-
`--provision NAME` applies a target-specific system setup after packages and
158+
`--provision NAME` applies target-specific system setup after packages and
156159
copied artifacts are present. Unlike `--with`, provisioners are not cached.
157-
They can therefore install and start an OpenShell system without coupling the
158-
prepared guest image to a particular build or driver configuration.
160+
Stage OpenShell artifacts with `--copy`, then use an ordered source installer
161+
provisioner to make OpenShell available without coupling the prepared guest
162+
image to a particular build or driver configuration.
163+
164+
OpenShell source provisioners run in command-line order. The first source
165+
installs and publishes the initial OpenShell state; later sources only make
166+
their packages and target-side apply commands available. This lets a scenario
167+
prepare guest state before initial installation and gives lifecycle actions the
168+
exact source artifacts they must install later.
159169

160170
Provisioners that support gateway continuity install a target-control command:
161171

@@ -182,23 +192,26 @@ timeout_secs = 120
182192
EOF
183193
```
184194

185-
`openshell-development` expects these copied guest paths:
195+
`openshell-candidate-binaries-source` makes staged raw candidate artifacts available.
196+
When it is the first OpenShell source provisioner, it installs them into the
197+
candidate binary OpenShell state. Stage these guest paths with `--copy`:
186198

187-
- `/usr/local/bin/openshell`
188-
- `/usr/local/bin/openshell-gateway`
189-
- `/usr/local/lib/openshell-sandbox.tar`
199+
- `/var/lib/openshell-test-guest/artifacts/openshell`
200+
- `/var/lib/openshell-test-guest/artifacts/openshell-gateway`
201+
- `/var/lib/openshell-test-guest/artifacts/openshell-sandbox.tar`
190202

191-
Compose it with `gateway-podman` to configure a rootless Podman
192-
gateway. For example, run conformance after the provisioners complete:
203+
Compose the binary candidate source with `gateway-podman` to configure
204+
a rootless Podman gateway. For example, run conformance after the provisioners
205+
complete:
193206

194207
```shell
195208
nix run .#test-guest -- \
196209
--distro fedora --with podman-rootless --with selinux \
197-
--copy ./openshell:/usr/local/bin/openshell \
210+
--copy ./openshell:/var/lib/openshell-test-guest/artifacts/openshell \
198211
--copy ./openshell-conformance:/usr/local/bin/openshell-conformance \
199-
--copy ./openshell-gateway:/usr/local/bin/openshell-gateway \
200-
--copy ./openshell-sandbox.tar:/usr/local/lib/openshell-sandbox.tar \
201-
--provision openshell-development \
212+
--copy ./openshell-gateway:/var/lib/openshell-test-guest/artifacts/openshell-gateway \
213+
--copy ./openshell-sandbox.tar:/var/lib/openshell-test-guest/artifacts/openshell-sandbox.tar \
214+
--provision openshell-candidate-binaries-source \
202215
--provision gateway-podman \
203216
-- /usr/local/bin/openshell-conformance run --plan - <<'EOF'
204217
version = 1
@@ -214,16 +227,32 @@ timeout_secs = 120
214227
EOF
215228
```
216229

217-
`openshell-rpm` expects OpenShell to have been installed with `--install`. It
218-
uses the RPM-owned `/usr/bin` binaries and `openshell-gateway` user service,
219-
without copied development artifacts or a supervisor archive. Compose it with
220-
`gateway-podman` before an RPM action such as
221-
`openshell-rpm-gateway-upgrade`.
230+
`openshell-candidate-rpm-source` makes staged candidate RPMs available and publishes a
231+
target-side candidate apply command. Stage the CLI and gateway packages as
232+
`/var/lib/openshell-test-guest/artifacts/openshell.rpm` and
233+
`/var/lib/openshell-test-guest/artifacts/openshell-gateway.rpm`.
234+
235+
`openshell-latest-release-rpm-source` downloads the latest stable OpenShell GitHub
236+
release for the guest architecture, stores its versioned RPMs under
237+
`/var/lib/openshell-conformance/baseline`, and publishes a target-side
238+
latest-release apply command.
239+
240+
For an upgrade test, order the latest-release source first so it initializes the
241+
guest, then make the candidate source available for the lifecycle action:
242+
243+
```shell
244+
--provision openshell-latest-release-rpm-source \
245+
--provision openshell-candidate-rpm-source \
246+
--provision gateway-podman
247+
```
248+
249+
The upgrade plan applies the candidate source and then uses the independent
250+
gateway-restart action to verify continuity across a subsequent gateway restart.
222251

223-
`openshell-rpm-latest-release` downloads and installs the latest stable
224-
OpenShell GitHub release for the guest architecture, then publishes the same
225-
RPM installation contract. Compose it with `gateway-podman` and an
226-
RPM gateway action when testing an upgrade from the current release.
252+
`openshell-binaries-contract`, `openshell-rpm-contract`, and
253+
`openshell-rpm-source` are internal composition roles used by the public source
254+
provisioners. They are listed for the runner's role resolution but are not
255+
normal `--provision` entry points.
227256

228257
Versioned plans under `nix/test-guest/conformance-plans/` bind conformance
229258
scenarios to the stable action-command contracts installed by provisioners.

nix/test-guest/conformance-plans/gateway-upgrade-restart.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ scenario = "sandbox-continuity"
1515
workload_expectation = "reconciled"
1616

1717
[[runs.actions]]
18-
name = "gateway-upgrade"
19-
command = "/home/openshell/.local/bin/openshell-test-guest-gateway-upgrade"
18+
name = "rpm-apply-candidate"
19+
command = "/home/openshell/.local/bin/openshell-test-guest-rpm-apply-candidate"
2020
timeout_secs = 120
2121

2222
[[runs.actions]]

nix/test-guest/default.nix

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,12 +40,13 @@ let
4040
];
4141

4242
provisionerRoles = [
43-
"openshell-development"
44-
"openshell-rpm"
45-
"openshell-rpm-latest-release"
43+
"openshell-candidate-binaries-source"
44+
"openshell-binaries-contract"
45+
"openshell-candidate-rpm-source"
46+
"openshell-rpm-contract"
47+
"openshell-latest-release-rpm-source"
48+
"openshell-rpm-source"
4649
"gateway-podman"
47-
"openshell-rpm-gateway-reinstall"
48-
"openshell-rpm-gateway-upgrade"
4950
];
5051

5152
mkDistroProfile =

nix/test-guest/provisioners/roles/gateway-podman/tasks/main.yml

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,13 @@
2222
- openshell_gateway_bin is defined
2323
- openshell_gateway_service is defined
2424
- openshell_gateway_endpoint is defined
25-
- openshell_install_source in ['development', 'rpm']
25+
- openshell_install_source in ['binaries', 'rpm']
2626
- openshell_podman_mode == 'rootless'
2727
fail_msg: >-
28-
gateway-podman requires an earlier OpenShell installation role and a
29-
podman-rootless test-guest configuration.
28+
gateway-podman requires an earlier OpenShell source provisioner, such as
29+
openshell-candidate-binaries-source, openshell-candidate-rpm-source, or
30+
openshell-latest-release-rpm-source, and a podman-rootless test-guest
31+
configuration.
3032
3133
- name: Resolve the gateway service account
3234
ansible.builtin.getent:
@@ -39,9 +41,9 @@
3941
openshell_gateway_service_uid: "{{ ansible_facts.getent_passwd.openshell[1] }}"
4042
openshell_gateway_service_home: "{{ ansible_facts.getent_passwd.openshell[4] }}"
4143

42-
- name: Configure a development gateway
44+
- name: Configure a candidate binary gateway
4345
ansible.builtin.include_tasks: development-gateway.yml
44-
when: openshell_install_source == 'development'
46+
when: openshell_install_source == 'binaries'
4547

4648
- name: Enable the gateway service account user manager
4749
ansible.builtin.command:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
openshell_binaries_contract_cli_bin: /usr/local/bin/openshell
6+
openshell_binaries_contract_gateway_bin: /usr/local/bin/openshell-gateway
7+
openshell_binaries_contract_sandbox_archive: /usr/local/lib/openshell-sandbox.tar
8+
openshell_binaries_contract_gateway_service: openshell-test-guest-gateway.service
9+
openshell_binaries_contract_gateway_endpoint: http://127.0.0.1:8080
10+
openshell_binaries_contract_state_root: /home/openshell/.local/share/openshell-test-guest
11+
openshell_binaries_contract_supervisor_image: localhost/openshell/supervisor:test-guest
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
- name: Verify installed candidate binaries
6+
ansible.builtin.stat:
7+
path: "{{ item }}"
8+
loop:
9+
- "{{ openshell_binaries_contract_cli_bin }}"
10+
- "{{ openshell_binaries_contract_gateway_bin }}"
11+
- "{{ openshell_binaries_contract_sandbox_archive }}"
12+
register: openshell_binaries_contract_artifacts
13+
14+
- name: Require installed candidate binaries
15+
ansible.builtin.assert:
16+
that: item.stat.exists
17+
fail_msg: "missing required candidate binary: {{ item.item }}"
18+
loop: "{{ openshell_binaries_contract_artifacts.results }}"
19+
loop_control:
20+
label: "{{ item.item }}"
21+
22+
- name: Publish candidate binary OpenShell installation
23+
ansible.builtin.set_fact:
24+
openshell_install_source: binaries
25+
openshell_cli_bin: "{{ openshell_binaries_contract_cli_bin }}"
26+
openshell_gateway_bin: "{{ openshell_binaries_contract_gateway_bin }}"
27+
openshell_gateway_service: "{{ openshell_binaries_contract_gateway_service }}"
28+
openshell_gateway_endpoint: "{{ openshell_binaries_contract_gateway_endpoint }}"
29+
openshell_gateway_state_root: "{{ openshell_binaries_contract_state_root }}"
30+
openshell_supervisor_source: archive
31+
openshell_supervisor_archive: "{{ openshell_binaries_contract_sandbox_archive }}"
32+
openshell_supervisor_image: "{{ openshell_binaries_contract_supervisor_image }}"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
openshell_binaries_candidate_staging_dir: /var/lib/openshell-test-guest/artifacts
6+
openshell_binaries_candidate_cli_artifact: "{{ openshell_binaries_candidate_staging_dir }}/openshell"
7+
openshell_binaries_candidate_gateway_artifact: "{{ openshell_binaries_candidate_staging_dir }}/openshell-gateway"
8+
openshell_binaries_candidate_sandbox_artifact: "{{ openshell_binaries_candidate_staging_dir }}/openshell-sandbox.tar"
9+
openshell_binaries_candidate_cli_bin: /usr/local/bin/openshell
10+
openshell_binaries_candidate_gateway_bin: /usr/local/bin/openshell-gateway
11+
openshell_binaries_candidate_sandbox_archive: /usr/local/lib/openshell-sandbox.tar
12+
openshell_binaries_candidate_apply_command: /home/openshell/.local/bin/openshell-test-guest-binaries-apply-candidate
13+
openshell_binaries_candidate_artifacts:
14+
- source: "{{ openshell_binaries_candidate_cli_artifact }}"
15+
destination: "{{ openshell_binaries_candidate_cli_bin }}"
16+
mode: "0755"
17+
- source: "{{ openshell_binaries_candidate_gateway_artifact }}"
18+
destination: "{{ openshell_binaries_candidate_gateway_bin }}"
19+
mode: "0755"
20+
- source: "{{ openshell_binaries_candidate_sandbox_artifact }}"
21+
destination: "{{ openshell_binaries_candidate_sandbox_archive }}"
22+
mode: "0644"
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
- name: Verify candidate OpenShell binaries
6+
ansible.builtin.stat:
7+
path: "{{ item.source }}"
8+
loop: "{{ openshell_binaries_candidate_artifacts }}"
9+
register: openshell_binaries_candidate_artifact_stats
10+
11+
- name: Require candidate OpenShell binaries
12+
ansible.builtin.assert:
13+
that: item.stat.exists
14+
fail_msg: "missing candidate OpenShell binary: {{ item.item.source }}"
15+
loop: "{{ openshell_binaries_candidate_artifact_stats.results }}"
16+
loop_control:
17+
label: "{{ item.item.source }}"
18+
19+
- name: Create the candidate binary apply command directory
20+
ansible.builtin.file:
21+
path: "{{ openshell_binaries_candidate_apply_command | dirname }}"
22+
state: directory
23+
mode: "0700"
24+
25+
- name: Install the candidate binary apply command
26+
ansible.builtin.copy:
27+
dest: "{{ openshell_binaries_candidate_apply_command }}"
28+
mode: "0700"
29+
content: |
30+
#!/usr/bin/env bash
31+
set -Eeuo pipefail
32+
{% for artifact in openshell_binaries_candidate_artifacts %}
33+
sudo install -D -m {{ artifact.mode }} -- {{ artifact.source | quote }} {{ artifact.destination | quote }}
34+
{% endfor %}
35+
36+
- name: Determine whether the candidate binaries are the initial OpenShell source
37+
ansible.builtin.set_fact:
38+
openshell_binaries_candidate_is_initial: "{{ openshell_install_source is not defined }}"
39+
40+
- name: Install candidate binaries as the initial OpenShell state
41+
ansible.builtin.command:
42+
cmd: "{{ openshell_binaries_candidate_apply_command }}"
43+
when: openshell_binaries_candidate_is_initial
44+
45+
- name: Publish the initial candidate binary OpenShell contract
46+
ansible.builtin.include_role:
47+
name: openshell-binaries-contract
48+
vars:
49+
openshell_binaries_contract_cli_bin: "{{ openshell_binaries_candidate_cli_bin }}"
50+
openshell_binaries_contract_gateway_bin: "{{ openshell_binaries_candidate_gateway_bin }}"
51+
openshell_binaries_contract_sandbox_archive: "{{ openshell_binaries_candidate_sandbox_archive }}"
52+
when: openshell_binaries_candidate_is_initial
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
openshell_rpm_candidate_staging_dir: /var/lib/openshell-test-guest/artifacts
6+
openshell_rpm_candidate_cli_package: "{{ openshell_rpm_candidate_staging_dir }}/openshell.rpm"
7+
openshell_rpm_candidate_gateway_package: "{{ openshell_rpm_candidate_staging_dir }}/openshell-gateway.rpm"

0 commit comments

Comments
 (0)