salt
salt copied to clipboard
[BUG] pkg.installed (aptpkg latest_version) UnboundLocalError on foreign-arch package
Description
When installing WINE under Debian on an amd64 machine, you usually need to pull i386 packages, too. However, the pkg.installed
state seems to struggle with packages only available in foreign architectures, at least when you specify them without their architecture name.
Setup
- on-prem machine
- onedir packaging
- masterless
Steps to Reproduce the behavior On an amd64 machine, try a state like this:
WINE packages:
cmd.run:
- unless:
# Don't run if already enabled.
- dpkg --print-foreign-architectures | grep -Fqx i386
- name: dpkg --add-architecture i386 && apt update
pkg.installed:
- require:
- cmd: WINE packages
- pkgs:
- fonts-wine
- libwine
- libwine:i386
- wine
- wine32
- wine64
This will fail as follows:
ID: WINE packages
Function: pkg.installed
Result: False
Comment: An exception occurred in this state: Traceback (most recent call last):
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/state.py", line 2428, in call
ret = self.states[cdata["full"]](
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/loader/lazy.py", line 160, in __call__
ret = self.loader.run(run_func, *args, **kwargs)
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/loader/lazy.py", line 1269, in run
return self._last_context.run(self._run_as, _func_or_method, *args, **kwargs)
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/loader/lazy.py", line 1284, in _run_as
return _func_or_method(*args, **kwargs)
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/loader/lazy.py", line 1317, in wrapper
return f(*args, **kwargs)
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/states/pkg.py", line 1934, in installed
pkg_ret = __salt__["pkg.install"](
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/loader/lazy.py", line 160, in __call__
ret = self.loader.run(run_func, *args, **kwargs)
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/loader/lazy.py", line 1269, in run
return self._last_context.run(self._run_as, _func_or_method, *args, **kwargs)
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/loader/lazy.py", line 1284, in _run_as
return _func_or_method(*args, **kwargs)
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/aptpkg.py", line 819, in install
_latest_version = latest_version(
File "/opt/saltstack/salt/lib/python3.10/site-packages/salt/modules/aptpkg.py", line 507, in latest_version
candidates[this_pkg] = candidate
UnboundLocalError: local variable 'this_pkg' referenced before assignment
Started: 16:01:22.614404
Duration: 50.036 ms
Changes:
The code in question is in aptpkg.latest_version()
:
cmd = ["apt-cache", "-q", "policy"]
cmd.extend(names)
if repo is not None:
cmd.extend(repo)
out = _call_apt(cmd, scope=False)
short_names = [nom.split(":", maxsplit=1)[0] for nom in names]
candidates = {}
for line in salt.utils.itertools.split(out["stdout"], "\n"):
if line.endswith(":") and line[:-1] in short_names:
this_pkg = names[short_names.index(line[:-1])]
elif "Candidate" in line:
candidate = ""
comps = line.split()
if len(comps) >= 2:
candidate = comps[-1]
if candidate.lower() == "(none)":
candidate = ""
candidates[this_pkg] = candidate
As you can see, the this_pkg
variable is set in the if
branch, but referenced in the elif
branch. This is at least brittle, if not outright wrong.
The package causing this issue is wine32
, since it doesn't exist in the amd64
architecture and thus apt-cache
prints its name with an architecture suffix:
# apt-cache -q policy wine32
wine32:i386:
Installed: 8.0~repack-4
Candidate: 8.0~repack-4
Version table:
*** 8.0~repack-4 500
500 http://deb.debian.org/debian bookworm/main i386 Packages
100 /var/lib/dpkg/status
line.endswith(":") and line[:-1] in short_names
doesn't match that.
salt-call pkg.latest_version wine32
is also broken, with the same UnboundLocalError
.
Changing the line in the YAML from - wine32
to - wine32:i386
allows the state to apply cleanly.
In contrast, salt-call pkg.latest_version wine32:i386
still doesn't work.
Expected behavior
Not quite sure actually. Maybe cut off the architecture suffix when parsing the apt-cache
output? Or give a warning like package 'wine32' was not found, are you missing an architecture suffix (e.g. 'wine32:i386')?
?
In any case, the parsing loop should be modified in order to not try and parse Candidate:
lines when this_pkg
has not yet been set.
Versions Report
salt --versions-report
Salt Version:
Salt: 3007.1
Python Version:
Python: 3.10.14 (main, Apr 3 2024, 21:30:09) [GCC 11.2.0]
Dependency Versions:
cffi: 1.16.0
cherrypy: 18.8.0
dateutil: 2.8.2
docker-py: Not Installed
gitdb: Not Installed
gitpython: Not Installed
Jinja2: 3.1.4
libgit2: Not Installed
looseversion: 1.3.0
M2Crypto: Not Installed
Mako: Not Installed
msgpack: 1.0.7
msgpack-pure: Not Installed
mysql-python: Not Installed
packaging: 23.1
pycparser: 2.21
pycrypto: Not Installed
pycryptodome: 3.19.1
pygit2: Not Installed
python-gnupg: 0.5.2
PyYAML: 6.0.1
PyZMQ: 25.1.2
relenv: 0.16.0
smmap: Not Installed
timelib: 0.3.0
Tornado: 6.3.3
ZMQ: 4.3.4
Salt Package Information:
Package Type: onedir
System Versions:
dist: debian 12.7 bookworm
locale: utf-8
machine: x86_64
release: 6.1.0-25-amd64
system: Linux
version: Debian GNU/Linux 12.7 bookworm