SR OS Ansible examples

Additional examples of Ansible in combination with SR OS

Introduction

If you have followed the SR OS with Ansible - 101 article you have some familiarity with well structured Ansible playbooks.  Sometimes, however, it is useful to have additional examples which can be added as part of a Ansible playbook.

This article provides some additional examples that can be executed: to change bof configuration, load configuration via a file or to compare configuration on your SR OS devicec with model-driven mode enabled.

Equipment and tools

This article is written in the form of examples. It assumes that you have access to one or more Nokia SR OS 7x50 routers (or vSIMs) and that you have a valid license for these products (if you need any of these, please contact your Nokia representative). It also assumes that you have access to a Linux machine from which to work (although it is possible to manage your SR OS devices from other host operating systems).

Equipment used for the creation of this article:

Item Version
Linux Machine CentOS 7.8
Ansible 2.11
SR OS 23.3.R2

First example, edit BOF configuration

With this example, we are going to update the BOF using Ansible supplied Netconf RPC module. In this example we will add the configuration for a primary DNS server.

The steps of the task are:

  1. Lock the candidate configuration for BOF
  2. Edit config via Netconf RPC
  3. Commit the candidate configuration
  4. Unlock the candidate configuration

The example includes the considerations to include the appropriate namespaces for applying the configuration.

  • netconf namespace
  • bof-candidate namespace

The example can be augmented as desired. It is in the format of a task with tags similar to SR OS Ansible 'get' playbook

For more information on the Ansible Netconf_rpc module, see the ansible documentation here.

### XML EDIT BOF CONFIGURATION
    - block:
      - name: lock
        connection: netconf
        ansible.netcommon.netconf_rpc:
          rpc: lock
          xmlns: "urn:ietf:params:xml:ns:netconf:base:1.0"
          content: |
             <target>
             <bof-candidate xmlns="urn:nokia.com:sros:ns:yang:sr:ietf-netconf-augments"/>
             </target>
      - name: edit config via rpc
        connection: netconf
        ansible.netcommon.netconf_rpc:
          rpc: edit-config
          xmlns: "urn:ietf:params:xml:ns:netconf:base:1.0"
          content: |
             <target>
             <bof-candidate xmlns="urn:nokia.com:sros:ns:yang:sr:ietf-netconf-augments"/>
             </target>
             <config>
               <bof xmlns="urn:nokia.com:sros:ns:yang:sr:bof-conf" xmlns:nc="urn:ietf:params:xml:ns:netconf:base:1.0" xmlns:nokia-attr="urn:nokia.com:sros:ns:yang:sr:attributes">
                 <dns>
                    <primary-server>192.168.122.1</primary-server>
                 </dns>
               </bof>
             </config>
      - name: commit
        connection: netconf
        ansible.netcommon.netconf_rpc:
          rpc: commit
          xmlns: "urn:ietf:params:xml:ns:netconf:base:1.0"
          content: |
             <configuration-region xmlns="urn:nokia.com:sros:ns:yang:sr:ietf-netconf-augments">
             bof
             </configuration-region>
      - name: unlock
        connection: netconf
        ansible.netcommon.netconf_rpc:
          rpc: unlock
          xmlns: "urn:ietf:params:xml:ns:netconf:base:1.0"
          content: |
             <target>
             <bof-candidate xmlns="urn:nokia.com:sros:ns:yang:sr:ietf-netconf-augments"/>
             </target>
      tags: ['never','xml-bof-config','bof-config-xml']

The appropiate RPC is created by Ansible by the defining the RPC, content and xmlns (namespace).

Second example, loading a configuration file

With this example a task is defined to load and replace a configuration on a node. The example is using the Ansible supplied Netconf config module.

As specified in the example the default operation will be fully replacing the complete configuration and it will commit it afterwards.

The example can be augmented as desired. It is in the format of a task with tags similar to SR OS Ansible 'get' playbook

Important to note the configuration to apply/load is supplied in xml, the complete <config> section.

For more information on the Ansible Netconf_config module, see the ansible documentation here.

### XML LOAD configuration from file
    - block:
      - name: use lookup filter to provide xml configuration
        ansible.netcommon.netconf_config:
          target: candidate
          commit: yes
          lock: always
          default_operation: replace
          content: "{{ lookup('file', './config.xml') }}"
      tags: ['never','xml-load-config','load-config-xml']

Third example, compare configuration

With this example, we are going to compare the configuration using Ansible supplied Netconf RPC module.

