# CLI Parser Directives The `command_parser` module is a module that can be used to parse the results of text strings into Ansible facts. The primary motivation for developing the `command_parser` module is to convert structured ASCII text output (such as the stdout returned from network devices) into JSON data structures suitable to be used as host facts. The parser template file format is loosely based on the Ansible playbook directives language. It uses the Ansible directive language to ease the transition from writing playbooks to writing parser templates. However, parser templates developed using this module are not written directly into the playbook, but are a separate file called from playbooks. This is done for a variety of reasons but most notably to keep separation between the parsing logic and playbook execution. The `command_parser` works based on a set of directives that perform actions on structured data with the end result being a valid JSON structure that can be returned to the Ansible facts system. ## Parser language The parser template format uses YAML formatting, providing an ordered list of directives to be performed on the content (provided by the module argument). The overall general structure of a directive is as follows: ```yaml - name: some description name of the task to be performed directive: argument: value argument_option: value argument: value directive_option: value directive_option: value ``` The `command_parser` currently supports the following top-level directives: * `pattern_match` * `pattern_group` * `json_template` * `export_facts` In addition to the directives, the following common directive options are currently supported: * `name` * `block` * `loop` * `loop_control` * `loop_var` * `when` * `register` * `export` * `export_as` * `extend` Any of the directive options are accepted but in some cases, the option may provide no operation. For instance, when using the `export_facts` directive, the options `register`, `export` and `export_as` are all ignored. The module should provide warnings when an option is ignored. The following sections provide more details about how to use the parser directives to parse text into JSON structure. ## Directive Options This section provides details on the various options that are available to be configured on any directive. ### `name` All entries in the parser template many contain a `name` directive. The `name` directive can be used to provide an arbitrary description as to the purpose of the parser items. The use of `name` is optional for all directives. The default value for `name` is `null`. ### `register` Use the `register` option to register the results of a directive operation temporarily into the variable name you specify so you can retrieve it later in your parser template. You use `register` in a parser template just as you would in an Ansible playbook. Variables created with `register` alone are not available outside of the parser context. Any values registered are only available within the scope of the parser activities. If you want to provide values back to the playbook, you must also define the [export](#export) option. Typically you will use `register` alone for parsing each individual part of the command output, then amalgamate them into a single variable at the end of the parser template, register that variable and set `export: yes` on it. The default value for `register` is `null`. ### `export` Use the `export` option to export any value back to the calling task as an Ansible fact. The `export` option accepts a boolean value that defines if the registered fact should be exported to the calling task in the playbook (or role) scope. To export the value, simply set `export` to True. Note this option requires the `register` value to be set in some cases and will produce a warning message if the `register` option is not provided. The default value for `export` is `False`. ### `export_as` Use the `export_as` option to export a value back to the calling task as an Ansible fact in a specific format. The `export_as` option defines the structure of the exported data. Accepted values for `export_as`: * `dict` * `hash` * `object` * `list` * `elements` that defines the structure **Note** this option requires the `register` value to be set and `export: True`. Variables can also be used with `export_as`. How to use variable with `export_as` is as follows: Variable should be defined in vars or defaults or in playbook. ```yaml vars: export_type: "list" ``` Parser file needs to have the variable set to `export_as`. ``` export_as: "{{ export_type }}" ``` ### `extend` Use the `extend` option to extend a current fact hierarchy with the new registered fact. This will case the facts to be merged and returned as a single tree. If the fact doesn't previously exist, this will create the entire structure. The default value for `extend` is `null`. ### loop Use the `loop` option to loop over a directive in order to process values. With the `loop` option, the parser will iterate over the directive and provide each of the values provided by the loop content to the directive for processing. Access to the individual items is the same as it would be for Ansible playbooks. When iterating over a list of items, you can access the individual item using the `{{ item }}` variable. When looping over a hash, you can access `{{ item.key }}` and `{{ item.value }}`. ### `loop_control` Use the `loop_control` option to specify the name of the variable to be used for the loop instead of default loop variable `item`. When looping over a hash, you can access `{{ foo.key }}` and `{{ foo.value }}` where `foo` is `loop_var`. The general structure of `loop_control` is as follows: ```yaml - name: User defined variable pattern_match: regex: "^(\\S+)" content: "{{ foo }}" loop: "{{ context }}" loop_control: loop_var: foo ``` ### `when` Use the `when` option to place a condition on the directive to decided if it is executed or not. The `when` option operates the same as it would in an Ansible playbook. For example, if you only want to perform the match statement when the value of `ansible_network_os` is set to `ios`, you can apply the `when` conditional like this: ```yaml - name: conditionally matched var pattern_match: regex: "hostname (.+)" when: ansible_network_os == 'ios' ``` ## Directives The directives perform actions on the content using regular expressions to extract various values. Each directive provides some additional arguments that can be used to perform its operation. ### `pattern_match` Use the `pattern_match` directive to extract one or more values from the structured ASCII text based on regular expressions. The following arguments are supported for this directive: * `regex` * `content` * `match_all` * `match_greedy` * `match_until` : Sets a ending boundary for `match_greedy`. The `regex` argument templates the value given to it so variables and filters can be used. Example : ```yaml - name: Use a variable and a filter pattern_match: regex: "{{ inventory_hostname | lower }} (.+)" ``` ### `pattern_group` Use the `pattern_group` directive to group multiple `pattern_match` results together. The following arguments are supported for this directive: * `json_template` * `set_vars` * `export_facts` ### `json_template` Use the `json_template` directive to create a JSON data structure based on a template. This directive will allow you to template out a multi-level JSON blob. The following arguments are supported for this directive: * `template` **Note** Native jinja2 datatype (eg. 'int', 'float' etc.) rendering is supported with Ansible version >= 2.7 and jinja2 library version >= 2.10. To enable native jinja2 config add below configuration in active ansible configuration file. ``` [defaults] jinja2_native= True ``` Usage example: ```yaml - set_fact: count: "1" - name: print count debug: msg: "{{ count|int }}" ``` With jinja2_native configuration enabled the output of above example task will have ``` "msg": 1 ``` and with jinja2_native configuration disabled (default) output of above example task will have ``` "msg": "1" ``` ### `set_vars` Use the `set_vars` directive to set variables to the values like key / value pairs and return a dictionary. ### `export_facts` Use the `export_facts` directive to take an arbitrary set of key / value pairs and expose (return) them back to the playbook global namespace. Any key / value pairs that are provided in this directive become available on the host.