Ansible.Basic: make module options case insensitive with dep warning (#51583)

* Ansible.Basic: make module options case insensitive with dep warning

* Add porting guide info
This commit is contained in:
Jordan Borean 2019-02-14 12:55:43 +10:00 committed by ansibot
parent f254d0074d
commit 7b8e814a10
3 changed files with 73 additions and 1 deletions

View file

@ -112,6 +112,10 @@ add ``$ErrorActionPreference = "Continue"`` to the top of the module. This chang
of the EAP that was accidentally removed in a previous release and ensure that modules are more resiliant to errors of the EAP that was accidentally removed in a previous release and ensure that modules are more resiliant to errors
that may occur in execution. that may occur in execution.
PowerShell module options and option choices are currently case insensitive to what is defined in the module
specification. This behaviour is deprecated and a warning displayed to the user if a case insensitive match was found.
A future release of Ansible will make these checks case sensitive.
Modules removed Modules removed
--------------- ---------------

View file

@ -809,13 +809,18 @@ namespace Ansible.Basic
private void CheckUnsupportedArguments(IDictionary param, List<string> legalInputs) private void CheckUnsupportedArguments(IDictionary param, List<string> legalInputs)
{ {
HashSet<string> unsupportedParameters = new HashSet<string>(); HashSet<string> unsupportedParameters = new HashSet<string>();
HashSet<string> caseUnsupportedParameters = new HashSet<string>();
List<string> removedParameters = new List<string>(); List<string> removedParameters = new List<string>();
foreach (DictionaryEntry entry in param) foreach (DictionaryEntry entry in param)
{ {
string paramKey = (string)entry.Key; string paramKey = (string)entry.Key;
if (!legalInputs.Contains(paramKey)) if (!legalInputs.Contains(paramKey, StringComparer.OrdinalIgnoreCase))
unsupportedParameters.Add(paramKey); unsupportedParameters.Add(paramKey);
else if (!legalInputs.Contains(paramKey))
// For backwards compatibility we do not care about the case but we need to warn the users as this will
// change in a future Ansible release.
caseUnsupportedParameters.Add(paramKey);
else if (paramKey.StartsWith("_ansible_")) else if (paramKey.StartsWith("_ansible_"))
{ {
removedParameters.Add(paramKey); removedParameters.Add(paramKey);
@ -852,6 +857,24 @@ namespace Ansible.Basic
msg = String.Format("{0}. Supported parameters include: {1}", FormatOptionsContext(msg), String.Join(", ", legalInputs)); msg = String.Format("{0}. Supported parameters include: {1}", FormatOptionsContext(msg), String.Join(", ", legalInputs));
FailJson(msg); FailJson(msg);
} }
if (caseUnsupportedParameters.Count > 0)
{
legalInputs.RemoveAll(x => passVars.Keys.Contains(x.Replace("_ansible_", "")));
string msg = String.Format("Parameters for ({0}) was a case insensitive match: {1}", ModuleName, String.Join(", ", caseUnsupportedParameters));
msg = String.Format("{0}. Module options will become case sensitive in a future Ansible release. Supported parameters include: {1}",
FormatOptionsContext(msg), String.Join(", ", legalInputs));
Warn(msg);
}
// Make sure we convert all the incorrect case params to the ones set by the module spec
foreach (string key in caseUnsupportedParameters)
{
string correctKey = legalInputs[legalInputs.FindIndex(s => s.Equals(key, StringComparison.OrdinalIgnoreCase))];
object value = param[key];
param.Remove(key);
param.Add(correctKey, value);
}
} }
private void CheckMutuallyExclusive(IDictionary param, IList mutuallyExclusive) private void CheckMutuallyExclusive(IDictionary param, IList mutuallyExclusive)

View file

@ -503,6 +503,51 @@ $tests = @{
$actual.invocation | Assert-DictionaryEquals -Expected @{module_args = $expected_module_args} $actual.invocation | Assert-DictionaryEquals -Expected @{module_args = $expected_module_args}
} }
"Parse module args with case insensitive input" = {
$spec = @{
options = @{
option1 = @{ type = "int"; required = $true }
}
}
$complex_args = @{
_ansible_module_name = "win_test"
Option1 = "1"
}
$m = [Ansible.Basic.AnsibleModule]::Create(@(), $spec)
# Verifies the case of the params key is set to the module spec not actual input
$m.Params.Keys | Assert-Equals -Expected @("option1")
$m.Params.option1 | Assert-Equals -Expected 1
# Verifies the type conversion happens even on a case insensitive match
$m.Params.option1.GetType().FullName | Assert-Equals -Expected "System.Int32"
$failed = $false
try {
$m.ExitJson()
} catch [System.Management.Automation.RuntimeException] {
$failed = $true
$_.Exception.Message | Assert-Equals -Expected "exit: 0"
$actual = [Ansible.Basic.AnsibleModule]::FromJson($_test_out)
}
$failed | Assert-Equals -Expected $true
$expected_warnings = "Parameters for (win_test) was a case insensitive match: Option1. "
$expected_warnings += "Module options will become case sensitive in a future Ansible release. "
$expected_warnings += "Supported parameters include: option1"
$expected = @{
changed = $false
invocation = @{
module_args = @{
option1 = 1
}
}
warnings = @($expected_warnings)
}
$actual | Assert-DictionaryEquals -Expected $expected
}
"No log values" = { "No log values" = {
$spec = @{ $spec = @{
options = @{ options = @{