Esempio n. 1
0
    def test_all_no_duplicate_names(self, gp_mock, glob_mock):
        '''
        This test goes along with ``test__load_module_source_no_duplicate_names``
        and ensures that we ignore duplicate imports on multiple paths
        '''

        fixture_path = os.path.join(os.path.dirname(__file__), 'loader_fixtures')

        gp_mock.return_value = [
            fixture_path,
            '/path/to'
        ]

        glob_mock.glob.side_effect = [
            [os.path.join(fixture_path, 'import_fixture.py')],
            ['/path/to/import_fixture.py']
        ]

        pl = PluginLoader('test', '', 'test', 'test_plugin')
        # Aside from needing ``list()`` so we can do a len, ``PluginLoader.all`` returns a generator
        # so ``list()`` actually causes ``PluginLoader.all`` to run.
        plugins = list(pl.all())
        self.assertEqual(len(plugins), 1)

        self.assertIn(os.path.join(fixture_path, 'import_fixture.py'), pl._module_cache)
        self.assertNotIn('/path/to/import_fixture.py', pl._module_cache)
Esempio n. 2
0
 def test_print_paths(self, mock_method):
     mock_method.return_value = ['/path/one', '/path/two', '/path/three']
     pl = PluginLoader('foo', 'foo', '', 'test_plugins')
     paths = pl.print_paths()
     expected_paths = os.pathsep.join(
         ['/path/one', '/path/two', '/path/three'])
     self.assertEqual(paths, expected_paths)
Esempio n. 3
0
 def test_plugins__get_paths(self):
     pl = PluginLoader('test', '', 'test', 'test_plugin')
     pl._paths = [
         PluginPathContext('/path/one', False),
         PluginPathContext('/path/two', True)
     ]
     self.assertEqual(pl._get_paths(), ['/path/one', '/path/two'])
Esempio n. 4
0
    def test_all_no_duplicate_names(self, gp_mock, glob_mock):
        '''
        This test goes along with ``test__load_module_source_no_duplicate_names``
        and ensures that we ignore duplicate imports on multiple paths
        '''

        fixture_path = os.path.join(os.path.dirname(__file__), 'loader_fixtures')

        gp_mock.return_value = [
            fixture_path,
            '/path/to'
        ]

        glob_mock.glob.side_effect = [
            [os.path.join(fixture_path, 'import_fixture.py')],
            ['/path/to/import_fixture.py']
        ]

        pl = PluginLoader('test', '', 'test', 'test_plugin')
        # Aside from needing ``list()`` so we can do a len, ``PluginLoader.all`` returns a generator
        # so ``list()`` actually causes ``PluginLoader.all`` to run.
        plugins = list(pl.all())
        self.assertEqual(len(plugins), 1)

        self.assertIn(os.path.join(fixture_path, 'import_fixture.py'), pl._module_cache)
        self.assertNotIn('/path/to/import_fixture.py', pl._module_cache)
Esempio n. 5
0
    def setUp(self):

        class Inventory():
            cache = dict()

        class PopenResult():
            returncode = 0
            stdout = b""
            stderr = b""

            def communicate(self):
                return (self.stdout, self.stderr)

        self.popen_result = PopenResult()
        self.inventory = Inventory()
        self.loader = mock.MagicMock()
        self.loader.load = mock.MagicMock()

        inv_loader = PluginLoader('InventoryModule', 'ansible.plugins.inventory', C.DEFAULT_INVENTORY_PLUGIN_PATH, 'inventory_plugins')
        self.inventory_module = inv_loader.get('script')
        self.inventory_module.set_options()

        def register_patch(name):
            patcher = mock.patch(name)
            self.addCleanup(patcher.stop)
            return patcher.start()

        self.popen = register_patch('subprocess.Popen')
        self.popen.return_value = self.popen_result

        self.BaseInventoryPlugin = register_patch('ansible.plugins.inventory.BaseInventoryPlugin')
        self.BaseInventoryPlugin.get_cache_prefix.return_value = 'abc123'
