Add ignore invalid options override for mod wrapper (#81899)

Adds an option that can have an action plugin tell the module to ignore
options that do not fit its arg spec. This is to enable support for core
running modules that exist outside of the collection that may not be new
enough to support some of the options supplied to it.
pull/82000/head
Jordan Borean 8 months ago committed by GitHub
parent 5812cabaf5
commit 22568305d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,6 @@
minor_changes:
- >-
modules - Add the ability for an action plugin to call ``self._execute_module(*, ignore_unknown_opts=True)`` to execute a module with options that may not be
supported for the version being called. This tells the module basic wrapper to ignore validating the options provided match the arg spec.
bugfixes:
- fetch - Do not calculate the file size for Windows fetch targets to improve performance.

@ -480,6 +480,8 @@ class AnsibleModule(object):
try:
error = self.validation_result.errors[0]
if isinstance(error, UnsupportedError) and self._ignore_unknown_opts:
error = None
except IndexError:
error = None

@ -87,6 +87,7 @@ PASS_VARS = {
'debug': ('_debug', False),
'diff': ('_diff', False),
'keep_remote_files': ('_keep_remote_files', False),
'ignore_unknown_opts': ('_ignore_unknown_opts', False),
'module_name': ('_name', None),
'no_log': ('no_log', False),
'remote_tmp': ('_remote_tmp', None),
@ -100,7 +101,7 @@ PASS_VARS = {
'version': ('ansible_version', '0.0'),
}
PASS_BOOLS = ('check_mode', 'debug', 'diff', 'keep_remote_files', 'no_log')
PASS_BOOLS = ('check_mode', 'debug', 'diff', 'keep_remote_files', 'ignore_unknown_opts', 'no_log')
DEFAULT_TYPE_VALIDATORS = {
'str': check_type_str,

@ -49,6 +49,7 @@ namespace Ansible.Basic
private static List<string> BOOLEANS_TRUE = new List<string>() { "y", "yes", "on", "1", "true", "t", "1.0" };
private static List<string> BOOLEANS_FALSE = new List<string>() { "n", "no", "off", "0", "false", "f", "0.0" };
private bool ignoreUnknownOpts = false;
private string remoteTmp = Path.GetTempPath();
private string tmpdir = null;
private HashSet<string> noLogValues = new HashSet<string>();
@ -64,6 +65,7 @@ namespace Ansible.Basic
{ "debug", "DebugMode" },
{ "diff", "DiffMode" },
{ "keep_remote_files", "KeepRemoteFiles" },
{ "ignore_unknown_opts", "ignoreUnknownOpts" },
{ "module_name", "ModuleName" },
{ "no_log", "NoLog" },
{ "remote_tmp", "remoteTmp" },
@ -76,7 +78,7 @@ namespace Ansible.Basic
{ "verbosity", "Verbosity" },
{ "version", "AnsibleVersion" },
};
private List<string> passBools = new List<string>() { "check_mode", "debug", "diff", "keep_remote_files", "no_log" };
private List<string> passBools = new List<string>() { "check_mode", "debug", "diff", "keep_remote_files", "ignore_unknown_opts", "no_log" };
private List<string> passInts = new List<string>() { "verbosity" };
private Dictionary<string, List<object>> specDefaults = new Dictionary<string, List<object>>()
{
@ -1043,7 +1045,7 @@ namespace Ansible.Basic
foreach (string parameter in removedParameters)
param.Remove(parameter);
if (unsupportedParameters.Count > 0)
if (unsupportedParameters.Count > 0 && !ignoreUnknownOpts)
{
legalInputs.RemoveAll(x => passVars.Keys.Contains(x.Replace("_ansible_", "")));
string msg = String.Format("Unsupported parameters for ({0}) module: {1}", ModuleName, String.Join(", ", unsupportedParameters));

@ -849,10 +849,13 @@ class ActionBase(ABC):
path=path,
follow=follow,
get_checksum=checksum,
get_size=False, # ansible.windows.win_stat added this in 1.11.0
checksum_algorithm='sha1',
)
# Unknown opts are ignored as module_args could be specific for the
# module that is being executed.
mystat = self._execute_module(module_name='ansible.legacy.stat', module_args=module_args, task_vars=all_vars,
wrap_async=False)
wrap_async=False, ignore_unknown_opts=True)
if mystat.get('failed'):
msg = mystat.get('module_stderr')
@ -936,7 +939,7 @@ class ActionBase(ABC):
data = re.sub(r'^((\r)?\n)?BECOME-SUCCESS.*(\r)?\n', '', data)
return data
def _update_module_args(self, module_name, module_args, task_vars):
def _update_module_args(self, module_name, module_args, task_vars, ignore_unknown_opts: bool = False):
# set check mode in the module arguments, if required
if self._task.check_mode:
@ -994,7 +997,11 @@ class ActionBase(ABC):
# make sure the remote_tmp value is sent through in case modules needs to create their own
module_args['_ansible_remote_tmp'] = self.get_shell_option('remote_tmp', default='~/.ansible/tmp')
def _execute_module(self, module_name=None, module_args=None, tmp=None, task_vars=None, persist_files=False, delete_remote_tmp=None, wrap_async=False):
# tells the module to ignore options that are not in its argspec.
module_args['_ansible_ignore_unknown_opts'] = ignore_unknown_opts
def _execute_module(self, module_name=None, module_args=None, tmp=None, task_vars=None, persist_files=False, delete_remote_tmp=None, wrap_async=False,
ignore_unknown_opts: bool = False):
'''
Transfer and run a module along with its arguments.
'''
@ -1030,7 +1037,7 @@ class ActionBase(ABC):
if module_args is None:
module_args = self._task.args
self._update_module_args(module_name, module_args, task_vars)
self._update_module_args(module_name, module_args, task_vars, ignore_unknown_opts=ignore_unknown_opts)
remove_async_dir = None
if wrap_async or self._task.async_val:

@ -2253,6 +2253,34 @@ test_no_log - Invoked with:
$actual.invocation | Assert-DictionaryEqual -Expected @{module_args = $complex_args }
}
"Unsupported options with ignore" = {
$spec = @{
options = @{
option_key = @{
type = "str"
}
}
}
Set-Variable -Name complex_args -Scope Global -Value @{
option_key = "abc"
invalid_key = "def"
another_key = "ghi"
_ansible_ignore_unknown_opts = $true
}
$m = [Ansible.Basic.AnsibleModule]::Create(@(), $spec)
$m.Params | Assert-DictionaryEqual -Expected @{ option_key = "abc"; invalid_key = "def"; another_key = "ghi" }
try {
$m.ExitJson()
}
catch [System.Management.Automation.RuntimeException] {
$output = [Ansible.Basic.AnsibleModule]::FromJson($_.Exception.InnerException.Output)
}
$output.Keys.Count | Assert-Equal -Expected 2
$output.changed | Assert-Equal -Expected $false
$output.invocation | Assert-DictionaryEqual -Expected @{module_args = @{option_key = "abc"; invalid_key = "def"; another_key = "ghi" } }
}
"Check mode and module doesn't support check mode" = {
$spec = @{
options = @{

@ -66,6 +66,8 @@ VALID_SPECS = (
({'arg': {'type': 'list', 'elements': 'str'}}, {'arg': [42, 32]}, ['42', '32']),
# parameter is required
({'arg': {'required': True}}, {'arg': 42}, '42'),
# ignored unknown parameters
({'arg': {'type': 'int'}}, {'arg': 1, 'invalid': True, '_ansible_ignore_unknown_opts': True}, 1),
)
INVALID_SPECS = (

Loading…
Cancel
Save