Use Ansible to load ps module utils in arg spec checker (#67596)
* Use Ansible to load ps module utils in arg spec checker * Added changelog and note
This commit is contained in:
parent
b54e64bbc9
commit
36def8bf03
4 changed files with 42 additions and 29 deletions
2
changelogs/fragments/valdate-modules-ps-arg-util.yaml
Normal file
2
changelogs/fragments/valdate-modules-ps-arg-util.yaml
Normal file
|
@ -0,0 +1,2 @@
|
|||
bugfixes:
|
||||
- ansible-test validate-modules - Fix arg spec collector for PowerShell to find utils in both a collection and base.
|
|
@ -29,6 +29,7 @@ from ansible.plugins.loader import ps_module_utils_loader
|
|||
class PSModuleDepFinder(object):
|
||||
|
||||
def __init__(self):
|
||||
# This is also used by validate-modules to get a module's required utils in base and a collection.
|
||||
self.ps_modules = dict()
|
||||
self.exec_scripts = dict()
|
||||
|
||||
|
|
|
@ -26,8 +26,10 @@ import sys
|
|||
|
||||
from contextlib import contextmanager
|
||||
|
||||
from ansible.executor.powershell.module_manifest import PSModuleDepFinder
|
||||
from ansible.module_utils.basic import FILE_COMMON_ARGUMENTS
|
||||
from ansible.module_utils.six import reraise
|
||||
from ansible.module_utils._text import to_bytes, to_text
|
||||
|
||||
from .utils import CaptureStd, find_executable, get_module_name_from_filename
|
||||
|
||||
|
@ -94,8 +96,22 @@ def get_ps_argument_spec(filename):
|
|||
if not pwsh:
|
||||
raise FileNotFoundError('Required program for PowerShell arg spec inspection "pwsh" not found.')
|
||||
|
||||
module_path = os.path.join(os.getcwd(), filename)
|
||||
b_module_path = to_bytes(module_path, errors='surrogate_or_strict')
|
||||
with open(b_module_path, mode='rb') as module_fd:
|
||||
b_module_data = module_fd.read()
|
||||
|
||||
ps_dep_finder = PSModuleDepFinder()
|
||||
ps_dep_finder.scan_module(b_module_data)
|
||||
|
||||
util_manifest = json.dumps({
|
||||
'module_path': to_text(module_path, errors='surrogiate_or_strict'),
|
||||
'ps_utils': dict([(name, info['path']) for name, info in ps_dep_finder.ps_modules.items()])
|
||||
})
|
||||
|
||||
script_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'ps_argspec.ps1')
|
||||
proc = subprocess.Popen([script_path, filename], stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=False)
|
||||
proc = subprocess.Popen([script_path, util_manifest], stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
shell=False)
|
||||
stdout, stderr = proc.communicate()
|
||||
|
||||
if proc.returncode != 0:
|
||||
|
|
|
@ -5,11 +5,12 @@ Set-StrictMode -Version 2.0
|
|||
$ErrorActionPreference = "Stop"
|
||||
$WarningPreference = "Stop"
|
||||
|
||||
$module_path = $args[0]
|
||||
if (-not $module_path) {
|
||||
$manifest = ConvertFrom-Json -InputObject $args[0] -AsHashtable
|
||||
if (-not $manifest.Contains('module_path') -or -not $manifest.module_path) {
|
||||
Write-Error -Message "No module specified."
|
||||
exit 1
|
||||
}
|
||||
$module_path = $manifest.module_path
|
||||
|
||||
# Check if the path is relative and get the full path to the module
|
||||
if (-not ([System.IO.Path]::IsPathRooted($module_path))) {
|
||||
|
@ -51,33 +52,26 @@ $module_code = Get-Content -LiteralPath $module_path -Raw
|
|||
$powershell = [PowerShell]::Create()
|
||||
$powershell.Runspace.SessionStateProxy.SetVariable("ErrorActionPreference", "Stop")
|
||||
|
||||
# Load the PowerShell module utils as the module may be using them to refer to shared module options
|
||||
# FUTURE: Lookup utils in the role or collection's module_utils dir based on #AnsibleRequires
|
||||
$script_requirements = [ScriptBlock]::Create($module_code).Ast.ScriptRequirements
|
||||
$required_modules = @()
|
||||
if ($null -ne $script_requirements) {
|
||||
$required_modules = $script_requirements.RequiredModules
|
||||
}
|
||||
foreach ($required_module in $required_modules) {
|
||||
if (-not $required_module.Name.StartsWith('Ansible.ModuleUtils.')) {
|
||||
continue
|
||||
# Load the PowerShell module utils as the module may be using them to refer to shared module options. Currently we
|
||||
# can only load the PowerShell utils due to cross platform compatiblity issues.
|
||||
if ($manifest.Contains('ps_utils')) {
|
||||
foreach ($util_info in $manifest.ps_utils.GetEnumerator()) {
|
||||
$util_name = $util_info.Key
|
||||
$util_path = $util_info.Value
|
||||
|
||||
if (-not (Test-Path -LiteralPath $util_path -PathType Leaf)) {
|
||||
# Failed to find the util path, just silently ignore for now and hope for the best.
|
||||
continue
|
||||
}
|
||||
|
||||
$util_sb = [ScriptBlock]::Create((Get-Content -LiteralPath $util_path -Raw))
|
||||
$powershell.AddCommand('New-Module').AddParameters(@{
|
||||
Name = $util_name
|
||||
ScriptBlock = $util_sb
|
||||
}) > $null
|
||||
$powershell.AddCommand('Import-Module').AddParameter('WarningAction', 'SilentlyContinue') > $null
|
||||
$powershell.AddCommand('Out-Null').AddStatement() > $null
|
||||
}
|
||||
|
||||
$module_util_path = [System.IO.Path]::GetFullPath([System.IO.Path]::Combine($module_path, '..', '..', '..',
|
||||
'module_utils', 'powershell', "$($required_module.Name).psm1"))
|
||||
if (-not (Test-Path -LiteralPath $module_util_path -PathType Leaf)) {
|
||||
# Failed to find path, just silently ignore for now and hope for the best
|
||||
continue
|
||||
}
|
||||
|
||||
$module_util_sb = [ScriptBlock]::Create((Get-Content -LiteralPath $module_util_path -Raw))
|
||||
$powershell.AddCommand('New-Module').AddParameters(@{
|
||||
Name = $required_module.Name
|
||||
ScriptBlock = $module_util_sb
|
||||
}) > $null
|
||||
$powershell.AddCommand('Import-Module').AddParameter('WarningAction', 'SilentlyContinue') > $null
|
||||
$powershell.AddCommand('Out-Null').AddStatement() > $null
|
||||
|
||||
}
|
||||
|
||||
$powershell.AddScript($module_code) > $null
|
||||
|
|
Loading…
Reference in a new issue