This will compare the configuration on the node giving the result in MD-CLI stanza. This would normally be a task in a playbook where you compare the changes after changing the configuration so a operator could verify the change before committing the changes.

The compare operation is part of the different operations/actions you can execute via Netconf on SR-OS. These operations are defined in the seperate nokia-oper.*yang files. In case of compare it is defined in nokia-oper-global.yang.

The example can be augmented as desired. It is in the format of a task with tags simular to SR OS Ansible 'get' playbook

For more information on the Ansible Netconf_rpc module, see the ansible documentation here.

### XML COMPARE CONFIGURATION
    - block:
      - name: Compare
        connection: netconf
        ansible.netcommon.netconf_rpc:
          rpc: action
          xmlns: "urn:ietf:params:xml:ns:yang:1"
          content:
            <global-operations xmlns="urn:nokia.com:sros:ns:yang:sr:oper-global">
              <md-compare>
                <format>md-cli</format>
              </md-compare>
            </global-operations>
        register: netconf_facts_compare_config_xml
      - name: Extract the compare output from the XML response
        xml:
          xmlstring: "{{ netconf_facts_compare_config_xml.stdout }}"
          content: text
          xpath: /x:rpc-reply/nokiaoper:results/nokiaoper:md-compare-output
          namespaces:
            x: urn:ietf:params:xml:ns:netconf:base:1.0
            nokiaoper: urn:nokia.com:sros:ns:yang:sr:oper-global
        delegate_to: localhost
        register: compare_config
      - name: Display the extracted compare output
        debug:
          msg: "Compare results are as followed: {{ compare_config.matches[0]['{urn:nokia.com:sros:ns:yang:sr:oper-global}md-compare-output'] }}"
      tags: ['never','xml-compare-config','compare-config-xml']

The appropriate RPC is created by Ansible by the defining the RPC, content and xmlns (namespace).

Below is the RPC which would be send to the node.

<?xml version="1.0" encoding="UTF-8"?><nc:rpc xmlns:nc="urn:ietf:params:xml:ns:netconf:  base:1.0" message-id="urn:uuid:c2e488c8-9b6c-4e8d-8ec9-86a75f3d92d8">
<action xmlns="urn  :ietf:params:xml:ns:yang:1">
<global-operations xmlns="urn:nokia.com:sros:ns:yang:sr:ope  r-global"> 
<md-compare> <format>md-cli</format> </md-compare> 
</global-operations>
</action>
</nc:rpc>

The xpath line in the task "Extract the compare output from the XML response"queries the input (netconf_facts_compare_config_xml.stdout) for the specific path to the element we are interested in the XML data.

Important to also consider are the namespaces for the appropriate XML matching. In this example this is /x:rpc-reply/nokiaoper:results/nokiaoper:md-compare-output

Considering the namespaces are:

  • x: urn:ietf:params:xml:ns:netconf:base:1.0
  • nokiaoper: urn:nokia.com:sros:ns:yang:sr:oper-global

In the task "Display the extracted compare output" there is an attribute called matches that is a list (as denoted by the []'s). This attribute contains all the matches from the xpath expression in the task "Extract the compare output from the XML response"

In this task we want to output the first match list item only and so you will see compare_config.matches[0] shown.

Inside the match we want to output the value of the key, md-compare-output. The full variable path embedded in the output string (sentence) needs to also consider the namespace, the full path would result in

compare_config.matches[0][{urn:nokia.com:sros:ns:yang:sr:oper-global}md-compare-output']

Running the playbook

Executing the playbook is performed using ansible-playbook command and passing it the inventory file and the tags you require (see above).  Use the following flags to pass the arguments:

  • -i <inventory-filename>
  • -t <tags>

For the sake of this example the compare task was added to ansible-playbook called ansible-netconf-yml.

Here is an example execution:

ansible-playbook -i inventory ansible-netconf.yml -t xml-compare-config

To demonstrate the task, in the background the name of the node was changed manually.

The result of running this playbook yields the following output:

PLAY [vsim-2] ***************************************************************************

TASK [Compare] **************************************************************************
ok: [vsim-2]

TASK [Extract the compare output from the XML response] *********************************
ok: [vsim-2 -> localhost]

TASK [Display the extracted compare output] *********************************************
ok: [vsim-2] =>
  msg: |-
    Compare results are as followed:
        configure {
            system {
    ~           name "VSIM-2"
            }
        }

PLAY RECAP ******************************************************************************
vsim-2                     : ok=3    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

On this page