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.
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 |
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:
The example includes the considerations to include the appropriate namespaces for applying the configuration.
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).
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']
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:
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']
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:
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