Destroy Runner/MasterMinion resources in salt-run and fix MasterMinion.__del__ - #70177
Destroy Runner/MasterMinion resources in salt-run and fix MasterMinion.__del__#70177twangboy wants to merge 3 commits into
Conversation
…n.__del__
salt-run left its Runner un-destroy()'d, and RunnerClient/WheelClient
never cleaned up the MasterMinion they lazily create via
SyncClientMixin.mminion. Both were only reclaimed by __del__'s
GC-time safety net, which now logs a loud "unclosed Runner"/
"unclosed MasterMinion" WARNING on every salt-run invocation instead
of being silently filtered.
- salt/cli/run.py: wrap SaltRun.run() in try/finally so runner.destroy()
always runs, covering both the --doc early-exit and the normal path.
- salt/runner.py, salt/wheel/__init__.py: destroy() now also tears down
self._mminion.
- salt/minion.py: MasterMinion.destroy() leaves returners/functions/utils
as {}, not None, but __del__'s "already torn down" check tested for
None specifically, so even a properly destroy()'d MasterMinion kept
tripping the warning. Check falsiness instead.
Fixes saltstack#70174
pylint's blacklisted-module check (saltpylint) flags direct use of unittest.mock; Salt's own tests must import MagicMock from tests.support.mock instead. Fixes the "Lint Salt's Test Suite" CI failure on PR saltstack#70177.
Review follow-up for saltstack#70177/saltstack#70174: MasterMinion.destroy(), RunnerClient.destroy(), and WheelClient.destroy() ran their per-component teardown steps back-to-back with no exception isolation. If any one component's .destroy() call raised, every later step -- including resetting the remaining attributes to {} and, in RunnerClient/WheelClient's case, tearing down the lazily created MasterMinion (self._mminion), the whole point of this fix -- was silently skipped, and the exception propagated out of destroy() itself. That's now unconditionally called from salt/cli/run.py's finally: runner.destroy(), so an exception there would replace SaltRun.run()'s real result/control flow with an unrelated destroy()-time traceback. Wrap each component's teardown call in its own try/except (mirroring the existing pattern in salt/utils/asynchronous.py's SyncWrapper.destroy()), and make each attribute reset unconditional, so one component failing can never block another's teardown, and destroy() itself can never raise.
|
Addressed both considerations:
|
What does this PR do?
salt-runleft its Runnerun-destroy()'d, andRunnerClient/WheelClientnever cleaned up theMasterMinionthey lazily create viaSyncClientMixin.mminion. Both were only reclaimed by__del__'s GC-time safety net, which now logs a loud "unclosed Runner"/ "unclosed MasterMinion" WARNING on everysalt-runinvocation instead of being silently filtered.salt/cli/run.py: wrapSaltRun.run()intry/finallysorunner.destroy()always runs, covering both the--docearly-exit and the normal path.salt/runner.py,salt/wheel/__init__.py:destroy()now also tears downself._mminion.salt/minion.py:MasterMinion.destroy()leaves returners/functions/utils as{}, notNone, but__del__'s "already torn down" check tested forNonespecifically, so even a properlydestroy()'d MasterMinion kept tripping the warning. Check falsiness instead.What issues does this PR fix or reference?
Fixes #70174
Merge requirements satisfied?
[NOTICE] Bug fixes or features added to Salt require tests.
Commits signed with GPG?
Yes