#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright 2020 Red Hat # GNU General Public License v3.0+ # (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) from __future__ import absolute_import, division, print_function __metaclass__ = type DOCUMENTATION = """ module: cli_parse author: Bradley Thornton (@cidrblock) short_description: Parse cli output or text using a variety of parsers description: - Parse cli output or text using a variety of parsers version_added: 1.0.0 options: command: type: str description: - The command to run on the host text: type: str description: - Text to be parsed parser: type: dict description: - Parser specific parameters required: True suboptions: name: type: str description: - The name of the parser to use required: True command: type: str description: - The command used to locate the parser's template os: type: str description: - Provide an operating system value to the parser - For `ntc_templates` parser, this should be in the supported `_` format. template_path: type: str description: - Path of the parser template on the Ansible controller - This can be a relative or an absolute path vars: type: dict description: - Additional parser specific parameters - See the cli_parse user guide for examples of parser specific variables - U(https://docs.ansible.com/ansible/latest/network/user_guide/cli_parsing.html) set_fact: description: - Set the resulting parsed data as a fact type: str notes: - The default search path for a parser template is templates/{{ short_os }}_{{ command }}.{{ extension }} - => short_os derived from ansible_network_os or ansible_distribution and set to lower case - => command is the command passed to the module with spaces replaced with _ - => extension is specific to the parser used (native=yaml, textfsm=textfsm, ttp=ttp) - The default Ansible search path for the templates directory is used for parser templates as well - Some parsers may have additional configuration options available. See the parsers/vars key and the parser's documentation - Some parsers require third-party python libraries be installed on the Ansible control node and a specific python version - example Pyats requires pyats and genie and requires Python 3 - example ntc_templates requires ntc_templates - example textfsm requires textfsm - example ttp requires ttp - example xml requires xml_to_dict - Support of 3rd party python libraries is limited to the use of their public APIs as documented - "Additional information and examples can be found in the parsing user guide:" - https://docs.ansible.com/ansible/latest/network/user_guide/cli_parsing.html """ EXAMPLES = r""" # Using the native parser # ------------- # templates/nxos_show_interface.yaml # - example: Ethernet1/1 is up # getval: '(?P\S+) is (?P\S+)' # result: # "{{ name }}": # name: "{{ name }}" # state: # operating: "{{ oper_state }}" # shared: True # # - example: admin state is up, Dedicated Interface # getval: 'admin state is (?P\S+)' # result: # "{{ name }}": # name: "{{ name }}" # state: # admin: "{{ admin_state }}" # # - example: " Hardware: Ethernet, address: 0000.5E00.5301 (bia 0000.5E00.5301)" # getval: '\s+Hardware: (?P.*), address: (?P\S+)' # result: # "{{ name }}": # hardware: "{{ hardware }}" # mac_address: "{{ mac }}" - name: Run command and parse with native ansible.utils.cli_parse: command: "show interface" parser: name: ansible.netcommon.native set_fact: interfaces_fact - name: Pass text and template_path ansible.utils.cli_parse: text: "{{ previous_command['stdout'] }}" parser: name: ansible.netcommon.native template_path: "{{ role_path }}/templates/nxos_show_interface.yaml" # Using the ntc_templates parser # ------------- # The ntc_templates use 'vendor_platform' for the file name # it will be derived from ansible_network_os if not provided # example cisco.ios.ios => cisco_ios - name: Run command and parse with ntc_templates ansible.utils.cli_parse: command: "show interface" parser: name: ansible.netcommon.ntc_templates register: parser_output - name: Pass text and command ansible.utils.cli_parse: text: "{{ previous_command['stdout'] }}" parser: name: ansible.netcommon.ntc_templates command: show interface register: parser_output # Using the pyats parser # ------------- # The pyats parser uses 'os' to locate the appropriate parser # it will be derived from ansible_network_os if not provided # in the case of pyats: cisco.ios.ios => iosxe - name: Run command and parse with pyats ansible.utils.cli_parse: command: "show interface" parser: name: ansible.netcommon.pyats register: parser_output - name: Pass text and command ansible.utils.cli_parse: text: "{{ previous_command['stdout'] }}" parser: name: ansible.netcommon.pyats command: show interface register: parser_output - name: Provide an OS to pyats to use an ios parser ansible.utils.cli_parse: text: "{{ previous_command['stdout'] }}" parser: name: ansible.netcommon.pyats command: show interface os: ios register: parser_output # Using the textfsm parser # ------------- # templates/nxos_show_version.textfsm # # Value UPTIME ((\d+\s\w+.s.,?\s?){4}) # Value LAST_REBOOT_REASON (.+) # Value OS (\d+.\d+(.+)?) # Value BOOT_IMAGE (.*) # Value PLATFORM (\w+) # # Start # ^\s+(NXOS: version|system:\s+version)\s+${OS}\s*$$ # ^\s+(NXOS|kickstart)\s+image\s+file\s+is:\s+${BOOT_IMAGE}\s*$$ # ^\s+cisco\s+${PLATFORM}\s+[cC]hassis # ^\s+cisco\s+Nexus\d+\s+${PLATFORM} # # Cisco N5K platform # ^\s+cisco\s+Nexus\s+${PLATFORM}\s+[cC]hassis # ^\s+cisco\s+.+-${PLATFORM}\s* # ^Kernel\s+uptime\s+is\s+${UPTIME} # ^\s+Reason:\s${LAST_REBOOT_REASON} -> Record - name: Run command and parse with textfsm ansible.utils.cli_parse: command: "show version" parser: name: ansible.utils.textfsm register: parser_output - name: Pass text and command ansible.utils.cli_parse: text: "{{ previous_command['stdout'] }}" parser: name: ansible.utils.textfsm command: show version register: parser_output # Using the ttp parser # ------------- # templates/nxos_show_interface.ttp # # {{ interface }} is {{ state }} # admin state is {{ admin_state }}{{ ignore(".*") }} - name: Run command and parse with ttp ansible.utils.cli_parse: command: "show interface" parser: name: ansible.utils.ttp set_fact: new_fact_key - name: Pass text and template_path ansible.utils.cli_parse: text: "{{ previous_command['stdout'] }}" parser: name: ansible.utils.ttp template_path: "{{ role_path }}/templates/nxos_show_interface.ttp" register: parser_output # Using the XML parser # ------------- - name: Run command and parse with xml ansible.utils.cli_parse: command: "show interface | xml" parser: name: ansible.utils.xml register: parser_output - name: Pass text and parse with xml ansible.utils.cli_parse: text: "{{ previous_command['stdout'] }}" parser: name: ansible.utils.xml register: parser_output """ RETURN = r""" parsed: description: The structured data resulting from the parsing of the text returned: always type: dict sample: stdout: description: The output from the command run returned: when provided a command type: str sample: stdout_lines: description: The output of the command run split into lines returned: when provided a command type: list elements: str sample: """