Skip to content

Add native Windows arm64 minion MSI support. - #70003

Open
knightmare2600 wants to merge 5 commits into
saltstack:masterfrom
knightmare2600:windows-arm64-msi
Open

Add native Windows arm64 minion MSI support.#70003
knightmare2600 wants to merge 5 commits into
saltstack:masterfrom
knightmare2600:windows-arm64-msi

Conversation

@knightmare2600

Copy link
Copy Markdown

What does this PR do?

What issues does this PR fix or reference?

This PR allows a native arm64 salt minion to be compiled on Widows ARM64.

Previous Behavior

The AMD64 minion works fine under emulation, but a native arm64 build to match the Linux variants would be good.

New Behavior

Salt minion runs natively, as opposed to under emulation on arm64 Windows

Merge requirements satisfied?

  • What the change does (native arm64 MSI build support — wire-up across tools/ci.py, the PowerShell packaging scripts, and the WiX .wxs)
  • The dependency: Depends on Windows arm64 support relenv#318 in the body.
  • Why it's a draft: this repo's CI can't actually exercise the arm64 path yet — cicd/shared-gh-workflows-context.yml pins a specific released relenv version, and there's no release with arm64 support to point at until Documention misleading #318 merges and relenv cuts one.

Commits signed with GPG?

No

NB: mssql module unavailable on arm64 (no pymssql wheel), and the VC++ runtime / SSM service binary run under Windows 11 ARM64's x64 emulation rather than natively, since neither has a published native build yet.

Adds arm64 to the windows build matrix (tools/ci.py) and fixes the
architecture-detection and build-plumbing bugs that blocked it from
actually working:

- tools/pkg/build.py: arm64 accepted by the windows build command's
  --arch choices; fixed onedir-dependencies wrongly remapping
  arm64 -> aarch64 for windows too - that's a linux-only relenv
  convention, and applying it to windows made relenv reject the arch
  outright.
- pkg/windows/build.ps1, build_python.ps1: ValidateSet now allows
  arm64. build_python.ps1's arch mapping was a binary
  if-x64-else-x86, so arm64 silently fell into the x86 branch.
- pkg/windows/prep_salt.ps1, install_vs_buildtools.ps1,
  nsis/build_pkg.ps1: architecture was derived from
  platform.architecture()[0] (pointer width only - "64bit" for both
  amd64 and arm64), switched to platform.machine(). No native arm64
  build of ssm.exe or the VC++ redistributable exists in
  salt-windows-deps yet; prep_salt.ps1 falls back to the x64 builds,
  which run under Windows 11 on Arm's x64 emulation, tracked
  separately from the true reported architecture via DOWNLOAD_ARCH.
  install_vs_buildtools.ps1 also had a VS-detection gap: it relies
  solely on the MSFT_VSInstance CIM class, which isn't registered on
  the windows-11-arm runner image even though VS 2022 ships
  pre-installed there - it was wrongly concluding VS was missing and
  bootstrapping an unrelated VS 2017 install from scratch. Falls back
  to vswhere.exe, present on every GitHub-hosted Windows image
  regardless of CIM provider support.
- build-salt-onedir.yml, build-deps-ci-action.yml: windows jobs route
  the arm64 matrix entry to the windows-11-arm hosted runner. The
  dependency-cache job needed this too or it would hard-fail: it runs
  the onedir's own python to build a venv, and x64 runners cannot
  execute arm64 binaries at all (no emulation in that direction).
pymssql has no win_arm64 wheel at any version, and Salt's onedir build
forbids compiling it from source (--only-binary), so pip has nothing
to install and the arm64 onedir build fails outright:
"Could not find a version that satisfies the requirement pymssql==2.3.11
(from versions: none)". Add a platform_machine != 'ARM64' marker so pip
just skips it there instead. The mssql execution/state module is
unavailable on arm64 minions until pymssql publishes an arm64 build;
every other module is unaffected.
Installing Salt ran pip via Start-Process -WindowStyle Hidden with no
output redirection at all, so any pip failure showed only bare
"Failed" with zero diagnostic information - success was inferred
solely from whether salt-minion.exe existed afterward, not from pip's
actual exit code. A real gap for every architecture, found while
diagnosing arm64 onedir build failures.
pkg/windows/build.ps1, msi/build_pkg.ps1: architecture was derived
from platform.architecture()[0] (pointer width only - "64bit" for
both amd64 and arm64), switched to platform.machine(). The WIN64/
ARCHITECTURE/ARCH_AKA/PROGRAMFILES parallel arrays used to drive WiX
extended to a real third (arm64) value so the resulting MSI is
correctly tagged as native ARM64 rather than mislabeled AMD64.