Esempio n. 6
0
 def test_plugins__get_package_paths_with_package(self):
     # the _get_package_paths() call uses __import__ to load a
     # python library, and then uses the __file__ attribute of
     # the result for that to get the library path, so we mock
     # that here and patch the builtin to use our mocked result
     foo = MagicMock()
     bar = MagicMock()
     bam = MagicMock()
     bam.__file__ = '/path/to/my/foo/bar/bam/__init__.py'
     bar.bam = bam
     foo.return_value.bar = bar
     pl = PluginLoader('test', 'foo.bar.bam', 'test', 'test_plugin')
     with patch('{0}.__import__'.format(BUILTINS), foo):
         self.assertEqual(pl._get_package_paths(), ['/path/to/my/foo/bar/bam'])
Esempio n. 7
0
 def test_plugins__get_package_paths_with_package(self):
     # the _get_package_paths() call uses __import__ to load a
     # python library, and then uses the __file__ attribute of
     # the result for that to get the library path, so we mock
     # that here and patch the builtin to use our mocked result
     foo = MagicMock()
     bar = MagicMock()
     bam = MagicMock()
     bam.__file__ = '/path/to/my/foo/bar/bam/__init__.py'
     bar.bam = bam
     foo.return_value.bar = bar
     pl = PluginLoader('test', 'foo.bar.bam', 'test', 'test_plugin')
     with patch('{0}.__import__'.format(BUILTINS), foo):
         self.assertEqual(pl._get_package_paths(), ['/path/to/my/foo/bar/bam'])
Esempio n. 8
0
    def test__load_module_source_no_duplicate_names(self):
        '''
        This test simulates importing 2 plugins with the same name,
        and validating that the import is shortcirtuited if a file with the same name
        has already been imported
        '''

        fixture_path = os.path.join(os.path.dirname(__file__), 'loader_fixtures')

        pl = PluginLoader('test', '', 'test', 'test_plugin')
        one = pl._load_module_source('import_fixture', os.path.join(fixture_path, 'import_fixture.py'))
        # This line wouldn't even succeed if we didn't short cirtuit on finding a duplicate name
        two = pl._load_module_source('import_fixture', '/path/to/import_fixture.py')

        self.assertEqual(one, two)
Esempio n. 9
0
    def test__load_module_source_no_duplicate_names(self):
        '''
        This test simulates importing 2 plugins with the same name,
        and validating that the import is short circuited if a file with the same name
        has already been imported
        '''

        fixture_path = os.path.join(os.path.dirname(__file__), 'loader_fixtures')

        pl = PluginLoader('test', '', 'test', 'test_plugin')
        one = pl._load_module_source('import_fixture', os.path.join(fixture_path, 'import_fixture.py'))
        # This line wouldn't even succeed if we didn't short circuit on finding a duplicate name
        two = pl._load_module_source('import_fixture', '/path/to/import_fixture.py')

        self.assertEqual(one, two)
Esempio n. 10
0
    def _setup_inventory_plugins(self):
        ''' sets up loaded inventory plugins for usage '''

        inventory_loader = PluginLoader('InventoryModule', 'ansible.plugins.inventory', 'inventory_plugins', 'inventory_plugins')
        display.vvvv('setting up inventory plugins')

        for name in C.INVENTORY_ENABLED:
            plugin = inventory_loader.get(name)
            if plugin:
                self._inventory_plugins.append(plugin)
            else:
                display.warning('Failed to load inventory plugin, skipping %s' % name)

        if not self._inventory_plugins:
            raise AnsibleError("No inventory plugins available to generate inventory, make sure you have at least one whitelisted.")
Esempio n. 11
0
    def _setup_inventory_plugins(self):
        ''' sets up loaded inventory plugins for usage '''

        inventory_loader = PluginLoader('InventoryModule', 'ansible.plugins.inventory', C.DEFAULT_INVENTORY_PLUGIN_PATH, 'inventory_plugins')
        display.vvvv('setting up inventory plugins')

        for name in C.INVENTORY_ENABLED:
            plugin = inventory_loader.get(name)
            if plugin:
                self._inventory_plugins.append(plugin)
            else:
                display.warning('Failed to load inventory plugin, skipping %s' % name)

        if not self._inventory_plugins:
            raise AnsibleError("No inventory plugins available to generate inventory, make sure you have at least one whitelisted.")
