Skip to content
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

Open
wants to merge 1 commit into
base: 3006.x
Choose a base branch
from

Conversation

hurzhurz
Copy link
Contributor

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 the changes parameter, where it searches for the result key.

Also this changes parameter is not necessary as even, in the case of the legacy-style, it is effectively just a copy of the func_ret parameter.

elif isinstance(func_ret, dict):
if isinstance(func_ret.get("result", {}), bool):
res = func_ret.get("result", {})
elif func_ret.get("retcode", 0) != 0:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This case is already handled on line 699

if isinstance(func_ret, dict) and func_ret.get("retcode", 0) != 0:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right, I missed that while changing it from changes_ret to func_ret. I will edit that!

# state result.
else:
res = _get_dict_result(changes_ret)
elif isinstance(func_ret, dict):
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Contributor

@bdrx312 bdrx312 Jan 14, 2025

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.

res = _get_dict_result(changes_ret)
# if mret is a dict, check if certain keys exist
elif isinstance(func_ret, dict):
# if return key exists and is is boolean, return that as the result
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo is is

Comment on lines +674 to +675
if isinstance(func_ret.get("result", {}), bool):
res = func_ret.get("result", {})
Copy link
Contributor

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

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