installer.nsi's own architecture detection (separate from
build_pkg.ps1's) only recognizes x64/AMD64/x86 and silently falls back
to x86 for anything else, producing an installer whose filename
build_pkg.ps1 can't find - build.ps1 runs NSIS before the MSI and
aborts the whole script on failure, so this blocked the MSI build
entirely. NSIS was never actually requested for arm64; skip building
it there rather than widen scope into fixing installer.nsi for a
component nobody asked for (build-packages.yml's NSIS upload step
skips accordingly, since there's nothing to upload).

Product.wxs never declared Package/@platform at all. WiX's implicit
default handles the existing amd64/x86 builds fine (this pipeline has
shipped MSIs for years without it) but doesn't recognize arm64 as a
value to infer from candle's -arch switch, silently defaulting to
x86 - light.exe then rejected the 64-bit VC++ CRT merge module with
"is a 64-bit merge module but the product consuming it is 32-bit."
Declare it explicitly via an ARCHITECTURE preprocessor define
build_pkg.ps1 passes to candle (exactly the string passed to -arch),
removing the ambiguity for every architecture rather than relying on
inference for whichever ones WiX happens to recognize.

Separately: merge modules enforce exact architecture matching at
build time (a Windows Installer rule, not a WiX limitation) - an x64
merge module cannot be merged into an arm64-declared product even
though the resulting DLLs run fine under Windows 11 on Arm's x64
emulation. No native arm64 VC++ CRT merge module is published
anywhere yet, so for arm64, embed vcredist_x64_2022.exe (the
standalone installer, for the same reason already relied on as a
fallback elsewhere in this pipeline) as Binary data and launch it via
a deferred CustomAction after InstallFiles instead of merging an
.msm. amd64/x86 are unaffected - still use the existing merge-module
path.
knightmare2600 added a commit to knightmare2600/example_music_infra that referenced this pull request Aug 10, 2026
Robert's added a custom ARM64 Windows Salt minion MSI, built by tracking
three still-open, unmerged upstream PRs (confirmed live against the
GitHub API, none merged as of 2026-08-10):
  - saltstack/salt#70003 -- native Windows arm64 minion MSI support
  - saltstack/relenv#318 -- Windows arm64 support (relenv, Salt's own
    relocatable Python builder, a real dependency of the minion build)
  - pymssql/pymssql#1013 -- native Windows arm64 wheel builds (a Salt
    dependency needed for the build to complete on arm64 at all)

Renamed the existing MSI from the unsuffixed Salt-Minion-Setup.msi to
Salt-Minion-Setup-x86_64.msi, and wired 82-salt-minion.yml to select
Salt-Minion-Setup-{{ host_arch }}.msi -- reuses tasks/arch_facts.yml's
own host_arch fact and naming convention (x86_64/arm64/x86) rather than
inventing a new one, matching 50-binaries.yml's already-established
pattern for exactly this problem. Added a loud, explicit failure for any
architecture with no matching MSI at all, instead of a confusing win_copy
"file not found" further down the task list.

Also fixes a real harness gap check_playbook_dir_paths.py had: its own
tail-matching regex excluded "{"/"}" outright, so it silently truncated
and misreported the new host_arch-templated path as unresolvable -- a
false positive, not a real bug. Fixed generically (glob-match any embedded
{{ ... }} Jinja expression, require at least one real file to match)
rather than special-cased to this one file, so it holds for any future
playbook_dir path with a runtime-templated segment. Both the pass and
fail paths of the fix tested directly before landing.
@knightmare2600
knightmare2600 marked this pull request as ready for review August 12, 2026 07:53
@knightmare2600
knightmare2600 requested a review from a team as a code owner August 12, 2026 07:53
@knightmare2600

Copy link
Copy Markdown
Author

I have also created the PR at pymssql/pymssql#1013 to allow native arm64 mssql wheel builds.

I am fairly new to making multiple PRs over multiple projects, but on my own checks with that PR, it allows the native arm64 Windows builds of mssql modules, which gives feature parity with the amd64 builds.

@twangboy

Copy link
Copy Markdown
Contributor

I added an Arm64 version of the Salt Service Manager here... that will get us a little closer: https://github.com/saltstack/salt-windows-deps/tree/main/ssm

@twangboy

Copy link
Copy Markdown
Contributor

Let's make this on the 3006.x branch

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants