Repository navigation
fix(e2e): model portable Podman service activation #9205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
564e248
fix(e2e): model portable Podman service activation
senthilr-nv 35f0e75
test(e2e): keep portable service cleanup linear
senthilr-nv 0bbca0b
test(e2e): exercise portable shim installation
senthilr-nv 1a7d6aa
merge: reconcile current main
senthilr-nv f5d2667
test(e2e): model cold portable socket activation
senthilr-nv 3853552
test(e2e): keep portable activation handoff linear
senthilr-nv 209cece
test(e2e): preserve portable socket authority
senthilr-nv 96c1a3b
merge: refresh portable profile fixture base
senthilr-nv eeb329d
test(e2e): clean portable fixture processes
senthilr-nv 90fbff5
test(e2e): fail closed on fixture cleanup
senthilr-nv d566677
merge: refresh portable profile fixture base
senthilr-nv 3f3d2ab
ci(e2e): clean portable workflow fixture
senthilr-nv 6c1dcfd
fix(e2e): serialize portable fixture refresh
senthilr-nv f164955
merge: refresh portable profile fixture base
senthilr-nv 758679e
merge(main): reconcile portable profile tests with current main
senthilr-nv 6de3e4d
test(e2e): bind portable fixture process identity
senthilr-nv bd7e9ba
merge(main): reconcile portable profile tests with current main
senthilr-nv ab3613a
test(e2e): keep portable fixture teardown linear
senthilr-nv 89f5a04
merge(main): reconcile portable profile tests with current main
senthilr-nv 4e252fb
fix(e2e): stabilize portable process identity checks
senthilr-nv File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| #!/usr/bin/env bash | ||
| # SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| set -euo pipefail | ||
|
|
||
| runtime_dir="${XDG_RUNTIME_DIR:?}" | ||
| service_dir="${runtime_dir}/podman" | ||
| socket_path="${service_dir}/podman.sock" | ||
| pid_file="${runtime_dir}/nemoclaw-podman-service.pid" | ||
| log_file="${runtime_dir}/nemoclaw-podman-service.log" | ||
|
|
||
| service_is_active() { | ||
| [[ -f "$pid_file" ]] || return 1 | ||
| local pid | ||
| pid="$(<"$pid_file")" | ||
| [[ "$pid" =~ ^[1-9][0-9]*$ ]] || return 1 | ||
| kill -0 "$pid" 2>/dev/null && [[ -S "$socket_path" ]] | ||
| } | ||
|
|
||
| stop_service() { | ||
| if [[ -f "$pid_file" ]]; then | ||
| local pid | ||
| pid="$(<"$pid_file")" | ||
| if [[ "$pid" =~ ^[1-9][0-9]*$ ]]; then | ||
| kill "$pid" 2>/dev/null || true | ||
| fi | ||
| fi | ||
| rm -f "$pid_file" "$socket_path" | ||
| } | ||
|
|
||
| start_socket() { | ||
| if service_is_active; then | ||
| return 0 | ||
| fi | ||
|
|
||
| stop_service | ||
| install -d -m 700 "$service_dir" | ||
| nohup podman system service --time=0 "unix://$socket_path" >"$log_file" 2>&1 & | ||
| echo $! >"$pid_file" | ||
|
|
||
| for ((attempt = 0; attempt < 100; attempt += 1)); do | ||
| if service_is_active; then | ||
| chmod 660 "$socket_path" | ||
| return 0 | ||
| fi | ||
| if ! kill -0 "$(<"$pid_file")" 2>/dev/null; then | ||
| break | ||
| fi | ||
| sleep 0.1 | ||
| done | ||
|
|
||
| stop_service | ||
| cat "$log_file" >&2 || true | ||
| return 1 | ||
| } | ||
|
|
||
| case "$*" in | ||
| "--user set-environment NETAVARK_FW=iptables CONTAINERS_CONF="*) | ||
| exit 0 | ||
| ;; | ||
| "--user try-restart podman.service") | ||
| if service_is_active; then | ||
| stop_service | ||
| start_socket | ||
| fi | ||
| ;; | ||
| "--user is-active --quiet podman.service") | ||
| if service_is_active; then | ||
| exit 0 | ||
| fi | ||
| exit 3 | ||
| ;; | ||
| "--user start podman.socket") | ||
| start_socket | ||
| ;; | ||
| *) | ||
| echo "unexpected user-service command: $*" >&2 | ||
| exit 64 | ||
| ;; | ||
| esac |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
119 changes: 119 additions & 0 deletions
119
test/e2e/support/portable-profile-systemctl-shim.test.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| // SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import { spawnSync } from "node:child_process"; | ||
| import fs from "node:fs"; | ||
| import path from "node:path"; | ||
| import { fileURLToPath } from "node:url"; | ||
|
|
||
| import { describe, expect, it } from "vitest"; | ||
|
|
||
| import { readYaml, type Workflow, type WorkflowStep } from "../../helpers/e2e-workflow-contract.ts"; | ||
|
|
||
| const REPO_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../../.."); | ||
| const SHIM_SOURCE = path.join(REPO_ROOT, "test/e2e/fixtures/portable-profile-systemctl-shim.sh"); | ||
|
|
||
| function writeExecutable(filePath: string, source: string): void { | ||
| fs.writeFileSync(filePath, source, { encoding: "utf8", mode: 0o700 }); | ||
| } | ||
|
|
||
| function portableLaunchProvisionStep(): WorkflowStep { | ||
| const workflow = readYaml<Workflow>(".github/workflows/portable-profile-e2e.yaml"); | ||
| const step = workflow.jobs["portable-launch"]?.steps?.find( | ||
| (candidate) => candidate.name === "Provision restricted rootless Linux runtime", | ||
| ); | ||
| expect(step).toBeDefined(); | ||
| return step!; | ||
| } | ||
|
|
||
| describe("portable profile systemctl fixture", () => { | ||
| it( | ||
| "reports inactive status, activates the socket, and reports active status (#9006)", | ||
| { | ||
| timeout: 15_000, | ||
| }, | ||
| () => { | ||
| const directory = fs.mkdtempSync("/tmp/portable-systemctl-shim-"); | ||
| const binDir = path.join(directory, "bin"); | ||
| const runtimeDir = path.join(directory, "runtime"); | ||
| const shim = path.join(binDir, "systemctl"); | ||
| fs.mkdirSync(binDir); | ||
| fs.mkdirSync(runtimeDir); | ||
| fs.copyFileSync(SHIM_SOURCE, shim); | ||
| fs.chmodSync(shim, 0o700); | ||
| writeExecutable( | ||
| path.join(binDir, "podman"), | ||
| `#!${process.execPath} | ||
| const net = require("node:net"); | ||
| const socketPath = process.argv.at(-1).replace("unix://", ""); | ||
| const server = net.createServer(); | ||
| server.listen(socketPath); | ||
| const stop = () => server.close(() => process.exit(0)); | ||
| process.on("SIGINT", stop); | ||
| process.on("SIGTERM", stop); | ||
| `, | ||
| ); | ||
| const env = { | ||
| ...process.env, | ||
| PATH: `${binDir}:${process.env.PATH ?? ""}`, | ||
| XDG_RUNTIME_DIR: runtimeDir, | ||
| }; | ||
| const systemctl = (args: string[]) => | ||
| spawnSync(shim, args, { encoding: "utf8", env, timeout: 15_000 }); | ||
|
|
||
| try { | ||
| expect(systemctl(["--user", "is-active", "--quiet", "podman.service"]).status).toBe(3); | ||
| expect( | ||
| systemctl([ | ||
| "--user", | ||
| "set-environment", | ||
| "NETAVARK_FW=iptables", | ||
| `CONTAINERS_CONF=${path.join(directory, "containers.conf")}`, | ||
| ]).status, | ||
| ).toBe(0); | ||
| const activation = systemctl(["--user", "start", "podman.socket"]); | ||
| expect(activation.status, activation.stderr).toBe(0); | ||
| expect(systemctl(["--user", "is-active", "--quiet", "podman.service"]).status).toBe(0); | ||
| } finally { | ||
| const pidFile = path.join(runtimeDir, "nemoclaw-podman-service.pid"); | ||
| if (fs.existsSync(pidFile)) { | ||
| const pid = Number(fs.readFileSync(pidFile, "utf8").trim()); | ||
| if (Number.isInteger(pid)) { | ||
| process.kill(pid, "SIGTERM"); | ||
| } | ||
| } | ||
| fs.rmSync(directory, { force: true, recursive: true }); | ||
| } | ||
| }, | ||
| ); | ||
|
|
||
| it("rejects an unexpected user-service command (#9006)", () => { | ||
| const runtimeDir = fs.mkdtempSync("/tmp/portable-systemctl-shim-"); | ||
| try { | ||
| const result = spawnSync(SHIM_SOURCE, ["--user", "restart", "podman.socket"], { | ||
| encoding: "utf8", | ||
| env: { ...process.env, XDG_RUNTIME_DIR: runtimeDir }, | ||
| }); | ||
| expect(result.status).toBe(64); | ||
| expect(result.stderr).toContain( | ||
| "unexpected user-service command: --user restart podman.socket", | ||
| ); | ||
| } finally { | ||
| fs.rmSync(runtimeDir, { force: true, recursive: true }); | ||
| } | ||
| }); | ||
|
|
||
| it("binds both portable profile lanes to the same systemctl fixture (#9006)", () => { | ||
| const provision = portableLaunchProvisionStep().run ?? ""; | ||
| expect(provision).toContain( | ||
| 'install -m 700 test/e2e/fixtures/portable-profile-systemctl-shim.sh "$shim_dir/systemctl"', | ||
| ); | ||
| expect(provision).toContain("systemctl --user start podman.socket"); | ||
| expect( | ||
| fs.readFileSync( | ||
| path.join(REPO_ROOT, "test/e2e/live/portable-profile-rootless-linux.test.ts"), | ||
| "utf8", | ||
| ), | ||
| ).toContain('"test/e2e/fixtures/portable-profile-systemctl-shim.sh"'); | ||
| }); | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.