Esempio n. 12
0
class Template(object):
    def __init__(self, root_dir, ops_config):
        loader = ChoiceLoader(
            [FileSystemLoader(root_dir),
             FileSystemLoader("/")])

        mode = ops_config.get('jinja2.undefined')
        undefined = Undefined
        if mode == 'StrictUndefined':
            undefined = StrictUndefined
        elif mode == 'DebugUndefined':
            undefined = DebugUndefined

        self.env = Environment(loader=loader, undefined=undefined)

        self.filter_plugin_loader = PluginLoader(
            'FilterModule', 'ansible.plugins.filter',
            ops_config.ansible_filter_plugins.split(':'), 'filter_plugins')

        for filter in self.filter_plugin_loader.all():
            self.env.filters.update(filter.filters())

    def render(self, source, vars):
        jinja_template = self.env.get_template(source)

        return jinja_template.render(**vars)
Esempio n. 13
0
def get_fragment_loader():
    fragment_loader = PluginLoader(
        'ModuleDocFragment',  # class_name
        '',  # package
        '{0}/library/plugins/doc_fragments'.format(BASE_DIR),  # config
        '',  # subdir
    )
    return fragment_loader
Esempio n. 14
0

import jinja2
import yaml
from jinja2 import Environment, FileSystemLoader
from six import iteritems, string_types

from ansible.errors import AnsibleError
from ansible.module_utils._text import to_bytes, to_text
from ansible.plugins.loader import PluginLoader
from ansible.utils import plugin_docs
from ansible.utils.display import Display

fragment_loader = PluginLoader(
    'ModuleDocFragment',  # class_name
    '',  # package
    '/here/library/utils/module_docs_fragments',  # config
    '',  # subdir
)

#####################################################################################
# constants and paths

# if a module is added in a version of Ansible older than this, don't print the version added information
# in the module documentation because everyone is assumed to be running something newer than this already.
TOO_OLD_TO_BE_NOTABLE = 1.3

# Get parent directory of the directory this script lives in
MODULEDIR = os.path.abspath(
    os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir, 'lib',
                 'ansible', 'modules'))
Esempio n. 15
0
# (c) 2018, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.plugins.loader import PluginLoader
import json

parser_loader = PluginLoader('ParserEngine', 'parsers', None,
                             'show_to_facts_parsers')


class ToFacts(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, 'to_facts'):
            return obj.to_facts()
        else:
            return json.JSONEncoder.default(self, obj)
Esempio n. 16
0
# (c) 2018, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
#
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from ansible.plugins.loader import PluginLoader

template_loader = PluginLoader('TemplateEngine',
                               'network_engine.plugins.template',
                               None,
                               'template_plugins',
                               required_base_class='TemplateBase')

