[Bug]: `HAS_WINRM` always `False` in salt-cloud due to wrong distribution name in `importlib.metadata` lookup
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 15.7k
- Forks
- 5.6k
- Avg merge
- 2d 44m
- Merged PRs (30d)
- 80
Description
What happened?
Salt Version: 3006.27 (Sulfur)
Component: salt/utils/cloud.py
Affected feature: salt-cloud Windows deployment via WinRM (use_winrm: true)
Description
When deploying Windows VMs via salt-cloud with use_winrm: true, the deployment
fails with the following error regardless of whether pywinrm is installed:
[ERROR ] WinRM requested but module winrm could not be imported.
Ensure you are using version 0.3.0 or higher.
[ERROR ] Failed to start Salt on host <hostname>
The root cause is an incorrect distribution name passed to
importlib.metadata.version() in the HAS_WINRM detection block of
salt/utils/cloud.py. The code looks up the distribution name "winrm" but
the legitimate PyPI package is distributed under the name "pywinrm". These
are different distribution names. importlib.metadata.version("winrm") raises
PackageNotFoundError (a subclass of ImportError), which is silently caught
by the except ImportError block, setting HAS_WINRM = False before the
actual import winrm line is ever reached — even when pywinrm is correctly
installed and fully importable.
Affected Code
File: salt/utils/cloud.py
Approximate line: 83–95
# Set the minimum version of PyWinrm.
WINRM_MIN_VER = "0.3.0"
try:
import importlib
import importlib.metadata
# Verify WinRM 0.3.0 or greater
version = importlib.metadata.version("winrm") # ← BUG: wrong name
if not salt.utils.versions.compare(version, ">=", WINRM_MIN_VER):
HAS_WINRM = False
else:
HAS_WINRM = True
import winrm
from winrm.exceptions import WinRMTransportError
except ImportError:
HAS_WINRM = False
Steps to Reproduce
- Install Salt 3006.27 onedir on a Linux salt-master.
- Install
pywinrminto the Salt onedir Python environment:
sudo /opt/saltstack/salt/bin/pip install "pywinrm>=0.3.0"
- Confirm pywinrm is installed and importable:
sudo /opt/saltstack/salt/bin/python3.11 -c "import winrm; print(winrm.__version__)"
# Output: 0.5.0
- Confirm all sub-imports succeed:
sudo /opt/saltstack/salt/bin/python3.11 -c "
import winrm
from winrm.exceptions import WinRMTransportError
from winrm.protocol import Protocol
print('all imports OK')
"
# Output: all imports OK
- Check
HAS_WINRMin the salt module context:
sudo /opt/saltstack/salt/bin/python3.11 -c "
import salt.utils.cloud
print('HAS_WINRM:', salt.utils.cloud.HAS_WINRM)
"
# Output: HAS_WINRM: False
- Attempt a salt-cloud Windows VM deployment with
use_winrm: truein the
cloud profile. Deployment fails with the error shown above.
Root Cause Diagnosis
The importlib.metadata.version() call uses the wrong distribution name.
The PyPI distribution name is pywinrm; the importable module name is winrm.
These are not the same string.
sudo /opt/saltstack/salt/bin/python3.11 -c "
import importlib.metadata
try:
v = importlib.metadata.version('winrm')
print('found as winrm:', v)
except Exception as e:
print('not found as winrm:', type(e).__name__, e)
try:
v = importlib.metadata.version('pywinrm')
print('found as pywinrm:', v)
except Exception as e:
print('not found as pywinrm:', type(e).__name__, e)
"
Output:
not found as winrm: PackageNotFoundError No package metadata was found for winrm
found as pywinrm: 0.5.0
PackageNotFoundError is a subclass of ModuleNotFoundError → ImportError,
so it is silently caught by the except ImportError block. HAS_WINRM is set
to False and the actual import winrm statement that would have succeeded
is never reached.
Note: There is a separate spam/clone package on PyPI literally named winrm
(reported in https://github.com/diyan/pywinrm/issues/319) which is not the
legitimate pywinrm package. The importlib.metadata.version("winrm") lookup
is effectively checking for this spam package rather than the real one.
Expected Behavior
HAS_WINRM should be True when pywinrm >= 0.3.0 is installed and
importable. salt-cloud Windows deployments with use_winrm: true should
proceed normally.
Actual Behavior
HAS_WINRM is always False when pywinrm is installed via pip into the
onedir environment, because importlib.metadata.version("winrm") raises
PackageNotFoundError before the actual import is attempted.
Fix
Change the distribution name in the importlib.metadata.version() call from
"winrm" to "pywinrm":
# Before (incorrect)
version = importlib.metadata.version("winrm")
# After (correct)
version = importlib.metadata.version("pywinrm")
This is consistent with how the package has always been referenced in Salt's
own requirements files and documentation (pip install pywinrm).
Workaround
Until a fix is released, apply the following patch after each salt-master
update:
sudo sed -i \
's/importlib\.metadata\.version("winrm")/importlib.metadata.version("pywinrm")/' \
/opt/saltstack/salt/lib/python3.11/site-packages/salt/utils/cloud.py
# Verify
grep -n "importlib.metadata.version" \
/opt/saltstack/salt/lib/python3.11/site-packages/salt/utils/cloud.py
# Confirm fix
sudo /opt/saltstack/salt/bin/python3.11 -c "
import salt.utils.cloud
print('HAS_WINRM:', salt.utils.cloud.HAS_WINRM)
"
# Expected: HAS_WINRM: True
sudo systemctl restart salt-master
Related
- pywinrm spam package report: https://github.com/diyan/pywinrm/issues/319
- pywinrm PyPI: https://pypi.org/project/pywinrm/
- Salt Windows cloud deployment docs:
https://docs.saltproject.io/en/latest/topics/cloud/windows.html
Type of salt install
Official rpm
Major version
3006.x
What supported OS are you seeing the problem on? Can select multiple. (If bug appears on an unsupported OS, please open a GitHub Discussion instead)
windows-2025
salt --versions-report output
$ sudo salt --versions-report
Salt Version:
Salt: 3006.27
Python Version:
Python: 3.11.15 (main, Jun 29 2026, 22:21:49) [GCC 11.2.0]
Dependency Versions:
cffi: 2.0.0
cherrypy: 18.10.0
cryptography: 47.0.0
dateutil: 2.9.0.post0
docker-py: Not Installed
gitdb: 4.0.12
gitpython: 3.1.50
Jinja2: 3.1.6
libgit2: Not Installed
looseversion: 1.3.0
M2Crypto: Not Installed
Mako: Not Installed
msgpack: 1.1.2
msgpack-pure: Not Installed
mysql-python: Not Installed
packaging: 24.0
pycparser: 3.00
pycrypto: Not Installed
pycryptodome: 3.23.0
pygit2: Not Installed
python-gnupg: 0.5.6
PyYAML: 6.0.3
PyZMQ: 27.1.0
relenv: 0.22.16
smmap: 5.0.2
timelib: 0.3.0
Tornado: 6.5.5
ZMQ: 4.3.5
System Versions:
dist: rhel 9.8 Plow
locale: utf-8
machine: x86_64
release: 5.14.0-687.36.1.el9_8.x86_64
system: Linux
version: Red Hat Enterprise Linux 9.8 Plow
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in salt/utils/cloud.py around the HAS_WINRM detection block and inspect how importlib.metadata.version() checks the WinRM dependency. Reproduce the lookup and import checks in the issue using the Salt onedir Python environment. Done means HAS_WINRM is true with pywinrm installed and the existing salt-cloud WinRM deployment path can proceed.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- cloud
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- Under an hour
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100