test, doc, CI: Add tests, CI and documentation for cross-architecture support extension#1794
test, doc, CI: Add tests, CI and documentation for cross-architecture support extension#1794DaliborKr wants to merge 21 commits into
Conversation
|
Merge Failed. This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset. |
There was a problem hiding this comment.
Code Review
This pull request introduces support for cross-architecture containers in Toolbx via QEMU user-mode emulation, adding an --arch flag to the create, enter, and run commands. The implementation includes logic for pulling non-native images using Skopeo, configuring binfmt_misc during container initialization, and a comprehensive suite of system tests. Feedback identifies a typo in a Zuul job name that would break CI, a bug where the architecture flag is ignored during automatic container creation in toolbox run, and a critical logic error in the X86_64 ELF mask that prevents correct binfmt_misc matching.
| run: playbooks/unit-test.yaml | ||
|
|
||
| - job: | ||
| name: system-test-fedora-rawhide-non-native-architecture-architecture |
There was a problem hiding this comment.
| } | ||
|
|
||
| if err := createContainer(container, image, release, "", false); err != nil { | ||
| if err := createContainer(container, image, release, "", architecture.GetArchConfigDefault(), false); err != nil { |
There was a problem hiding this comment.
When toolbox run is called on a non-existent container, it attempts to create it automatically. However, it is currently hardcoded to use the default host architecture (architecture.GetArchConfigDefault()), ignoring any --arch flag provided by the user. This will result in a native container being created even when a cross-architecture one was requested. The runCommand function should be updated to accept and pass the resolved archID or archConfig.
| NameOCI: "amd64", | ||
| Aliases: []string{"x86_64", "amd64"}, | ||
| ELFMagic: []byte{0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x3e, 0x00}, | ||
| ELFMask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff}, |
There was a problem hiding this comment.
The ELFMask for X86_64 at bytes 5 and 6 (Data encoding and Version) is set to 0xfe. Since the ELFMagic for these bytes is 0x01, the binfmt_misc matching logic (data & mask) == magic will always fail because (data & 0xfe) will always have a 0 in the least significant bit, making it impossible to equal 0x01. These should likely be 0xff to match the standard ELF64 LSB header exactly, similar to the Aarch64 definition.
| ELFMask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff}, | |
| ELFMask: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff}, |
| return false, false, fmt.Errorf("failed to verify: image %s does not support architecture %s or the image does not exists at all", | ||
| imageFull, expectedArchName) |
There was a problem hiding this comment.
Typo in the error message: "exists" should be "exist".
| return false, false, fmt.Errorf("failed to verify: image %s does not support architecture %s or the image does not exists at all", | |
| imageFull, expectedArchName) | |
| return false, false, fmt.Errorf("failed to verify: image %s does not support architecture %s or the image does not exist at all", | |
| imageFull, expectedArchName) |
Add unit tests for functionality introduced in PRs containers#1780, containers#1782, containers#1783, and containers#1784: - pkg/shell: Test RunWithExitCode2 and RunContextWithExitCode2 (containers#1780) - pkg/architecture/architecture: Test ParseArgArchValue, GetArchNameOCI, getArchNameBinfmt, getArchitecture, ImageReferenceGetArchFromTag, and isStaticallyLinkedELF (containers#1782, containers#1783) - pkg/architecture/binfmt_misc: Test bytesToEscapedString, buildRegistrationString, and getDefaultRegistration (containers#1782) - pkg/skopeo: Test GetSize, GetSizeHuman, VerifyArchitectureMatch, and JSON unmarshaling with real skopeo inspect output (containers#1784) containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
…ainers Add helper functions and image caching support for running Bats system tests against cross-architecture (non-native) Toolbx containers, using QEMU user-mode emulation via binfmt_misc. In helpers.bash: - Add 'non-native' to TOOLBX_TEST_SYSTEM_TAGS_ALL so that the new tests are included when all tags are run - Add _pull_and_cache_distro_image_cross_arch() that uses 'skopeo copy --override-arch' to cache a foreign architecture image variant, with the cache directory suffixed by the architecture name to avoid collisions with native images - Add pull_distro_image_cross_arch() and pull_default_image_cross_arch() to load cached cross-arch images into Podman's container storage with architecture-suffixed tags - Add create_distro_container_cross_arch() and create_default_container_cross_arch() for creating non-native containers using the --arch flag - Add pull_default_image_and_copy_to() that copies the default image under a different name, for testing custom image names with architecture-like suffixes - Add skip_if_no_cross_arch_support() that checks for QEMU and binfmt_misc availability and skips the test if not present - Add get_cross_arch() that maps the host architecture to a suitable foreign architecture for testing (x86_64 → arm64, aarch64 → amd64) - Add oci_arch_to_binfmt() for converting OCI architecture names to their binfmt_misc equivalents (arm64 → aarch64, amd64 → x86_64) - Add build_restricted_path() that creates a directory of symlinks to all host executables except specified patterns, for testing error paths when tools like QEMU or skopeo are missing In setup_suite.bash: - Add a 'non-native' tag block that caches the default system image, a Fedora 44 image, and their cross-arch variants for use by the non-native test suites containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
…mands Add system tests for the cross-architecture extensions to the 'create' and 'run' (including the entry point init-container) commands introduced in PRs containers#1787, containers#1788, and containers#1789. The 3xx numbering range mirrors the 1xx range for native command tests, with 301 corresponding to 101 (create) and 304 to 104 (run). 301-create.bats (28 tests) covers: - Basic cross-arch container creation with --arch - Interaction with --distro/--release, --image, and --container flags - binfmt architecture name aliases (e.g., aarch64 resolves to arm64) - Host architecture passed to --arch is treated as native - Architecture-suffixed image tags (inference and conflict detection) - Native and cross-arch container coexistence - Entry point arguments (--arch, --arch-emulator-path) - Error paths: unsupported architecture, case sensitivity, conflicting --arch and image tag, duplicate container, missing QEMU, fake QEMU (shell script instead of ELF), missing skopeo 304-run.bats (23 tests) covers: - Smoke tests with true(1) and uname(1) architecture verification - /run/.toolboxenv existence, --container targeting, container reuse - binfmt_misc mount and QEMU registration inside the container - Exit code propagation (false, exit 2) - Entry point error and delay handling - Stop and restart re-initialization - sudo inside cross-arch container - Native and cross-arch container coexistence without interference - QEMU emulator fallback paths (missing recorded path, /usr/bin fallback) All tests use the 'non-native' Bats file tag for selective execution. containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
49dac73 to
f3ca4f7
Compare
Add system tests that verify the runtime environment inside cross-architecture Toolbx containers matches the behavior of native ones. The 4xx numbering range mirrors the 2xx range for native runtime environment tests: 401 (IPC), 403 (network), 406 (user), 410 (ulimit), 411 (D-Bus), 420 (environment variables), 430 (CDI), 450 (Kerberos), and 470 (RPM). Each test creates a non-native container verifies that the corresponding host integration feature (namespace sharing, DNS, user mapping, resource limits, D-Bus session/system buses, environment variable forwarding, CDI device access, Kerberos configuration, and RPM macros) works correctly under QEMU emulation. All tests use the 'non-native' Bats file tag for selective execution. containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
…re tests Add CI infrastructure to run the non-native architecture system tests on Zuul and GitHub Actions. Add qemu-user-static to the Fedora dependency playbook so that QEMU user-mode emulation is available on CI nodes. Add the system-test-non-native.yaml playbook that runs 'bats --filter-tags non-native' with the TOOLBX_TEST_SYSTEM_TAGS environment variable set to 'non-native' (3xx and 4xx non-native test files), following the same pattern used by the existing playbooks for commands-options and runtime-environment test groups [1]. Add non-native-architecture jobs for all Fedora Rawhide, Fedora 43 and Fedora 42. Add the 3xx and 4xx non-native test files to the GitHub Actions Ubuntu workflow. [1] containers@987f5e259289b4b3 containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add the --arch flag to the manual pages for create, enter and run. Update the init-container manual page with the --arch and --arch-emulator-path flags, and add a description of the QEMU user-mode emulation setup performed during container initialization. Add a new "Cross-architecture containers support" section to the main toolbox(1) manual page, describing the feature and listing the supported architectures. containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
|
Merge Failed. This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset. |
The existing RunContextWithExitCode() wraps all errors from exec.Command in generic "failed to invoke" messages, which prevents callers from distinguishing between actual error types. Add RunContextWithExitCode2() and RunWithExitCode2() that return errors with their original types intact, including for ExitError. This allows callers to use errors.Is() and errors.As() to handle specific failure modes. For example, detecting a missing skopeo binary (exec.ErrNotFound) or an ENOEXEC error from inside non native containers, when an emulator is not set correctly. These new functions are meant to replace its original versions in the future. containers#1780 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
In /src/cmd/create.go, the same pattern of spinner creation and nil-safe stopping is repeated. Extract this into startSpinner() and stopSpinner() helper functions so that future callers can use spinners without duplicating the code. Replace the existing inline spinner code in createContainer() and pullImage() with calls to these new helpers. containers#1781 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
…atching Add IsSupportedDistroImage(), which iterates over all supported distros and checks if the image basename matches any of them. This will be used by the architecture resolution code to decide whether to parse architecture suffixes from image tags, as this should be done only for natively supported images [1]. [1] Toolbx supported distributions: https://containertoolbx.org/distros/ containers#1781 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Introduce the architecture package that represents the core of the Toolbx cross-architecture support, which is based on user-mode emulation using QEMU and binfmt_misc. The Architecture struct collects all per-architecture data (ELF magic/mask, OCI and binfmt naming, aliases, binfmt registration parameters) into a single map. Architectures present in the supportedArchitectures map represent the set of supported architectures within Toolbx. Define architecture ID constants NotSpecified, Aarch64, Ppc64le, and X86_64, along with their supportedArchitectures entries. Add core query functions: - ParseArgArchValue() for resolving user-supplied architecture strings - GetArchNameBinfmt() and GetArchNameOCI() for name lookups (one architecture can have multiple valid names [1]) - HasContainerNativeArch() for comparing against the host - ImageReferenceGetArchFromTag() for extracting architecture from image tag suffixes like "42-aarch64" for architecture detection Expose the HostArchID package variable, which is set in the init() function, so the variable can be accessed in the early init() state from every inheritor that utilizes the architecture package (HostArchID serves as a default value for initContainer --arch flag), and the Config struct for preserving the architecture ID and the QEMU emulator path, through the call chain. [1] https://itsfoss.com/arm-aarch64-x86_64/ containers#1782 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Cross-architecture containers need QEMU binfmt_misc handlers registered within the container so that non-native architecture binaries can be executed via the host's kernel. Add the Registration struct that models a binfmt_misc registration entry, including name, magic type, offset, ELF magic/mask bytes, interpreter path, and flags. Add functions: - MountBinfmtMisc() to mount the sanboxed binfmt_misc filesystem inside a container, which enables setting the C flag in binfmt_misc registration without affecting the host system. The C flag presents a threat of privilege escalation when registered on the host, that why we want to have it isolated [1] - getDefaultRegistration() to fill a Registration struct containing all necessary binfmt_misc information taken from the architecture.supportedArchitectures data - RegisterBinfmtMisc() to write the registration string to /proc/sys/fs/binfmt_misc/register, which makes the non-native binary perception active - bytesToEscapedString() helper that formats byte slices into the \xHH-escaped string format required by the binfmt_misc register interface [1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=21ca59b365c0 containers#1782 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Before creating or initializing a cross-architecture container, the system must be checked for the required QEMU emulator and binfmt_misc registration. This prevents users from creating or running non-native containers when their host system doesn't meet the requirements, and provides users with an informative error message referring to the problem. Add IsArchSupportedOnCreation(), which searches for a statically linked QEMU binary on the host using exec.LookPath() and verifies that a matching binfmt_misc registration exists. It returns the path to the QEMU binary for use during container creation, which is meant to be passed to the init-container and registered through sandboxed binfmt_misc within the container. Add IsArchSupportedOnInitialization() which performs similar checks from inside the container, looking at the interpreter path passed from the host and falling back to standard host-mounted locations under /run/host/usr/bin/. Add isStaticallyLinkedELF() helper that uses debug/elf to verify a binary is statically linked. Only a statically linked QEMU interpreter can be used, because a dynamically linked one would cause the kernel to attempt to resolve its host-native shared libraries (such as libc.so) within the container, resulting in an immediate crash. Add validateBinfmtRegistration(), which checks for the presence of qemu-<arch> entries in binfmt_misc (or qemu-<arch>-static, since it can differ based on the system). containers#1783 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add Architecture and NameFull fields to the Skopeo Image struct so that callers can inspect the architecture of a remote image. Move the image size computation from the /cmd layer into GetSize() and GetSizeHuman() methods on Image, since the skopeo package owns the layer data. Add VerifyArchitectureMatch() method to Image that validates the image's architecture field against an expected architecture ID. The purpose of this function is to check whether the image architecture matches the demanded architecture before it is pulled. Specifically, this verification applies to the images that support only a single architecture (they are not part of a multi-platform manifest list), because the skopeo inspect proceeds successfully even when the value of a flag --override-arch does not match the actual image architecture (for a multi-architecture image the skopeo inspect with not-matching --override-arch would fail). Like this, the user can be prevented from incompatible images. containers#1784 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Change Inspect() to accept archID and authfile parameters. When the requested architecture differs from the host's, --override-arch is passed to skopeo, which then inspects the correct manifest in a multi-arch image (if it exists for the given architecture, otherwise the inspection fails). It also uses RunContextWithExitCode2() so callers can detect a missing skopeo binary via errors.Is(err, exec.ErrNotFound), which is only a soft dependency of the Toolbx package, as it is not required for running native containers. Add CopyOverrideArch(), which uses 'skopeo copy --override-arch' to pull a specific architecture variant of a multi-arch image into Podman's local container storage. This is used instead of 'podman pull' because Podman does not support pulling a foreign architecture image into a locally addressable name. The way in which the cross-arch extension chooses the name for non-native images (and also containers) is described in the discussion at [1] [1] containers/podman#27780 (comment) containers#1784 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
…and names Add resolveArchitectureID(), which combines the --arch command-line flag with architecture detection from image tag suffixes (e.g., "fedora-toolbox:42-aarch64"). This detection applies only to images from distributions that Toolbx explicitly supports (see [1]), to avoid a false architecture approach on custom images where a dash-separated component might not represent an architecture, since there is no standard set regarding preserving architecture in the tag (see detailed explanation at [2]). When both sources specify an architecture, it validates that they do not conflict. Add resolveImageNameWithArchitectureSuffix(), which appends the OCI architecture name to supported distro image references when the target architecture differs from the host, to ensure the local Toolbx images naming convention [2]. Again, this applies only to supported distros. [1] https://containertoolbx.org/distros/ [2] containers/podman#27780 (comment) containers#1786 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Change resolveContainerAndImageNames() to accept an archID parameter. When the target architecture is non-native, and the container name was auto-generated (was not set by a user), append the architecture suffix to the container name (e.g., "fedora-toolbox-arm64") to distinguish it from native containers. Temporarily update the callers of resolveContainerAndImageNames() to pass in architecture.HostArchID to the updated signature, to maintain a default native behavior. Once implemented, the --arch argument in the callers will pass the actual architecture information. containers#1786 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add the --arch flag to the 'create' command, allowing users to create Toolbx containers for architectures different from the host (e.g., 'toolbox create --arch arm64'). Utilize the architecture resolution pipeline in create() by using resolveArchitectureID() (added in [1]) to determine the target architecture from the --arch flag and image tags. Validate host support via IsArchSupportedOnCreation() (added in [2]), which checks for the required QEMU emulator and binfmt_misc registration. Pass architecture ID to resolveContainerAndImageNames() (updated in [1]) so that non-native containers get architecture-suffixed names. Update pullImage() to handle cross-architecture image pulling: when the target architecture is non-native, use skopeo.CopyOverrideArch() (added in [3]) instead of podman.Pull(), since Podman does not support pulling foreign architecture images into locally addressable names. The need for this is explained in a discussion in [4]. Add a 'toolbox-arch' label to created containers to record the target architecture in OCI format. Extract the image pull error formatting into createErrorImagePull() in utils.go to avoid duplication between the native and cross-arch pull paths. Update the createContainer() call in run.go to pass the default architecture config via GetArchConfigDefault(), maintaining the existing native-architecture behavior. [1] containers#1786 [2] containers#1783 [3] containers#1784 [4] containers/podman#27780 containers#1787 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Rework the image download prompt flow to support architecture verification before pulling non-native images. The new implementation ensures that the image inspection completes for the non-native creation path before it is pulled, so the image's architecture can be verified. The previous implementation used promptForDownloadError as a control flow mechanism between the first and second download prompts. Replace this with the pullImageDecision enum (pullNo, pullYes, pullUnknown) for clearer three-state signaling. Replaced getImageSizeFromRegistryAsync() with getImageFromRegistryAsync(), which now returns the full skopeo.Image struct instead of just the image size string. It calls skopeo.Inspect() (updated in [1]), making image metadata available throughout the download prompt flow for both size display and architecture verification in a single inspect call. Use Image.GetSizeHuman() (added in [1]) for image size display in the second download prompt, replacing the local size computation. Update showPromptForDownloadFirst() to return (pullImageDecision, *skopeo.Image, error). For non-native architectures, when the user confirms the download, the function now waits for the skopeo inspect to complete (with a spinner) before returning, ensuring that architecture verification can happen before the pull begins. Update pullImage() to verify the image architecture before pulling non-native images by calling VerifyArchitectureMatch() (added in [1]) to catch incompatible single-architecture images. Handle the case where the inspect returns nil (multi-arch manifest has no matching variant) with an explicit error. Detect a missing skopeo binary via exec.ErrNotFound, which is only a soft dependency of the Toolbx package, as it is not required for running non-native containers, and report it through createErrorSkopeoNotFound() added in utils.go. [1] containers#1784 containers#1787 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add the --arch and --arch-emulator-path flags to the init-container command, passed from the create command when creating a cross-architecture container. The --arch flag defaults to the host architecture ID so that existing native containers continue to work without changes. When the container's architecture differs from the host, the init-container entry point configures QEMU emulation inside the container before any foreign-architecture binaries can run: 1. Validate QEMU emulation by running the 'true' command, which fails with ENOEXEC if the host's binfmt_misc registration is not working (detected via RunWithExitCode2() added in [1]), because it is necessary to have host emulation working to emulate the binfmt_misc registration in the following step. 2. Mount a fresh binfmt_misc filesystem inside the container via MountBinfmtMisc() (added in [2]) to create a sandboxed binfmt_misc registration with the C flag. 3. Validate architecture support via IsArchSupportedOnInitialization() (added in [3]), which verifies the QEMU interpreter at the host-mounted path under /run/host. 4. Register the QEMU interpreter with the C flag via RegisterBinfmtMisc() (added and explained in [2]) The binfmt_misc registration is performed inside the container rather than relying on the host's registration, as explained in [2]. Update showEntryPointLog() in run.go to propagate lines prefixed with 'Warning:' to stderr on the host, instead of treating them as errors. This is needed because the cross-architecture initialization may emit warnings that should be visible to the user but are not fatal. [1] containers#1780 [2] containers#1782 [3] containers#1783 containers#1788 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add the --arch / -a flag to the enter command, allowing users to enter cross-architecture containers by specifying the target architecture (e.g., toolbox enter --arch arm64). Can be used with flags --distro and --release, just as for container creation. The flag value is resolved through resolveArchitectureID() (added in [1]) and passed to resolveContainerAndImageNames() (updated for cross-arch in [1]) so that it resolves to the architecture-suffixed container name. [1] containers#1786 containers#1789 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add the --arch / -a flag to the run command, allowing users to run commands inside cross-architecture containers by specifying the target architecture (e.g., toolbox run --arch arm64 uname -m). Can be used with flags --distro and --release, just as for container creation. The flag value is resolved through resolveArchitectureID() (added in [1]) and passed to resolveContainerAndImageNames() (updated for cross-arch in [1]) so that it resolves to the architecture-suffixed container name. [1] containers#1786 containers#1789 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add unit tests for functionality introduced in PRs containers#1780, containers#1782, containers#1783, and containers#1784: - pkg/shell: Test RunWithExitCode2 and RunContextWithExitCode2 (containers#1780) - pkg/architecture/architecture: Test ParseArgArchValue, GetArchNameOCI, getArchNameBinfmt, getArchitecture, ImageReferenceGetArchFromTag, and isStaticallyLinkedELF (containers#1782, containers#1783) - pkg/architecture/binfmt_misc: Test bytesToEscapedString, buildRegistrationString, and getDefaultRegistration (containers#1782) - pkg/skopeo: Test GetSize, GetSizeHuman, VerifyArchitectureMatch, and JSON unmarshaling with real skopeo inspect output (containers#1784) containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
…ainers Add helper functions and image caching support for running Bats system tests against cross-architecture (non-native) Toolbx containers, using QEMU user-mode emulation via binfmt_misc. In helpers.bash: - Add 'non-native' to TOOLBX_TEST_SYSTEM_TAGS_ALL so that the new tests are included when all tags are run - Add _pull_and_cache_distro_image_cross_arch() that uses 'skopeo copy --override-arch' to cache a foreign architecture image variant, with the cache directory suffixed by the architecture name to avoid collisions with native images - Add pull_distro_image_cross_arch() and pull_default_image_cross_arch() to load cached cross-arch images into Podman's container storage with architecture-suffixed tags - Add create_distro_container_cross_arch() and create_default_container_cross_arch() for creating non-native containers using the --arch flag - Add pull_default_image_and_copy_to() that copies the default image under a different name, for testing custom image names with architecture-like suffixes - Add skip_if_no_cross_arch_support() that checks for QEMU and binfmt_misc availability and skips the test if not present - Add get_cross_arch() that maps the host architecture to a suitable foreign architecture for testing (x86_64 → arm64, aarch64 → amd64) - Add oci_arch_to_binfmt() for converting OCI architecture names to their binfmt_misc equivalents (arm64 → aarch64, amd64 → x86_64) - Add build_restricted_path() that creates a directory of symlinks to all host executables except specified patterns, for testing error paths when tools like QEMU or skopeo are missing In setup_suite.bash: - Add a 'non-native' tag block that caches the default system image, a Fedora 44 image, and their cross-arch variants for use by the non-native test suites containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
…mands Add system tests for the cross-architecture extensions to the 'create' and 'run' (including the entry point init-container) commands introduced in PRs containers#1787, containers#1788, and containers#1789. The 3xx numbering range mirrors the 1xx range for native command tests, with 301 corresponding to 101 (create) and 304 to 104 (run). 301-create.bats (28 tests) covers: - Basic cross-arch container creation with --arch - Interaction with --distro/--release, --image, and --container flags - binfmt architecture name aliases (e.g., aarch64 resolves to arm64) - Host architecture passed to --arch is treated as native - Architecture-suffixed image tags (inference and conflict detection) - Native and cross-arch container coexistence - Entry point arguments (--arch, --arch-emulator-path) - Error paths: unsupported architecture, case sensitivity, conflicting --arch and image tag, duplicate container, missing QEMU, fake QEMU (shell script instead of ELF), missing skopeo 304-run.bats (23 tests) covers: - Smoke tests with true(1) and uname(1) architecture verification - /run/.toolboxenv existence, --container targeting, container reuse - binfmt_misc mount and QEMU registration inside the container - Exit code propagation (false, exit 2) - Entry point error and delay handling - Stop and restart re-initialization - sudo inside cross-arch container - Native and cross-arch container coexistence without interference - QEMU emulator fallback paths (missing recorded path, /usr/bin fallback) All tests use the 'non-native' Bats file tag for selective execution. containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add system tests that verify the runtime environment inside cross-architecture Toolbx containers matches the behavior of native ones. The 4xx numbering range mirrors the 2xx range for native runtime environment tests: 401 (IPC), 403 (network), 406 (user), 410 (ulimit), 411 (D-Bus), 420 (environment variables), 430 (CDI), 450 (Kerberos), and 470 (RPM). Each test creates a non-native container verifies that the corresponding host integration feature (namespace sharing, DNS, user mapping, resource limits, D-Bus session/system buses, environment variable forwarding, CDI device access, Kerberos configuration, and RPM macros) works correctly under QEMU emulation. All tests use the 'non-native' Bats file tag for selective execution. containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
…re tests Add CI infrastructure to run the non-native architecture system tests on Zuul and GitHub Actions. Add qemu-user-static to the Fedora dependency playbook so that QEMU user-mode emulation is available on CI nodes. Add the system-test-non-native.yaml playbook that runs 'bats --filter-tags non-native' with the TOOLBX_TEST_SYSTEM_TAGS environment variable set to 'non-native' (3xx and 4xx non-native test files), following the same pattern used by the existing playbooks for commands-options and runtime-environment test groups [1]. Add non-native-architecture jobs for all Fedora Rawhide, Fedora 43 and Fedora 42. Add the 3xx and 4xx non-native test files to the GitHub Actions Ubuntu workflow. [1] containers@987f5e259289b4b3 containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
Add the --arch flag to the manual pages for create, enter and run. Update the init-container manual page with the --arch and --arch-emulator-path flags, and add a description of the QEMU user-mode emulation setup performed during container initialization. Add a new "Cross-architecture containers support" section to the main toolbox(1) manual page, describing the feature and listing the supported architectures. containers#1794 Signed-off-by: Dalibor Kricka <dalidalk@seznam.cz>
f3ca4f7 to
d10e9eb
Compare
This is PR 10/10 in a series adding cross-architecture container support using QEMU and binfmt_misc.
Depends on: #1789 (cmd/enter, cmd/run: Add --arch flag for cross-arch containers support)
Please review #1789 first. The new commits in this PR are:
Summary
Introduces unit tests, system (BATS) tests, CI configuration and manual page documentation for the cross-architecture container support introduced in PRs #1780 through #1789.