Conditional parameter value in Ansible playbooks
Ansible playbook is just a list of tasks executed one by one in the order you define them in the playbook code. Using the conditional statements you may skip execution of some tasks, but there is one general rule that should apply to all playbooks you create – keep the number of tasks at the minimum.
Execution of each task takes time, and until you provide additional optimization, Ansible will establish the connection, perform an authentication process and then terminate the connection with a remote device. The longer this process takes, the more time you waste when you execute the playbook. It is a good practice to consolidate the tasks – if you need to perform multiple commands on a remote network device, you should define them as a parameter of one task instead of running them in separate tasks. In rare cases it may lead to unexpected problems like the one I described in my post Automated scripts can send commands faster than RP can process.
Sometimes you need to vary the value of an option provided to the task module. If you need to get an output of a CLI command on Juniper device, you will use the module junos_command which is part of standard Ansible library. Using the display parameter, you can specify if command output will be encoded in XML or JSON format. JSON is a more flexible format, but it is not a supported output format on older JunOS version. If you try to request it but the firmware does not support it your task, and the whole playbook will fail. Most of the developers will create two separate task and the conditional test to check version as a task with the when option. However, let me show you the other, not that well known, way.
Conditional tasks using when
Consider developing a really simple task of executing the shell command on Juniper router. It can be as simple as “show version”. Raw console command output is the least desired format you want programmatically process. You should always prefer output in some kind of structure easy to process. Older JunOS version let you display output as XML, starting from release 14.2 you can choose between XML and JSON. All you have to do is add “display xml” or “display json” parameter to “show version” command using the pipe (‘|’) construction. Give it a try on your device!
In Ansible playbook you can achieve the same using the ‘display’ parameter in ‘junos_command’ task from default JunOS Ansible library. Acceptable values are either ‘
Let’s assume you are the lucky developer and you have the firmware version correctly recorded in the ‘my_junos_version’ variable in the playbook. Now you want to record the ‘show version’ command output in the JSON structure if device firmware support such output format. I bet most of the readers instantly thought of creating two tasks and using the ‘when’ conditional to compare recorded firmware version with the predefined value of ‘14.2’.
- name: Execute command on router
junos_command:
display: xml
commands: "show version"
register: record_output
when: my_junos_version < '14.2'
- name: Execute command on router
junos_command:
display: json
commands: "show version"
register: record_output
when: my_junos_version >= '14.2'
This approach is correct but may be not flexible in larger playbooks. You need to maintain duplicated tasks with same task code but different condition and one parameter.
Conditional inside the tasks
Is it possible to put conditional inside the task? Yes, it is. Remember you have many tools in Ansible/YAML to manipulate the data or use the conditional constructions. You can use it for any field in Ansible playbook.
Lets modify example from the previous paragraph
- name: Execute command on router
junos_command:
display: "{{ my_junos_version is version( '14.2' , '>') | ternary ('json','xml') }}"
commands: "show version"
register: record_output
As you can see we have now only one task instead of two. The conditional now is not part of a task but defined as value of display parameter. Lets take a closer look. We use the my_junos_version again but together with version() function. This function uses three parameters – first one is my_junos_version provided in conditional. Other two are explicit function parameters – the parameter you compare against and logical operation you want to perform, in my case it is the greater than. This is really handy function because you don’t have to think about such things as major or minor version numbers. This condidional will return True if JunOS version in variable is greater than 14.2.
Computed boolean value is then provided to another function ternary(). It is very simple function that returns is first parameter if provided boolean value is True or second in case it is False.