o nnh@sddlmZddlZddlZddlZddlZddlZddlZddlZddl Z ddl Z ddl Z ddlm Z m Z mZddlmZddlmZmZddlmZddlmZddlmZdd lmZdd lmZdd l m!Z!m"Z"m#Z#dd l$m%Z%dd l&m'Z'm(Z(ddl)m*Z*ddl+m,Z,ddl-m.Z.ddl/Z0ddl1Z0e,Z2e.dgdZ3dZ4dZ5dZ6dZ7dZ8dZ9dZ:dZ;ej<=ej<>e?ddZ@dZAdZBdZCd ZDd!d"ZEejFreAZGneEeAZGej<>ej<>ej<>e?ZHe Id#e JeHZKe Id$ZLe Id%ZMGd&d'd'ejNZOd(d)ZPeQd*fd+d,ZRGd-d.d.ZSGd/d0d0eSZTGd1d2d2eSZUdFd3d4ZVdFd5d6ZWd7d8ZXd9d:ZYd;d<ZZ *dGd=d>Z[d?d@Z\ * *dHdBdCZ]dFdDdEZ^dS)I) annotationsN)ASTImport ImportFrom)BytesIO) __version__ __author__) constants) AnsibleError)!InterpreterDiscoveryRequiredError)module_manifest)AnsibleJSONEncoder)to_bytesto_text to_native)module_utils_loader)_get_collection_metadata_nested_dict_get)action_write_locks)Display) namedtupleModuleUtilsProcessEntry) name_parts is_ambiguoushas_redirected_child is_optionals"#<>s"<>"s)"<>"s# POWERSHELL_COMMONs$<>s<>z# -*- coding: utf-8 -*-s# -*- coding: utf-8 -*-z.. module_utilsa.%(shebang)s %(coding)s _ANSIBALLZ_WRAPPER = True # For test-module.py script to tell this is a ANSIBALLZ_WRAPPER # This code is part of Ansible, but is an independent component. # The code in this particular templatable string, and this templatable string # only, is BSD licensed. Modules which end up using this snippet, which is # dynamically combined together by Ansible still belong to the author of the # module, and they may assign their own license to the complete work. # # Copyright (c), James Cammarata, 2016 # Copyright (c), Toshio Kuratomi, 2016 # # Redistribution and use in source and binary forms, with or without modification, # are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions and the following disclaimer in the documentation # and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. # IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE # USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. def _ansiballz_main(): import os import os.path # Access to the working directory is required by Python when using pipelining, as well as for the coverage module. # Some platforms, such as macOS, may not allow querying the working directory when using become to drop privileges. try: os.getcwd() except OSError: try: os.chdir(os.path.expanduser('~')) except OSError: os.chdir('/') %(rlimit)s import sys import __main__ # For some distros and python versions we pick up this script in the temporary # directory. This leads to problems when the ansible module masks a python # library that another import needs. We have not figured out what about the # specific distros and python versions causes this to behave differently. # # Tested distros: # Fedora23 with python3.4 Works # Ubuntu15.10 with python2.7 Works # Ubuntu15.10 with python3.4 Fails without this # Ubuntu16.04.1 with python3.5 Fails without this # To test on another platform: # * use the copy module (since this shadows the stdlib copy module) # * Turn off pipelining # * Make sure that the destination file does not exist # * ansible ubuntu16-test -m copy -a 'src=/etc/motd dest=/var/tmp/m' # This will traceback in shutil. Looking at the complete traceback will show # that shutil is importing copy which finds the ansible module instead of the # stdlib module scriptdir = None try: scriptdir = os.path.dirname(os.path.realpath(__main__.__file__)) except (AttributeError, OSError): # Some platforms don't set __file__ when reading from stdin # OSX raises OSError if using abspath() in a directory we don't have # permission to read (realpath calls abspath) pass # Strip cwd from sys.path to avoid potential permissions issues excludes = set(('', '.', scriptdir)) sys.path = [p for p in sys.path if p not in excludes] import base64 import runpy import shutil import tempfile import zipfile if sys.version_info < (3,): PY3 = False else: PY3 = True ZIPDATA = %(zipdata)r # Note: temp_path isn't needed once we switch to zipimport def invoke_module(modlib_path, temp_path, json_params): # When installed via setuptools (including python setup.py install), # ansible may be installed with an easy-install.pth file. That file # may load the system-wide install of ansible rather than the one in # the module. sitecustomize is the only way to override that setting. z = zipfile.ZipFile(modlib_path, mode='a') # py3: modlib_path will be text, py2: it's bytes. Need bytes at the end sitecustomize = u'import sys\nsys.path.insert(0,"%%s")\n' %% modlib_path sitecustomize = sitecustomize.encode('utf-8') # Use a ZipInfo to work around zipfile limitation on hosts with # clocks set to a pre-1980 year (for instance, Raspberry Pi) zinfo = zipfile.ZipInfo() zinfo.filename = 'sitecustomize.py' zinfo.date_time = %(date_time)s z.writestr(zinfo, sitecustomize) z.close() # Put the zipped up module_utils we got from the controller first in the python path so that we # can monkeypatch the right basic sys.path.insert(0, modlib_path) # Monkeypatch the parameters into basic from ansible.module_utils import basic basic._ANSIBLE_ARGS = json_params %(coverage)s # Run the module! By importing it as '__main__', it thinks it is executing as a script runpy.run_module(mod_name=%(module_fqn)r, init_globals=dict(_module_fqn=%(module_fqn)r, _modlib_path=modlib_path), run_name='__main__', alter_sys=True) # Ansible modules must exit themselves print('{"msg": "New-style module did not handle its own exit", "failed": true}') sys.exit(1) def debug(command, zipped_mod, json_params): # The code here normally doesn't run. It's only used for debugging on the # remote machine. # # The subcommands in this function make it easier to debug ansiballz # modules. Here's the basic steps: # # Run ansible with the environment variable: ANSIBLE_KEEP_REMOTE_FILES=1 and -vvv # to save the module file remotely:: # $ ANSIBLE_KEEP_REMOTE_FILES=1 ansible host1 -m ping -a 'data=october' -vvv # # Part of the verbose output will tell you where on the remote machine the # module was written to:: # [...] # SSH: EXEC ssh -C -q -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o # PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o # ControlPath=/home/badger/.ansible/cp/ansible-ssh-%%h-%%p-%%r -tt rhel7 '/bin/sh -c '"'"'LANG=en_US.UTF-8 LC_ALL=en_US.UTF-8 # LC_MESSAGES=en_US.UTF-8 /usr/bin/python /home/badger/.ansible/tmp/ansible-tmp-1461173013.93-9076457629738/ping'"'"'' # [...] # # Login to the remote machine and run the module file via from the previous # step with the explode subcommand to extract the module payload into # source files:: # $ ssh host1 # $ /usr/bin/python /home/badger/.ansible/tmp/ansible-tmp-1461173013.93-9076457629738/ping explode # Module expanded into: # /home/badger/.ansible/tmp/ansible-tmp-1461173408.08-279692652635227/ansible # # You can now edit the source files to instrument the code or experiment with # different parameter values. When you're ready to run the code you've modified # (instead of the code from the actual zipped module), use the execute subcommand like this:: # $ /usr/bin/python /home/badger/.ansible/tmp/ansible-tmp-1461173013.93-9076457629738/ping execute # Okay to use __file__ here because we're running from a kept file basedir = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'debug_dir') args_path = os.path.join(basedir, 'args') if command == 'explode': # transform the ZIPDATA into an exploded directory of code and then # print the path to the code. This is an easy way for people to look # at the code on the remote machine for debugging it in that # environment z = zipfile.ZipFile(zipped_mod) for filename in z.namelist(): if filename.startswith('/'): raise Exception('Something wrong with this module zip file: should not contain absolute paths') dest_filename = os.path.join(basedir, filename) if dest_filename.endswith(os.path.sep) and not os.path.exists(dest_filename): os.makedirs(dest_filename) else: directory = os.path.dirname(dest_filename) if not os.path.exists(directory): os.makedirs(directory) f = open(dest_filename, 'wb') f.write(z.read(filename)) f.close() # write the args file f = open(args_path, 'wb') f.write(json_params) f.close() print('Module expanded into:') print('%%s' %% basedir) exitcode = 0 elif command == 'execute': # Execute the exploded code instead of executing the module from the # embedded ZIPDATA. This allows people to easily run their modified # code on the remote machine to see how changes will affect it. # Set pythonpath to the debug dir sys.path.insert(0, basedir) # read in the args file which the user may have modified with open(args_path, 'rb') as f: json_params = f.read() # Monkeypatch the parameters into basic from ansible.module_utils import basic basic._ANSIBLE_ARGS = json_params # Run the module! By importing it as '__main__', it thinks it is executing as a script runpy.run_module(mod_name=%(module_fqn)r, init_globals=None, run_name='__main__', alter_sys=True) # Ansible modules must exit themselves print('{"msg": "New-style module did not handle its own exit", "failed": true}') sys.exit(1) else: print('WARNING: Unknown debug command. Doing nothing.') exitcode = 0 return exitcode # # See comments in the debug() method for information on debugging # ANSIBALLZ_PARAMS = %(params)s if PY3: ANSIBALLZ_PARAMS = ANSIBALLZ_PARAMS.encode('utf-8') try: # There's a race condition with the controller removing the # remote_tmpdir and this module executing under async. So we cannot # store this in remote_tmpdir (use system tempdir instead) # Only need to use [ansible_module]_payload_ in the temp_path until we move to zipimport # (this helps ansible-test produce coverage stats) temp_path = tempfile.mkdtemp(prefix='ansible_' + %(ansible_module)r + '_payload_') zipped_mod = os.path.join(temp_path, 'ansible_' + %(ansible_module)r + '_payload.zip') with open(zipped_mod, 'wb') as modlib: modlib.write(base64.b64decode(ZIPDATA)) if len(sys.argv) == 2: exitcode = debug(sys.argv[1], zipped_mod, ANSIBALLZ_PARAMS) else: # Note: temp_path isn't needed once we switch to zipimport invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS) finally: try: shutil.rmtree(temp_path) except (NameError, OSError): # tempdir creation probably failed pass sys.exit(exitcode) if __name__ == '__main__': _ansiballz_main() a os.environ['COVERAGE_FILE'] = %(coverage_output)r + '=python-%%s=coverage' %% '.'.join(str(v) for v in sys.version_info[:2]) import atexit try: import coverage except ImportError: print('{"msg": "Could not import `coverage` module.", "failed": true}') sys.exit(1) cov = coverage.Coverage(config_file=%(coverage_config)r) def atexit_coverage(): cov.stop() cov.save() atexit.register(atexit_coverage) cov.start() a try: if PY3: import importlib.util if importlib.util.find_spec('coverage') is None: raise ImportError else: import imp imp.find_module('coverage') except ImportError: print('{"msg": "Could not find `coverage` module.", "failed": true}') sys.exit(1) a import resource existing_soft, existing_hard = resource.getrlimit(resource.RLIMIT_NOFILE) # adjust soft limit subject to existing hard limit requested_soft = min(existing_hard, %(rlimit_nofile)d) if requested_soft != existing_soft: try: resource.setrlimit(resource.RLIMIT_NOFILE, (requested_soft, existing_hard)) except ValueError: # some platforms (eg macOS) lie about their hard limit pass cCs>g}|D]}|}|r|drq||qd|S)N# ) splitlinesstrip startswithappendjoin)sourcebuflinelr(I/usr/local/lib/python3.10/dist-packages/ansible/executor/module_common.py_strip_commentss   r*z*%s/(?Pansible/modules/.*)\.(py|ps1)$zH/(?Pansible_collections/[^/]+/[^/]+/plugins/modules/.*)\.(py|ps1)$s(?:from +\.{2,} *module_utils.* +import |from +ansible_collections\.[^.]+\.[^.]+\.plugins\.module_utils.* +import |import +ansible_collections\.[^.]+\.[^.]+\.plugins\.module_utils.*|from +ansible\.module_utils.* +import |import +ansible\.module_utils\.)cs:eZdZd fdd ZddZeZddZdd ZZS) ModuleDepFinderFcsXtt|j|i|||_t|_t|_||_||_t |j t |j i|_ ||dS)a Walk the ast tree for the python module. :arg module_fqn: The fully qualified name to reach this module in dotted notation. example: ansible.module_utils.basic :arg is_pkg_init: Inform the finder it's looking at a package init (eg __init__.py) to allow relative import expansion to use the proper package level without having imported it locally first. Save submodule[.submoduleN][.identifier] into self.submodules when they are from ansible.module_utils or ansible_collections packages self.submodules will end up with tuples like: - ('ansible', 'module_utils', 'basic',) - ('ansible', 'module_utils', 'urls', 'fetch_url') - ('ansible', 'module_utils', 'database', 'postgres') - ('ansible', 'module_utils', 'database', 'postgres', 'quote') - ('ansible', 'module_utils', 'database', 'postgres', 'quote') - ('ansible_collections', 'my_ns', 'my_col', 'plugins', 'module_utils', 'foo') It's up to calling code to determine whether the final element of the tuple are module names or something else (function, class, or variable names) .. seealso:: :python3:class:`ast.NodeVisitor` N)superr+__init___treeset submodulesoptional_imports module_fqn is_pkg_initr visit_Importrvisit_ImportFrom _visit_mapvisit)selfr2treer3argskwargs __class__r(r)r-szModuleDepFinder.__init__cCsn|j}|j}t|D])\}}t|tr4|D]}t|ttfr*||_||j |qt|t r3||qq dS)zOverridden ``generic_visit`` that makes some assumptions about our use case, and improves performance by calling visitors directly instead of calling ``visit`` to offload calling visitors. N) generic_visitr6ast iter_fields isinstancelistrrparentr=r)r8noder> visit_mapfieldvalueitemr(r(r)r>s  zModuleDepFinder.generic_visitcCsf|jD](}|jds|jdr+t|jd}|j||j|jkr+|j |q| |dS)z Handle import ansible.module_utils.MODLIB[.MODLIBn] [as asname] We save these as interesting submodules when the imported library is in ansible.module_utils or ansible.collections zansible.module_utils.ansible_collections..N) namesnamer!tuplesplitr0addrCr.r1r>)r8rDaliaspy_modr(r(r)r4s      zModuleDepFinder.visit_ImportcCs>|jdkr>|jr|j dpdn|j }|jr:t|jd}|jr0d|d||jf}nd|d|}n|j}n|j}d}|jdjdkrR|j dn$| dr_t|d}n| drv| d smd |vrut|d}n |r|jD]}|j ||jf|j |jkr|j ||jfq{||dS) a  Handle from ansible.module_utils.MODLIB import [.MODLIBn] [as asname] Also has to handle relative imports We save these as interesting submodules when the imported library is in ansible.module_utils or ansible.collections rNrJ_six)rSzansible.module_utilsrIzplugins.module_utilsz.plugins.module_utils.)levelr3r2rMrNmoduler#rKrLr0rOr!endswithrCr.r1r>)r8rDlevel_slice_offsetparts node_modulerQrPr(r(r)r5s6     z ModuleDepFinder.visit_ImportFromF) __name__ __module__ __qualname__r-r>r7r4r5 __classcell__r(r(r<r)r+s %r+cCsXtj|stdtj|t|d }|}Wd|S1s%wY|S)Nz1imported module support code does not exist at %srb)ospathexistsr abspathopenread)rafddatar(r(r)_slurp@s    rhFc Cstj|}d|}d|}d}|dkr[|r|d}nJtj|rTtjj||d} | | }|r:|dvrSd|} | d i} | | vrOt d ||d | | }nt d |d d ||vri| | |}|sm|}d |} |r}| dd |} | |fS)za Handles the different ways ansible allows overriding the shebang target for a module. zansible_%s_interpreterzINTERPRETER_%sNpythonansible_playbook_python variables)auto auto_legacy auto_silentauto_legacy_silentzdiscovered_interpreter_%s ansible_factszinterpreter discovery needed)interpreter_namediscovery_modezinterpreter discovery requiredrnz#!{0} )r`rabasenamer upperCconfigget_configuration_definitionget_config_valuetemplategetr formatr#) interpreter task_varstemplarr:remote_is_localrrinterpreter_configinterpreter_config_keyinterpreter_outinterpreter_from_configdiscovered_interpreter_configfacts_from_task_varsshebangr(r(r) _get_shebangHs4      rc@sTeZdZdddZeddZddZdd Zd d Zd d Z dddZ ddZ dS)ModuleUtilLocatorBaseFcCst||_||_||_d|_d|_||_d|_d|_d|_d|_ |r4t | |dkr4||ddg|_ dS|g|_ dS)NFrR) _is_ambiguous_child_is_redirected _is_optionalfound redirected fq_name_parts source_code output_path is_package_collection_namelen!_get_module_utils_remainder_partscandidate_namesr8rrchild_is_redirectedrr(r(r)r-s zModuleUtilLocatorBase.__init__cCsdd|jDS)NcSsg|]}d|qS)rJ)r#).0nr(r(r) sz@ModuleUtilLocatorBase.candidate_names_joined..)r)r8r(r(r)candidate_names_joinedz,ModuleUtilLocatorBase.candidate_names_joinedc Cs||}|s dSzt|j}Wn%ty5}z|jr"WYd}~dStdd||jt|d}~wwt |ddd|g}|sEdS| d}|du}|sU| d}|r| d}| d } | d } d d|} | rx| d | 7} n| d7} t | | |||jd |vrd|_ d|} d|_|d } | ds| d}t|dkrtd| | d|d|dd|dd} t d| | || | |_dSdS)NFzGerror processing module_util {0} loading redirected collection {1}: {2}rJplugin_routingr tombstone deprecation removal_dateremoval_version warning_textz module_util {0} has been removedz ({0})redirectTansible_collectionszinvalid redirect for {0}: {1}z4ansible_collections.{0}.{1}.plugins.module_utils.{2}rrRz"redirecting module_util {0} to {1})rrr ValueErrorrr r}r#rrr|display deprecatedrrr!rNr Exceptionvvv_generate_redirect_shim_sourcer)r8rmodule_utils_relative_partscollection_metadatave routing_entry dep_or_tsremovedrrrmsg source_pkgredirect_target_pkg split_fqcnr(r(r)_handle_redirects^          z&ModuleUtilLocatorBase._handle_redirectcCsgSNr(r8rr(r(r)rsz7ModuleUtilLocatorBase._get_module_utils_remainder_partscCsd||S)NrJ)r#rrr(r(r)_get_module_utils_remainderrz1ModuleUtilLocatorBase._get_module_utils_remaindercCsdS)NFr(rr(r(r) _find_modulesz"ModuleUtilLocatorBase._find_moduleTcCs|jD]}|r||rn||rn|s||rn q|jr)d|_d|_ndS|jr3|d}n|}d|_tjj |d|_ ||_ dS)NTr)r-.py) rrrrrrrr`rar#rr)r8redirect_firstcandidate_name_parts path_partsr(r(r)_locates$    zModuleUtilLocatorBase._locatecCs d||S)Nz8 import sys import {1} as mod sys.modules['{0}'] = mod )r})r8fq_source_modulefq_target_moduler(r(r)rsz4ModuleUtilLocatorBase._generate_redirect_shim_sourceNFFF)T) r[r\r]r-propertyrrrrrrrr(r(r(r)rs  ;  rcs.eZdZd fdd ZddZddZZS) LegacyModuleUtilLocatorFNcsftt|||||dddkrtd||ddkr%d}|g|_||_d|_|jdd dS) Nrransiblerz=this class can only locate from ansible.module_utils, got {0}six)rrrzansible.builtinF)r) r,rr-rr}r _mu_pathsrr)r8rrmu_pathsrr<r(r)r-s z LegacyModuleUtilLocator.__init__cC |ddS)Nrr(rr(r(r)r z9LegacyModuleUtilLocator._get_module_utils_remainder_partscs||tdkr|j}n fdd|jD}tjjd|||_}|durCt j |j dtjj vrC|j d|_|j }ndSt||_dS)NrRcs(g|]}tjj|gddRqS)Nr)r`rar#rprel_name_partsr(r)r!s(z8LegacyModuleUtilLocator._find_module..rJ /__init__.pyFT)rrr importlib machinery PathFinder find_specr#_infor`rasplitextoriginSOURCE_SUFFIXESrVrrhr)r8rpathsinforar(rr)rs   " z$LegacyModuleUtilLocator._find_module)FNF)r[r\r]r-rrr^r(r(r<r)rsrcs.eZdZdfdd ZddZddZZS) CollectionModuleUtilLocatorFcsztt||||||ddkrtd|t|dkr-|dddkr-td|d |d d|_|dS) NrrzMCollectionModuleUtilLocator can only locate from ansible_collections, got {0}r)pluginsrzoCollectionModuleUtilLocator can only locate below ansible_collections.(ns).(coll).plugins.module_utils, got {0}rJrR) r,rr-rr}rr#rrrr<r(r)r-1s  z$CollectionModuleUtilLocator.__init__cCst|dkrd|_d|_dSd|dd}tjj|dd}d}zt|ttj|d}Wn t y;Ynw|durDd|_nz t|t|d}Wn t yYYnw|dur`d S||_dS) NrrTrJrrz __init__.pyrF) rrrr#r`rapkgutilget_datar ImportError)r8rcollection_pkg_nameresource_base_pathsrcr(r(r)r>s.   z(CollectionModuleUtilLocator._find_modulecCr)Nrr(rr(r(r)rdrz=CollectionModuleUtilLocator._get_module_utils_remainder_partsr)r[r\r]r-rrr^r(r(r<r)r0s &rcCstj||d}|r |j|_|S)N)filename date_time)zipfileZipInfo compression compress_type)rrzfzinfor(r(r) _make_zinfohsrc s|dur tdd}dttdttddfddd d tjd d D}|tz t |d dt j }Wnt t fyP}z td||jfd}~wwt||fdd jD}|tdd d d d|r/||d\} } } } | vrqk| dddkrt| | || d} n| ddkrt| | | | d} n td| gqk| js| rqkd|| j}t|| jvrqkz t | jd dt j }Wnt t fy}z td| j|jfd}~wwtd| j|| j| fddjD| j| j!f| j<g}| jddD]}||t"|}|vr+|t|d | j#| dq|snD]%} | d}|$t%|||d | dt&|d!d"}t'd#|q1dS)$a Using ModuleDepFinder, make sure we have all of the module_utils files that the module and its module_utils files needs. (no longer actually recursive) :arg name: Name of the python module we're examining :arg module_fqn: Fully qualified name of the python module we're scanning :arg module_data: string Python code of the module we're scanning :arg zf: An open :python:class:`zipfile.ZipFile` object that holds the Ansible module payload which we're assembling NrsUfrom pkgutil import extend_path __path__=extend_path(__path__,__name__) __version__="s" __author__="s" zansible/__init__.py)sHfrom pkgutil import extend_path __path__=extend_path(__path__,__name__) z ansible/module_utils/__init__.py))rrcSsg|] }tj|r|qSr()r`raisdirrr(r(r)rsz$recursive_finder..F)subdirsz execzUnable to import %s due to %scs"g|] }t|dd|jvdqS)TFrrr1rm)finderr(r)rs")rrbasicrrrr)rrrr)rrrz=ModuleDepFinder improperly found a non-module_utils import %szFCould not find imported module support code for {0}. Looked for ({1})rJc3s.|]}|vrt|dd|jvdVqdS)TFrNrrrpy_module_cacher(r) s  z#recursive_finder..rrRrsurrogate_or_stricterrorszIncluding module_utils file %s)(timegmtimerrrr _get_pathsr"_MODULE_UTILS_PATHcompiler? PyCF_ONLY_AST SyntaxErrorIndentationErrorr rr+r0rsortpoprrrwarningrr}rrrr#rextendrrMrwritestrrrvvvvv)rLr2 module_datarrmodule_utils_pathsr9emodules_to_processpy_module_namerrr module_inforaccumulated_pkg_namepkgnormalized_namepy_module_file_namemu_filer(rr)recursive_finderrs        7    rcCsDttgdttddtdgB}|dd}t|d|S)N)  i) bytearrayr/rangebool translate) b_module_data textcharsstartr(r(r) _is_binarys( r.cCsVd}t|}|st|}|r'|d}d|vrtdd|d}|Std)ap Get the fully qualified name for an ansible module based on its pathname remote_module_fqn is the fully qualified name. Like ansible.modules.system.ping Or ansible_collections.Namespace.Collection_name.plugins.modules.ping .. warning:: This function is for ansible modules only. It won't work for other things (non-module plugins, etc) NrarJz7Module name (or path) was not a valid python identifier/z1Unable to determine module's fully qualified name)CORE_LIBRARY_PATH_REsearchCOLLECTION_PATH_REgrouprr#rN) module_pathremote_module_fqnmatchrar(r(r)_get_ansible_module_fqns   r7c Cs|d}d|d}|t|||d||ddkr#d}t}nd}t|}t|t|D]}d|d |d } | |vrDq2|t| ||dd q2d S) zKAdd a module from ansible or from an ansible collection into the module ziprJr/rrrrrrRNr)rNr#rr frozensetnamelistr(r) rrr5r+module_path_partsr4r-existing_pathsidx package_pathr(r(r)_add_module_to_zip s(     r?c-Cs>d}}t|r d}}nft|vrd}d}|td}nWt|r&d}d}nMt|vr5d}d}|td}n>td|tjs]td |tjs]td |tjs]td |tjs]td |tjrbd}d}nt|vrkd}d }nd|vrsd}}d}|dvr~|||fSt }zt |}Wnt yt dd|}Ynw|dkrtdd}|ddkrtj|dtjjid}td|t|d}z ttj|tdd}Wnty}ztdt|d}~wwztt|}Wntyt d|tj }Ynwt!j"#t$j%d}t!j"#|d ||f}d}t!j"&|rAt d!|t'|d" }|(}Wdn 1s;wYn|t)j)vrTt d#|t)j)|}n t d$|t)j)d}t d%|t d&t*|t!j"&|st d't }tj+|d(|d)} t,|||| |t d*t-| |||| .t/0|1}t!j"&|szt!2|Wnt3yt!j"&|słYnwt d+t'|d,d- }!|!4|Wdn 1swYt d.t!5|d,|t d/Wdn 1swY|dur?t d0zt'|d" }!|!(}Wdn 1s,wYWn t6y>td1wt7|d2d3}t8|\}"}#|"durRd4}"t9|"|||#|d5\}}$t$j:j;d6|d7}%t<|%t=srt=|>|%}%|%r}t?t|%d8}&nd9}&t!j@Ad:}'|'rt!j@d;}(|(rtBt|'|(d<})ntC})nd9})|4tDtEt|||||tF||)|&d= |1}nc|dkrd>}tGH|||| ||| | | | ||| }nJ|d krtDtj|tdd}*tDt|*}+|tItDttJ}|tK|+}|tLtDd?#t$jM}|t|*}d@tD|AdAt$jNd2d3},|dB|,}|||fS)Cz Given the source of the module, convert it to a Jinja2 template to insert module code and return whether it's a new or old style module. oldbinarynewris(from ansible.module_utils.basic import * powershells,#Requires -Module Ansible.ModuleUtils.Legacys#Requires -Modules#Requires -Versions#AnsibleRequires -OSVersions#AnsibleRequires -Powershells#AnsibleRequires -CSharpUtiljsonargss WANT_JSONnon_native_want_jsonN)r@rErAz)ANSIBALLZ: Could not determine module FQNzansible.modules.%srritzinfoz%cz7Cannot create zipfile due to pre-1980 configured date: )ANSIBLE_MODULE_ARGST)cls vault_to_textzDUnable to pass options to module, they must be JSON serializable: %szOBad module compression string specified: %s. Using ZIP_STORED (no compression)ansiballz_cachez%s-%sz"ANSIBALLZ: using cached module: %sr_zANSIBALLZ: Using lock for %sz$ANSIBALLZ: Using generic lock for %szANSIBALLZ: Acquiring lockzANSIBALLZ: Lock acquired: %szANSIBALLZ: Creating modulew)moderz&ANSIBALLZ: Writing module into payloadzANSIBALLZ: Writing modulez-partwbzANSIBALLZ: Renaming modulezANSIBALLZ: Done creating modulez$ANSIBALLZ: Reading module after lockzvA different worker process failed to create module file. Look at traceback for that process for debugging information.rrz/usr/bin/pythonrPYTHON_MODULE_RLIMIT_NOFILErk) rlimit_nofiler_ANSIBLE_COVERAGE_CONFIG_ANSIBLE_COVERAGE_OUTPUT)coverage_configcoverage_output) zipdataansible_moduler2paramsrcodingrcoveragerlimitz #!powershell,ssyslog.ansible_syslog_facilityssyslog.LOG_USER)Or.REPLACERreplaceNEW_STYLE_PYTHON_MODULE_REr1REPLACER_WINDOWSre IGNORECASEREPLACER_JSONARGSrr7rrdebugrrdatetimetimezoneutcstrftimer dictreprjsondumpsr TypeErrorrgetattrrAttributeErrorr  ZIP_STOREDr`rar#rwDEFAULT_LOCAL_TMPrbrdreridZipFilerr?closebase64 b64encodegetvaluemakedirsOSErrorwriterenameIOErrorr_extract_interpreterrrxrzrAintr{ANSIBALLZ_RLIMIT_TEMPLATEenvironr|ANSIBALLZ_COVERAGE_TEMPLATE!ANSIBALLZ_COVERAGE_CHECK_TEMPLATErACTIVE_ANSIBALLZ_TEMPLATEENCODING_STRING ps_manifest_create_powershell_wrapperREPLACER_VERSIONrREPLACER_COMPLEXREPLACER_SELINUXDEFAULT_SELINUX_SPECIAL_FSDEFAULT_SYSLOG_FACILITY)- module_namer+r4 module_argsrrmodule_compression async_timeoutbecome become_method become_userbecome_password become_flags environmentrmodule_substyle module_styleroutputr5r date_stringrWpython_repred_paramsrcompression_method lookup_pathcached_module_filenamerUrlock zipoutputrf o_interpretero_argsr~rPrZrSrTrYmodule_args_jsonpython_repred_argsfacilityr(r(r)_find_module_utils/sF                        .                    rcCsrd}g}|dd}|ddr5|d}tt|dddd}d d |D}|d}|dd}||fS) z Used to extract shebang expression from binary module data and return a text string with the shebang, or None if no shebang is detected. N rRrs#!rrrcSsg|]}t|ddqS)rr)r)rar(r(r)r5sz(_extract_interpreter..)rNr!r shlexr)r+r~r:b_lines b_shebang cli_splitr(r(r)r}%s   r}rpcCs"|durin|}| durin| } t|d }|}Wdn1s$wYt||||||||||| | | | | d\}}}|dkrL||t|ddfS|durt|\}}|durt||||| d\}}|dd }||krxt|d dd |d <tj | d r| d t d|}|||fS)a Used to insert chunks of code into modules before transfer rather than doing regular python imports. This allows for more efficient transfer in a non-bootstrapping scenario by not moving extra files over the wire and also takes care of embedding arguments in the transferred modules. This version is done in such a way that local imports can still be used in the module code, so IDEs don't have to be aware of what is going on. Example: from ansible.module_utils.basic import * ... will result in the insertion of basic.py into the module from the module_utils/ directory in the source tree. For powershell, this code effectively no-ops, as the exec wrapper requires access to a number of properties not available here. Nr_)rrrrrrrrrApassthru) nonstringrNrrRr)rrrri)rdrerrr}rrNrr`rarur!insertb_ENCODING_STRINGr#)rr4rrrrrrrrrrrrrr+rrr~r:new_interpreterrr(r(r) modify_module<s.        rc Cs|durd}tj|dg}n||g}i}i}t|tr(|D]} || q ||}|D] } | drO| dd} | |vrO||d| pKi q/|||i |||S)NzFinding module_defaults for action %s. The caller has not passed the action_groups, so any that may include this action will be ignored.)rzgroup/rzgroup/%s) rr r|rArBupdater{r!rNcopy) actionr:defaultsr action_groupsr group_namestmp_argsmodule_defaultsdefault group_namer(r(r)get_action_args_with_defaultsvs*       rrrZ) NrprFNNNNNF)_ __future__rr?rurerkr`rrrrarrrrioransible.releaserrrr rwansible.errorsr &ansible.executor.interpreter_discoveryr ansible.executor.powershellr r ansible.module_utils.common.jsonr +ansible.module_utils.common.text.convertersrrransible.plugins.loaderr2ansible.utils.collection_loader._collection_finderrransible.executorransible.utils.displayr collectionsrimportlib.utilrimportlib.machineryrrr]rrr`rcrrrrar#dirname__file__rANSIBALLZ_TEMPLATErrrr*DEFAULT_KEEP_REMOTE_FILESr site_packagesrescaper0r2r_ NodeVisitorr+rhrMrrrrrrr.r7r?rr}rrr(r(r(r)s                9* 8 t!# w :