コード例 #1
0
ファイル: module_common.py プロジェクト: awiddersheim/ansible
def recursive_finder(name, data, py_module_names, py_module_cache, zf):
    """
    Using ModuleDepFinder, make sure we have all of the module_utils files that
    the module its module_utils files needs.
    """
    # Parse the module and find the imports of ansible.module_utils
    tree = ast.parse(data)
    finder = ModuleDepFinder()
    finder.visit(tree)

    #
    # Determine what imports that we've found are modules (vs class, function.
    # variable names) for packages
    #

    normalized_modules = set()
    # Loop through the imports that we've found to normalize them
    # Exclude paths that match with paths we've already processed
    # (Have to exclude them a second time once the paths are processed)

    module_utils_paths = [p for p in module_utils_loader._get_paths(subdirs=False) if os.path.isdir(p)]
    module_utils_paths.append(_MODULE_UTILS_PATH)
    for py_module_name in finder.submodules.difference(py_module_names):
        module_info = None

        if py_module_name[0] == 'six':
            # Special case the python six library because it messes up the
            # import process in an incompatible way
            module_info = imp.find_module('six', module_utils_paths)
            py_module_name = ('six',)
            idx = 0
        elif py_module_name[0] == '_six':
            # Special case the python six library because it messes up the
            # import process in an incompatible way
            module_info = imp.find_module('_six', [os.path.join(p, 'six') for p in module_utils_paths])
            py_module_name = ('six', '_six')
            idx = 0
        else:
            # Check whether either the last or the second to last identifier is
            # a module name
            for idx in (1, 2):
                if len(py_module_name) < idx:
                    break
                try:
                    module_info = imp.find_module(py_module_name[-idx],
                                                  [os.path.join(p, *py_module_name[:-idx]) for p in module_utils_paths])
                    break
                except ImportError:
                    continue

        # Could not find the module.  Construct a helpful error message.
        if module_info is None:
            msg = ['Could not find imported module support code for %s.  Looked for' % (name,)]
            if idx == 2:
                msg.append('either %s.py or %s.py' % (py_module_name[-1], py_module_name[-2]))
            else:
                msg.append(py_module_name[-1])
            raise AnsibleError(' '.join(msg))

        # Found a byte compiled file rather than source.  We cannot send byte
        # compiled over the wire as the python version might be different.
        # imp.find_module seems to prefer to return source packages so we just
        # error out if imp.find_module returns byte compiled files (This is
        # fragile as it depends on undocumented imp.find_module behaviour)
        if module_info[2][2] not in (imp.PY_SOURCE, imp.PKG_DIRECTORY):
            msg = ['Could not find python source for imported module support code for %s.  Looked for' % name]
            if idx == 2:
                msg.append('either %s.py or %s.py' % (py_module_name[-1], py_module_name[-2]))
            else:
                msg.append(py_module_name[-1])
            raise AnsibleError(' '.join(msg))

        if idx == 2:
            # We've determined that the last portion was an identifier and
            # thus, not part of the module name
            py_module_name = py_module_name[:-1]

        # If not already processed then we've got work to do
        if py_module_name not in py_module_names:
            # If not in the cache, then read the file into the cache
            # We already have a file handle for the module open so it makes
            # sense to read it now
            if py_module_name not in py_module_cache:
                if module_info[2][2] == imp.PKG_DIRECTORY:
                    # Read the __init__.py instead of the module file as this is
                    # a python package
                    normalized_name = py_module_name + ('__init__',)
                    normalized_path = os.path.join(os.path.join(module_info[1], '__init__.py'))
                    normalized_data = _slurp(normalized_path)
                else:
                    normalized_name = py_module_name
                    normalized_path = module_info[1]
                    normalized_data = module_info[0].read()
                    module_info[0].close()

                py_module_cache[normalized_name] = (normalized_data, normalized_path)
                normalized_modules.add(normalized_name)

            # Make sure that all the packages that this module is a part of
            # are also added
            for i in range(1, len(py_module_name)):
                py_pkg_name = py_module_name[:-i] + ('__init__',)
                if py_pkg_name not in py_module_names:
                    pkg_dir_info = imp.find_module(py_pkg_name[-1],
                                                   [os.path.join(p, *py_pkg_name[:-1]) for p in module_utils_paths])
                    normalized_modules.add(py_pkg_name)
                    py_module_cache[py_pkg_name] = (_slurp(pkg_dir_info[1]), pkg_dir_info[1])

    #
    # iterate through all of the ansible.module_utils* imports that we haven't
    # already checked for new imports
    #

    # set of modules that we haven't added to the zipfile
    unprocessed_py_module_names = normalized_modules.difference(py_module_names)

    for py_module_name in unprocessed_py_module_names:
        py_module_path = os.path.join(*py_module_name)
        py_module_file_name = '%s.py' % py_module_path

        zf.writestr(os.path.join("ansible/module_utils",
                    py_module_file_name), py_module_cache[py_module_name][0])
        display.vvvvv("Using module_utils file %s" % py_module_cache[py_module_name][1])

    # Add the names of the files we're scheduling to examine in the loop to
    # py_module_names so that we don't re-examine them in the next pass
    # through recursive_finder()
    py_module_names.update(unprocessed_py_module_names)

    for py_module_file in unprocessed_py_module_names:
        recursive_finder(py_module_file, py_module_cache[py_module_file][0], py_module_names, py_module_cache, zf)
        # Save memory; the file won't have to be read again for this ansible module.
        del py_module_cache[py_module_file]