parser_loader = PluginLoader(
    'ParserEngine',
    'network_engine.plugins.parser',
    None,
    'parser_plugins',
    # required_base_class='ParserBase'
)
Esempio n. 17
0
    def run(self):

        super(DocCLI, self).run()

        plugin_type = self.options.type

        # choose plugin type
        if plugin_type == 'cache':
            loader = cache_loader
        elif plugin_type == 'callback':
            loader = callback_loader
        elif plugin_type == 'connection':
            loader = connection_loader
        elif plugin_type == 'lookup':
            loader = lookup_loader
        elif plugin_type == 'strategy':
            loader = strategy_loader
        elif plugin_type == 'vars':
            loader = vars_loader
        elif plugin_type == 'inventory':
            loader = PluginLoader('InventoryModule',
                                  'ansible.plugins.inventory',
                                  'inventory_plugins', 'inventory_plugins')
        else:
            loader = module_loader

        # add to plugin path from command line
        if self.options.module_path:
            for path in self.options.module_path:
                if path:
                    loader.add_directory(path)

        # save only top level paths for errors
        search_paths = DocCLI.print_paths(loader)
        loader._paths = None  # reset so we can use subdirs below

        # list plugins for type
        if self.options.list_dir:
            paths = loader._get_paths()
            for path in paths:
                self.find_plugins(path, plugin_type)

            self.pager(self.get_plugin_list_text(loader))
            return 0

        # process all plugins of type
        if self.options.all_plugins:
            paths = loader._get_paths()
            for path in paths:
                self.find_plugins(path, plugin_type)
            self.args = sorted(set(self.plugin_list))

        if len(self.args) == 0:
            raise AnsibleOptionsError("Incorrect options passed")

        # process command line list
        text = ''
        for plugin in self.args:

            try:
                # if the plugin lives in a non-python file (eg, win_X.ps1), require the corresponding python file for docs
                filename = loader.find_plugin(plugin,
                                              mod_type='.py',
                                              ignore_deprecated=True,
                                              check_aliases=True)
                if filename is None:
                    display.warning("%s %s not found in:\n%s\n" %
                                    (plugin_type, plugin, search_paths))
                    continue

                if any(filename.endswith(x) for x in C.BLACKLIST_EXTS):
                    continue

                try:
                    doc, plainexamples, returndocs, metadata = plugin_docs.get_docstring(
                        filename, verbose=(self.options.verbosity > 0))
                except:
                    display.vvv(traceback.format_exc())
                    display.error(
                        "%s %s has a documentation error formatting or is missing documentation."
                        % (plugin_type, plugin))
                    continue

                if doc is not None:

                    # assign from other sections
                    doc['plainexamples'] = plainexamples
                    doc['returndocs'] = returndocs
                    doc['metadata'] = metadata

                    # generate extra data
                    if plugin_type == 'module':
                        # is there corresponding action plugin?
                        if plugin in action_loader:
                            doc['action'] = True
                        else:
                            doc['action'] = False
                    doc['filename'] = filename
                    doc['now_date'] = datetime.date.today().strftime(
                        '%Y-%m-%d')
                    if 'docuri' in doc:
                        doc['docuri'] = doc[plugin_type].replace('_', '-')

                    if self.options.show_snippet and plugin_type == 'module':
                        text += self.get_snippet_text(doc)
                    else:
                        text += self.get_man_text(doc)
                else:
                    # this typically means we couldn't even parse the docstring, not just that the YAML is busted,
                    # probably a quoting issue.
                    raise AnsibleError("Parsing produced an empty object.")
            except Exception as e:
                display.vvv(traceback.format_exc())
                raise AnsibleError(
                    "%s %s missing documentation (or could not parse documentation): %s\n"
                    % (plugin_type, plugin, str(e)))

        if text:
            self.pager(text)
        return 0
Esempio n. 18
0
 def test_plugins__get_paths(self):
     pl = PluginLoader('test', '', 'test', 'test_plugin')
     pl._paths = ['/path/one', '/path/two']
     self.assertEqual(pl._get_paths(), ['/path/one', '/path/two'])
Esempio n. 19
0
 def test_plugins__get_package_paths_no_package(self):
     pl = PluginLoader('test', '', 'test', 'test_plugin')
     self.assertEqual(pl._get_package_paths(), [])
Esempio n. 20
0
 def test_plugins__get_paths(self):
     pl = PluginLoader('test', '', 'test', 'test_plugin')
     pl._paths = ['/path/one', '/path/two']
     self.assertEqual(pl._get_paths(), ['/path/one', '/path/two'])
Esempio n. 21
0
 def test_plugins__get_package_paths_no_package(self):
     pl = PluginLoader('test', '', 'test', 'test_plugin')
     self.assertEqual(pl._get_package_paths(), [])
