-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[3006.x] module.run: fix result detection from returned dict #67115
base: 3006.x
Are you sure you want to change the base?
Conversation
# state result. | ||
else: | ||
res = _get_dict_result(changes_ret) | ||
elif isinstance(func_ret, dict): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no longer an else case for when func_ret
is not a bool
nor a dict
, the return will be True
. The func_ret
not being a bool
nor dict
is unexpected so should throw an exception or at least return False
. Also we are checking isinstance(func_ret, dict)
multiple times (also on line 669). We should just check once and have the func_ret.get("retcode", 0) != 0
check be inside it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was not really a plain else case before, as the else
had the if isinstance(changes_ret, dict)
inside which itself had no else case.
And I think it is ok or even wanted to have it return True
in such cases: Not every execution module function does give a clear successful/unsuccessful indication.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not every execution module function does give a clear successful/unsuccessful indication.
In that case I would expect func_ret
to be None
which I recommend we handle in the way you deem correct, but an unexpected data type should either return the truth/bool
value of it self (i.e. bool(func_ret)
so empty list []
is False and list with value is True) or should throw an exception because we are getting an unexpected value. We should not do the worst case though of returning True
that function was successful it wasn't and returned a bad value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, there seems to be no hard standard for the return of execution modules. Unlike state modules.
Returning None
or []
could simply mean that it had nothing to do.
For example saltutil.sync_modules
does return a list of synced modules. But if there was nothing to sync, the list is empty, which is totally fine and actually a success.
However, there are some typical ways how some module functions indicate the succession: By a returning a bool or by dict keys result
or retcode
. Everything else would be a guess.
Using module.run is just some kind of a workaround anyway. If a proper determination of the result is needed, one should look for a state module or make one.
Also this PR is just meant to fix the limited (and often sufficient) way the function already had to determine the succession. Not to redesign it.
1c23b3d
to
e4946c3
Compare
if isinstance(func_ret.get("result", {}), bool): | ||
res = func_ret.get("result", {}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we determined the result is already in the dict, I recommend using []
instead of get
. Also we don't use the default {}
value on line 674 so I recommend using None instead:
if isinstance(func_ret.get("result"), bool):
res = func_ret["result"]
alternatively we can use the newer python :=
assignment operator:
if isinstance(bool_res := func_ret.get("result"), bool):
res = bool_res
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since we determined the result is already in the dict, I recommend using
[]
instead ofget
. Also we don't use the default{}
value on line 674 so I recommend using None instead:if isinstance(func_ret.get("result"), bool): res = func_ret["result"]
I actually thought about that, but I didn't want to start refactoring the whole module.
And I just moved those lines and did not create or edit them.
alternatively we can use the newer python
:=
assignment operator:if isinstance(bool_res := func_ret.get("result"), bool): res = bool_res
While I think the assignment operator is pretty neat, I think it is better to not use it here.
Salt is sometimes still used with somewhat old python versions that don't support it yet. For example if you use salt-ssh, you need to rely on the python installation that already exists on the system.
e4946c3
to
b361e25
Compare
What does this PR do?
Fixes #65842 Module.run state returns invalid result when method returns a dict
module.run should also check for a key
result
in the return of the executed module to determin if it was successful.But this only works for the legacy- and not the new-style.
This is because in the new-style, the
_get_result
function is always executed with a actually empty dict as thechanges
parameter, where it searches for theresult
key.Also this
changes
parameter is not necessary as even, in the case of the legacy-style, it is effectively just a copy of thefunc_ret
parameter.