コード例 #2
0
def recursive_finder(name, data, py_module_names, py_module_cache, zf):
    """
    Using ModuleDepFinder, make sure we have all of the module_utils files that
    the module its module_utils files needs.
    """
    # Parse the module and find the imports of ansible.module_utils
    try:
        tree = ast.parse(data)
    except (SyntaxError, IndentationError) as e:
        raise AnsibleError("Unable to import %s due to %s" % (name, e.msg))
    finder = ModuleDepFinder()
    finder.visit(tree)

    #
    # Determine what imports that we've found are modules (vs class, function.
    # variable names) for packages
    #

    normalized_modules = set()
    # Loop through the imports that we've found to normalize them
    # Exclude paths that match with paths we've already processed
    # (Have to exclude them a second time once the paths are processed)

    module_utils_paths = [
        p for p in module_utils_loader._get_paths(subdirs=False)
        if os.path.isdir(p)
    ]
    module_utils_paths.append(_MODULE_UTILS_PATH)
    for py_module_name in finder.submodules.difference(py_module_names):
        module_info = None

        if py_module_name[0] == 'six':
            # Special case the python six library because it messes up the
            # import process in an incompatible way
            module_info = imp.find_module('six', module_utils_paths)
            py_module_name = ('six', )
            idx = 0
        elif py_module_name[0] == '_six':
            # Special case the python six library because it messes up the
            # import process in an incompatible way
            module_info = imp.find_module(
                '_six', [os.path.join(p, 'six') for p in module_utils_paths])
            py_module_name = ('six', '_six')
            idx = 0
        elif py_module_name[0] == 'ansible_collections':
            # FIXME: replicate module name resolution like below for granular imports
            # this is a collection-hosted MU; look it up with get_data
            package_name = '.'.join(py_module_name[:-1])
            resource_name = py_module_name[-1] + '.py'
            try:
                # FIXME: need this in py2 for some reason TBD, but we shouldn't (get_data delegates to wrong loader without it)
                pkg = import_module(package_name)
                module_info = pkgutil.get_data(package_name, resource_name)
            except FileNotFoundError:
                # FIXME: implement package fallback code
                raise AnsibleError(
                    'unable to load collection-hosted module_util {0}.{1}'.
                    format(to_native(package_name), to_native(resource_name)))
            idx = 0
        else:
            # Check whether either the last or the second to last identifier is
            # a module name
            for idx in (1, 2):
                if len(py_module_name) < idx:
                    break
                try:
                    module_info = imp.find_module(py_module_name[-idx], [
                        os.path.join(p, *py_module_name[:-idx])
                        for p in module_utils_paths
                    ])
                    break
                except ImportError:
                    continue

        # Could not find the module.  Construct a helpful error message.
        if module_info is None:
            msg = [
                'Could not find imported module support code for %s.  Looked for'
                % (name, )
            ]
            if idx == 2:
                msg.append('either %s.py or %s.py' %
                           (py_module_name[-1], py_module_name[-2]))
            else:
                msg.append(py_module_name[-1])
            raise AnsibleError(' '.join(msg))

        if isinstance(module_info, bytes):  # collection-hosted, just the code
            # HACK: maybe surface collection dirs in here and use existing find_module code?
            normalized_name = py_module_name
            normalized_data = module_info
            normalized_path = os.path.join(*py_module_name)
            py_module_cache[normalized_name] = (normalized_data,
                                                normalized_path)
            normalized_modules.add(normalized_name)

            # HACK: walk back up the package hierarchy to pick up package inits; this won't do the right thing
            # for actual packages yet...
            accumulated_pkg_name = []
            for pkg in py_module_name[:-1]:
                accumulated_pkg_name.append(
                    pkg)  # we're accumulating this across iterations
                normalized_name = tuple(accumulated_pkg_name[:] + [
                    '__init__'
                ])  # extra machinations to get a hashable type (list is not)
                if normalized_name not in py_module_cache:
                    normalized_path = os.path.join(*accumulated_pkg_name)
                    # HACK: possibly preserve some of the actual package file contents; problematic for extend_paths and others though?
                    normalized_data = ''
                    py_module_cache[normalized_name] = (normalized_data,
                                                        normalized_path)
                    normalized_modules.add(normalized_name)

        else:
            # Found a byte compiled file rather than source.  We cannot send byte
            # compiled over the wire as the python version might be different.
            # imp.find_module seems to prefer to return source packages so we just
            # error out if imp.find_module returns byte compiled files (This is
            # fragile as it depends on undocumented imp.find_module behaviour)
            if module_info[2][2] not in (imp.PY_SOURCE, imp.PKG_DIRECTORY):
                msg = [
                    'Could not find python source for imported module support code for %s.  Looked for'
                    % name
                ]
                if idx == 2:
                    msg.append('either %s.py or %s.py' %
                               (py_module_name[-1], py_module_name[-2]))
                else:
                    msg.append(py_module_name[-1])
                raise AnsibleError(' '.join(msg))

            if idx == 2:
                # We've determined that the last portion was an identifier and
                # thus, not part of the module name
                py_module_name = py_module_name[:-1]

            # If not already processed then we've got work to do
            # If not in the cache, then read the file into the cache
            # We already have a file handle for the module open so it makes
            # sense to read it now
            if py_module_name not in py_module_cache:
                if module_info[2][2] == imp.PKG_DIRECTORY:
                    # Read the __init__.py instead of the module file as this is
                    # a python package
                    normalized_name = py_module_name + ('__init__', )
                    if normalized_name not in py_module_names:
                        normalized_path = os.path.join(module_info[1],
                                                       '__init__.py')
                        normalized_data = _slurp(normalized_path)
                        py_module_cache[normalized_name] = (normalized_data,
                                                            normalized_path)
                        normalized_modules.add(normalized_name)
                else:
                    normalized_name = py_module_name
                    if normalized_name not in py_module_names:
                        normalized_path = module_info[1]
                        normalized_data = module_info[0].read()
                        module_info[0].close()
                        py_module_cache[normalized_name] = (normalized_data,
                                                            normalized_path)
                        normalized_modules.add(normalized_name)

                # Make sure that all the packages that this module is a part of
                # are also added
                for i in range(1, len(py_module_name)):
                    py_pkg_name = py_module_name[:-i] + ('__init__', )
                    if py_pkg_name not in py_module_names:
                        pkg_dir_info = imp.find_module(py_pkg_name[-1], [
                            os.path.join(p, *py_pkg_name[:-1])
                            for p in module_utils_paths
                        ])
                        normalized_modules.add(py_pkg_name)
                        py_module_cache[py_pkg_name] = (_slurp(
                            pkg_dir_info[1]), pkg_dir_info[1])

    # FIXME: Currently the AnsiBallZ wrapper monkeypatches module args into a global
    # variable in basic.py.  If a module doesn't import basic.py, then the AnsiBallZ wrapper will
    # traceback when it tries to monkypatch.  So, for now, we have to unconditionally include
    # basic.py.
    #
    # In the future we need to change the wrapper to monkeypatch the args into a global variable in
    # their own, separate python module.  That way we won't require basic.py.  Modules which don't
    # want basic.py can import that instead.  AnsibleModule will need to change to import the vars
    # from the separate python module and mirror the args into its global variable for backwards
    # compatibility.
    if ('basic', ) not in py_module_names:
        pkg_dir_info = imp.find_module('basic', module_utils_paths)
        normalized_modules.add(('basic', ))
        py_module_cache[('basic', )] = (_slurp(pkg_dir_info[1]),
                                        pkg_dir_info[1])
    # End of AnsiballZ hack

    #
    # iterate through all of the ansible.module_utils* imports that we haven't
    # already checked for new imports
    #

    # set of modules that we haven't added to the zipfile
    unprocessed_py_module_names = normalized_modules.difference(
        py_module_names)

    for py_module_name in unprocessed_py_module_names:
        # HACK: this seems to work as a way to identify a collections-based import, but a stronger identifier would be better
        if not py_module_cache[py_module_name][1].startswith('/'):
            dir_prefix = ''
        else:
            dir_prefix = 'ansible/module_utils'

        py_module_path = os.path.join(*py_module_name)
        py_module_file_name = '%s.py' % py_module_path

        zf.writestr(os.path.join(dir_prefix, py_module_file_name),
                    py_module_cache[py_module_name][0])
        display.vvvvv("Using module_utils file %s" %
                      py_module_cache[py_module_name][1])

    # Add the names of the files we're scheduling to examine in the loop to
    # py_module_names so that we don't re-examine them in the next pass
    # through recursive_finder()
    py_module_names.update(unprocessed_py_module_names)

    for py_module_file in unprocessed_py_module_names:
        recursive_finder(py_module_file, py_module_cache[py_module_file][0],
                         py_module_names, py_module_cache, zf)
        # Save memory; the file won't have to be read again for this ansible module.
        del py_module_cache[py_module_file]
