diff options
Diffstat (limited to 'plugins/modules/vyos_facts.py')
| -rw-r--r-- | plugins/modules/vyos_facts.py | 317 | 
1 files changed, 76 insertions, 241 deletions
| diff --git a/plugins/modules/vyos_facts.py b/plugins/modules/vyos_facts.py index c480969b..e4bf6697 100644 --- a/plugins/modules/vyos_facts.py +++ b/plugins/modules/vyos_facts.py @@ -1,65 +1,90 @@  #!/usr/bin/python -# -# This file is part of Ansible -# -# Ansible is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Ansible is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Ansible.  If not, see <http://www.gnu.org/licenses/>. -# +# -*- coding: utf-8 -*- +# Copyright 2019 Red Hat +# GNU General Public License v3.0+ +# (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +""" +The module file for vyos_facts +""" + +  ANSIBLE_METADATA = {'metadata_version': '1.1', -                    'status': ['preview'], +                    'status': [u'preview'],                      'supported_by': 'network'}  DOCUMENTATION = """  ---  module: vyos_facts -version_added: "2.2" -author: "Nathaniel Case (@qalthos)" -short_description: Collect facts from remote devices running VyOS +version_added: 2.2 +short_description: Get facts about vyos devices.  description: -  - Collects a base set of device facts from a remote device that -    is running VyOS.  This module prepends all of the -    base network fact keys with U(ansible_net_<fact>).  The facts -    module will always collect a base set of facts from the device -    and can enable or disable collection of additional facts. +  - Collects facts from network devices running the vyos operating +    system. This module places the facts gathered in the fact tree keyed by the +    respective resource name.  The facts module will always collect a +    base set of facts from the device and can enable or disable +    collection of additional facts. +author: +  - Nathaniel Case (@qalthos) +  - Nilashish Chakraborty (@Nilashishc)  extends_documentation_fragment: vyos  notes: -  - Tested against VYOS 1.1.7 +  - Tested against VyOS 1.1.8  options:    gather_subset:      description:        - When supplied, this argument will restrict the facts collected          to a given subset.  Possible values for this argument include -        all, default, config, and neighbors.  Can specify a list of -        values to include a larger subset.  Values can also be used +        all, default, config, and neighbors. Can specify a list of +        values to include a larger subset. Values can also be used          with an initial C(M(!)) to specify that a specific subset should          not be collected.      required: false      default: "!config" +  gather_network_resources: +    description: +      - When supplied, this argument will restrict the facts collected +        to a given subset. Possible values for this argument include +        all and the resources like interfaces. +        Can specify a list of values to include a larger subset. Values +        can also be used with an initial C(M(!)) to specify that a +        specific subset should not be collected. +    required: false +    version_added: "2.9" +    choices: ['all', 'interfaces', '!interfaces', 'l3_interfaces', '!l3_interfaces']  """  EXAMPLES = """ -- name: collect all facts from the device -  vyos_facts: +# Gather all facts +- vyos_facts:      gather_subset: all +    gather_network_resources: all -- name: collect only the config and default facts -  vyos_facts: +# collect only the config and default facts +- vyos_facts:      gather_subset: config -- name: collect everything exception the config -  vyos_facts: +# collect everything exception the config +- vyos_facts:      gather_subset: "!config" + +# Collect only the interfaces facts +- vyos_facts: +    gather_subset: +      - '!all' +      - '!min' +    gather_network_resources: +      - interfaces + +# Do not collect interfaces facts +- vyos_facts: +    gather_network_resources: +      - "!interfaces" + +# Collect interfaces and minimal default facts +- vyos_facts: +    gather_subset: min +    gather_network_resources: interfaces  """  RETURN = """ @@ -103,228 +128,38 @@ ansible_net_python_version:    description: The Python version Ansible controller is using    returned: always    type: str +ansible_net_gather_network_resources: +  description: The list of fact resource subsets collected from the device +  returned: always +  type: list  """ -import platform -import re -  from ansible.module_utils.basic import AnsibleModule -from ansible.module_utils.six import iteritems -from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import run_commands, get_capabilities +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.argspec.facts.facts import FactsArgs +from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.facts.facts import Facts  from ansible_collections.vyos.vyos.plugins.module_utils.network.vyos.vyos import vyos_argument_spec -class FactsBase(object): - -    COMMANDS = frozenset() - -    def __init__(self, module): -        self.module = module -        self.facts = dict() -        self.responses = None - -    def populate(self): -        self.responses = run_commands(self.module, list(self.COMMANDS)) - - -class Default(FactsBase): - -    COMMANDS = [ -        'show version', -    ] - -    def populate(self): -        super(Default, self).populate() -        data = self.responses[0] -        self.facts['serialnum'] = self.parse_serialnum(data) -        self.facts.update(self.platform_facts()) - -    def parse_serialnum(self, data): -        match = re.search(r'HW S/N:\s+(\S+)', data) -        if match: -            return match.group(1) - -    def platform_facts(self): -        platform_facts = {} - -        resp = get_capabilities(self.module) -        device_info = resp['device_info'] - -        platform_facts['system'] = device_info['network_os'] - -        for item in ('model', 'image', 'version', 'platform', 'hostname'): -            val = device_info.get('network_os_%s' % item) -            if val: -                platform_facts[item] = val - -        platform_facts['api'] = resp['network_api'] -        platform_facts['python_version'] = platform.python_version() - -        return platform_facts - - -class Config(FactsBase): - -    COMMANDS = [ -        'show configuration commands', -        'show system commit', -    ] - -    def populate(self): -        super(Config, self).populate() - -        self.facts['config'] = self.responses - -        commits = self.responses[1] -        entries = list() -        entry = None - -        for line in commits.split('\n'): -            match = re.match(r'(\d+)\s+(.+)by(.+)via(.+)', line) -            if match: -                if entry: -                    entries.append(entry) - -                entry = dict(revision=match.group(1), -                             datetime=match.group(2), -                             by=str(match.group(3)).strip(), -                             via=str(match.group(4)).strip(), -                             comment=None) -            else: -                entry['comment'] = line.strip() - -        self.facts['commits'] = entries - - -class Neighbors(FactsBase): - -    COMMANDS = [ -        'show lldp neighbors', -        'show lldp neighbors detail', -    ] - -    def populate(self): -        super(Neighbors, self).populate() - -        all_neighbors = self.responses[0] -        if 'LLDP not configured' not in all_neighbors: -            neighbors = self.parse( -                self.responses[1] -            ) -            self.facts['neighbors'] = self.parse_neighbors(neighbors) - -    def parse(self, data): -        parsed = list() -        values = None -        for line in data.split('\n'): -            if not line: -                continue -            elif line[0] == ' ': -                values += '\n%s' % line -            elif line.startswith('Interface'): -                if values: -                    parsed.append(values) -                values = line -        if values: -            parsed.append(values) -        return parsed - -    def parse_neighbors(self, data): -        facts = dict() -        for item in data: -            interface = self.parse_interface(item) -            host = self.parse_host(item) -            port = self.parse_port(item) -            if interface not in facts: -                facts[interface] = list() -            facts[interface].append(dict(host=host, port=port)) -        return facts - -    def parse_interface(self, data): -        match = re.search(r'^Interface:\s+(\S+),', data) -        return match.group(1) - -    def parse_host(self, data): -        match = re.search(r'SysName:\s+(.+)$', data, re.M) -        if match: -            return match.group(1) - -    def parse_port(self, data): -        match = re.search(r'PortDescr:\s+(.+)$', data, re.M) -        if match: -            return match.group(1) - - -FACT_SUBSETS = dict( -    default=Default, -    neighbors=Neighbors, -    config=Config -) - -VALID_SUBSETS = frozenset(FACT_SUBSETS.keys()) - -  def main(): -    argument_spec = dict( -        gather_subset=dict(default=['!config'], type='list') -    ) +    """ +    Main entry point for module execution + +    :returns: ansible_facts +    """ +    argument_spec = FactsArgs.argument_spec      argument_spec.update(vyos_argument_spec)      module = AnsibleModule(argument_spec=argument_spec,                             supports_check_mode=True) -    warnings = list() - -    gather_subset = module.params['gather_subset'] - -    runable_subsets = set() -    exclude_subsets = set() - -    for subset in gather_subset: -        if subset == 'all': -            runable_subsets.update(VALID_SUBSETS) -            continue - -        if subset.startswith('!'): -            subset = subset[1:] -            if subset == 'all': -                exclude_subsets.update(VALID_SUBSETS) -                continue -            exclude = True -        else: -            exclude = False - -        if subset not in VALID_SUBSETS: -            module.fail_json(msg='Subset must be one of [%s], got %s' % -                             (', '.join(VALID_SUBSETS), subset)) - -        if exclude: -            exclude_subsets.add(subset) -        else: -            runable_subsets.add(subset) - -    if not runable_subsets: -        runable_subsets.update(VALID_SUBSETS) - -    runable_subsets.difference_update(exclude_subsets) -    runable_subsets.add('default') - -    facts = dict() -    facts['gather_subset'] = list(runable_subsets) - -    instances = list() -    for key in runable_subsets: -        instances.append(FACT_SUBSETS[key](module)) +    warnings = ['default value for `gather_subset` ' +                'will be changed to `min` from `!config` v2.11 onwards'] -    for inst in instances: -        inst.populate() -        facts.update(inst.facts) +    result = Facts(module).get_facts() -    ansible_facts = dict() -    for key, value in iteritems(facts): -        key = 'ansible_net_%s' % key -        ansible_facts[key] = value +    ansible_facts, additional_warnings = result +    warnings.extend(additional_warnings)      module.exit_json(ansible_facts=ansible_facts, warnings=warnings) | 