Esempio n. 22
0
 def test_print_paths(self, mock_method):
     mock_method.return_value = ['/path/one', '/path/two', '/path/three']
     pl = PluginLoader('foo', 'foo', '', 'test_plugins')
     paths = pl.print_paths()
     expected_paths = os.pathsep.join(['/path/one', '/path/two', '/path/three'])
     self.assertEqual(paths, expected_paths)
Esempio n. 23
0
 def assertPluginLoaderConfigBecomes(self, arg, expected):
     pl = PluginLoader('test', '', arg, 'test_plugin')
     self.assertEqual(pl.config, expected)
Esempio n. 24
0
    def run(self):

        super(DocCLI, self).run()

        plugin_type = self.options.type

        # choose plugin type
        if plugin_type == 'cache':
            loader = cache_loader
        elif plugin_type == 'callback':
            loader = callback_loader
        elif plugin_type == 'connection':
            loader = connection_loader
        elif plugin_type == 'lookup':
            loader = lookup_loader
        elif plugin_type == 'strategy':
            loader = strategy_loader
        elif plugin_type == 'vars':
            loader = vars_loader
        elif plugin_type == 'inventory':
            loader = PluginLoader('InventoryModule', 'ansible.plugins.inventory', 'inventory_plugins', 'inventory_plugins')
        else:
            loader = module_loader

        # add to plugin path from command line
        if self.options.module_path is not None:
            for i in self.options.module_path.split(os.pathsep):
                loader.add_directory(i)

        # save only top level paths for errors
        search_paths = DocCLI.print_paths(loader)
        loader._paths = None  # reset so we can use subdirs below

        # list plugins for type
        if self.options.list_dir:
            paths = loader._get_paths()
            for path in paths:
                self.find_plugins(path, plugin_type)

            self.pager(self.get_plugin_list_text(loader))
            return 0

        # process all plugins of type
        if self.options.all_plugins:
            paths = loader._get_paths()
            for path in paths:
                self.find_plugins(path, plugin_type)
            self.args = sorted(set(self.plugin_list))

        if len(self.args) == 0:
            raise AnsibleOptionsError("Incorrect options passed")

        # process command line list
        text = ''
        for plugin in self.args:

            try:
                # if the plugin lives in a non-python file (eg, win_X.ps1), require the corresponding python file for docs
                filename = loader.find_plugin(plugin, mod_type='.py', ignore_deprecated=True, check_aliases=True)
                if filename is None:
                    display.warning("%s %s not found in:\n%s\n" % (plugin_type, plugin, search_paths))
                    continue

                if any(filename.endswith(x) for x in C.BLACKLIST_EXTS):
                    continue

                try:
                    doc, plainexamples, returndocs, metadata = plugin_docs.get_docstring(filename, verbose=(self.options.verbosity > 0))
                except:
                    display.vvv(traceback.format_exc())
                    display.error("%s %s has a documentation error formatting or is missing documentation." % (plugin_type, plugin))
                    continue

                if doc is not None:

                    # assign from other sections
                    doc['plainexamples'] = plainexamples
                    doc['returndocs'] = returndocs
                    doc['metadata'] = metadata

                    # generate extra data
                    if plugin_type == 'module':
                        # is there corresponding action plugin?
                        if plugin in action_loader:
                            doc['action'] = True
                        else:
                            doc['action'] = False
                    doc['filename'] = filename
                    doc['now_date'] = datetime.date.today().strftime('%Y-%m-%d')
                    if 'docuri' in doc:
                        doc['docuri'] = doc[plugin_type].replace('_', '-')

                    if self.options.show_snippet and plugin_type == 'module':
                        text += self.get_snippet_text(doc)
                    else:
                        text += self.get_man_text(doc)
                else:
                    # this typically means we couldn't even parse the docstring, not just that the YAML is busted,
                    # probably a quoting issue.
                    raise AnsibleError("Parsing produced an empty object.")
            except Exception as e:
                display.vvv(traceback.format_exc())
                raise AnsibleError("%s %s missing documentation (or could not parse documentation): %s\n" % (plugin_type, plugin, str(e)))

        if text:
            self.pager(text)
        return 0