コード例 #3
0
ファイル: module_common.py プロジェクト: nvngpt31/ansible-3
def recursive_finder(name, data, py_module_names, py_module_cache, zf):
    """
    Using ModuleDepFinder, make sure we have all of the module_utils files that
    the module its module_utils files needs.
    """
    # Parse the module and find the imports of ansible.module_utils
    tree = ast.parse(data)
    finder = ModuleDepFinder()
    finder.visit(tree)

    #
    # Determine what imports that we've found are modules (vs class, function.
    # variable names) for packages
    #

    normalized_modules = set()
    # Loop through the imports that we've found to normalize them
    # Exclude paths that match with paths we've already processed
    # (Have to exclude them a second time once the paths are processed)

    module_utils_paths = [p for p in module_utils_loader._get_paths(subdirs=False) if os.path.isdir(p)]
    module_utils_paths.append(_MODULE_UTILS_PATH)
    for py_module_name in finder.submodules.difference(py_module_names):
        module_info = None

        if py_module_name[0] == 'six':
            # Special case the python six library because it messes up the
            # import process in an incompatible way
            module_info = imp.find_module('six', module_utils_paths)
            py_module_name = ('six',)
            idx = 0
        elif py_module_name[0] == '_six':
            # Special case the python six library because it messes up the
            # import process in an incompatible way
            module_info = imp.find_module('_six', [os.path.join(p, 'six') for p in module_utils_paths])
            py_module_name = ('six', '_six')
            idx = 0
        else:
            # Check whether either the last or the second to last identifier is
            # a module name
            for idx in (1, 2):
                if len(py_module_name) < idx:
                    break
                try:
                    module_info = imp.find_module(py_module_name[-idx],
                                                  [os.path.join(p, *py_module_name[:-idx]) for p in module_utils_paths])
                    break
                except ImportError:
                    continue

        # Could not find the module.  Construct a helpful error message.
        if module_info is None:
            msg = ['Could not find imported module support code for %s.  Looked for' % (name,)]
            if idx == 2:
                msg.append('either %s.py or %s.py' % (py_module_name[-1], py_module_name[-2]))
            else:
                msg.append(py_module_name[-1])
            raise AnsibleError(' '.join(msg))

        # Found a byte compiled file rather than source.  We cannot send byte
        # compiled over the wire as the python version might be different.
        # imp.find_module seems to prefer to return source packages so we just
        # error out if imp.find_module returns byte compiled files (This is
        # fragile as it depends on undocumented imp.find_module behaviour)
        if module_info[2][2] not in (imp.PY_SOURCE, imp.PKG_DIRECTORY):
            msg = ['Could not find python source for imported module support code for %s.  Looked for' % name]
            if idx == 2:
                msg.append('either %s.py or %s.py' % (py_module_name[-1], py_module_name[-2]))
            else:
                msg.append(py_module_name[-1])
            raise AnsibleError(' '.join(msg))

        if idx == 2:
            # We've determined that the last portion was an identifier and
            # thus, not part of the module name
            py_module_name = py_module_name[:-1]

        # If not already processed then we've got work to do
        # If not in the cache, then read the file into the cache
        # We already have a file handle for the module open so it makes
        # sense to read it now
        if py_module_name not in py_module_cache:
            if module_info[2][2] == imp.PKG_DIRECTORY:
                # Read the __init__.py instead of the module file as this is
                # a python package
                normalized_name = py_module_name + ('__init__',)
                if normalized_name not in py_module_names:
                    normalized_path = os.path.join(os.path.join(module_info[1], '__init__.py'))
                    normalized_data = _slurp(normalized_path)
                    py_module_cache[normalized_name] = (normalized_data, normalized_path)
                    normalized_modules.add(normalized_name)
            else:
                normalized_name = py_module_name
                if normalized_name not in py_module_names:
                    normalized_path = module_info[1]
                    normalized_data = module_info[0].read()
                    module_info[0].close()
                    py_module_cache[normalized_name] = (normalized_data, normalized_path)
                    normalized_modules.add(normalized_name)

            # Make sure that all the packages that this module is a part of
            # are also added
            for i in range(1, len(py_module_name)):
                py_pkg_name = py_module_name[:-i] + ('__init__',)
                if py_pkg_name not in py_module_names:
                    pkg_dir_info = imp.find_module(py_pkg_name[-1],
                                                   [os.path.join(p, *py_pkg_name[:-1]) for p in module_utils_paths])
                    normalized_modules.add(py_pkg_name)
                    py_module_cache[py_pkg_name] = (_slurp(pkg_dir_info[1]), pkg_dir_info[1])

    # FIXME: Currently the AnsiBallZ wrapper monkeypatches module args into a global
    # variable in basic.py.  If a module doesn't import basic.py, then the AnsiBallZ wrapper will
    # traceback when it tries to monkypatch.  So, for now, we have to unconditionally include
    # basic.py.
    #
    # In the future we need to change the wrapper to monkeypatch the args into a global variable in
    # their own, separate python module.  That way we won't require basic.py.  Modules which don't
    # want basic.py can import that instead.  AnsibleModule will need to change to import the vars
    # from the separate python module and mirror the args into its global variable for backwards
    # compatibility.
    if ('basic',) not in py_module_names:
        pkg_dir_info = imp.find_module('basic', module_utils_paths)
        normalized_modules.add(('basic',))
        py_module_cache[('basic',)] = (_slurp(pkg_dir_info[1]), pkg_dir_info[1])
    # End of AnsiballZ hack

    #
    # iterate through all of the ansible.module_utils* imports that we haven't
    # already checked for new imports
    #

    # set of modules that we haven't added to the zipfile
    unprocessed_py_module_names = normalized_modules.difference(py_module_names)

    for py_module_name in unprocessed_py_module_names:
        py_module_path = os.path.join(*py_module_name)
        py_module_file_name = '%s.py' % py_module_path

        zf.writestr(os.path.join("ansible/module_utils",
                    py_module_file_name), py_module_cache[py_module_name][0])
        display.vvvvv("Using module_utils file %s" % py_module_cache[py_module_name][1])

    # Add the names of the files we're scheduling to examine in the loop to
    # py_module_names so that we don't re-examine them in the next pass
    # through recursive_finder()
    py_module_names.update(unprocessed_py_module_names)

    for py_module_file in unprocessed_py_module_names:
        recursive_finder(py_module_file, py_module_cache[py_module_file][0], py_module_names, py_module_cache, zf)
        # Save memory; the file won't have to be read again for this ansible module.
        del py_module_cache[py_module_file]
コード例 #4
0
 def get_search_path(self, invocation):
     return tuple(path
                  for path in module_utils_loader._get_paths(subdirs=False)
                  if os.path.isdir(path))