Topic: tech juniper jaut prev next
tech juniper jaut > Module 05: Ansible Intermediate
Ansible uses SSH to connect to remote devices and copy and run Python code.
The Juniper implementation requires all tasks to run locally on the management server. Tasks connect to remote devices by NETCONF.
Ansible modules are written in Python. They are more like Python functions, not Python modules. In Ansible, the result is JSON. Modules are idempotent; they only make changes if required.
Ansible server files:
Juniper Ansible modules in the Ansible Module Library use the ncclient library to communicate over NETCONF. Previously, Juniper modules were only available in Ansible Galaxy. The new naming convention is ‘juniperjunos*’.
pip install junos-eznc
pip install jxmlease
ansible-galaxy install Juniper.junos
Playbooks reference ‘Juniper.junos’.
Ansible configuration file preference
ANSIBLE_CONFIG
ansible.cfg
~/.ansible.cfg
/etc/ansible/ansible.cfg
[defaults] inventory = hosts hostkeychecking = False
It is possible to use Ansible without a configuration file as the defaults may be enough.
The inventory file lists hosts. Devices are in groups. Devices can be part of multiple groups. The group ‘all’ is always defined. The default location is ‘/etc/ansible/hosts’ and can be overridden by the configuration file or the ‘-i’ key.
[routers]
vmx-1
[spine]
spine[1:4].example.com
[leaf]
leaf[1:24].example.com
The ‘switches’ group includes all hosts that are part of the ‘spine’ and ‘leaf’ groups.
[switches:children]
spine
leaf
Ad-hoc commands can be run from the command line without a playbook.
ansible -m junos_facts -a "username=lab password=lab123" -c local <hostname>
Playbooks automate tasks on multiple devices. Here is an example using the Galaxy module. The ‘Juniper.junos’ role imports the Galaxy module. Use ‘connection: local’ to prevent Ansible attempting to copy the modules to the remote host.
---
- name: play1
connection: local
roles:
- Juniper.junos
vars_prompt:
- name: USERNAME
prompt: Username
private: no
- name: PASSWORD
prompt: Password
private: yes
hosts: <list of hosts>
tasks:
- name: Get Junos device information
juniper_junos_facts:
user: "{{ USERNAME }}"
passwd: "{{ PASSWORD }}"
register: junos_facts
- name: Print Junos facts
debug:
msg: "{{ junos_facts }}"
Execute a playbook with the ‘ansible-playbook’ utility, giving the playbook name as the argument.
If using the Ansible library module, omit the ‘roles’ section and change the task to the following;
tasks:
- name: Get Junos device information
juniper_junos_facts:
provider:
username: "{{ USERNAME }}"
password: "{{ PASSWORD }}"
register: junos_facts
Use ‘–list-hosts’ to only list the hosts that will run each play (without running the play).
Use ‘–limit’ to limit execution of a playbook to just one device. This is useful for making a ‘canary’ deployment.
If execution fails, the hosts on which it failed are written to ‘.retry’. The playbook can be run again with ‘ansible-playbook book.yml –limit book.retry’.
Use ‘–check’ to do a dry run, without making changes. Not all Ansible modules support all arguments; it is best to try them in a test environment first.
Ansible Vault is used to store sensitive information. Once SSH keys have been stored, username and password information does not need to be stored in the plaintext playbook.
ansible-vault encrypt hello.yml
# prompt for password
ansible-vault view hello.yml
ansible-playbook hello.yml --ask-vault-pass
# or configure in ansible.cfg
Ansible provides a ‘when’ statement, which operates like ‘if’.
- name: Check Version
fail: msg="Incorrect Junos version"
when: (junos_facts.facts.junos_info.re0.text != "...")
Similarly, use the ‘loop’ option to run a task multiple times.
...
juniper_junos_command:
command: "show interfaces {{item}} terse"
...
loop:
- ge-0/0/0
- ge-0/0/1
‘until’ style loops are also supported. This approach is common for playbooks that provision large services.
until: (condition)
retries: 20
delay: 5
Handlers are similar to tasks. They are referenced by tasks using the ‘notify’ key and only if a task makes a change. Handlers are executed in the order they are defined and are executed at most once per playbook run.
For example, a ‘commit’ handler might be notified if a task makes a config change, so that the change can be committed.
tasks:
- name: ...
juniper_junos_config:
...
notify: confirm commit
handlers:
- name: confirm commit
juniper_junos_config:
provider: "{{ provider }}"
comment: "Confirming previous commit"
commit: yes
Variables can be used to deal with differences between hosts. The order of precedence is groupvar/all, groupvars/, host_vars/, vars:, varsprompt:, varsfiles:, command line variables (‘-e’ option).
Playbooks use Jinja2 syntax for variable substitution, including filters. Use of advanced constructs is not recommended.
Ansible provides a number of special variables, including ‘inventory_hostname’ (used as the ‘host’ argument), ‘hostvars’ and ‘groups’.
Variables can be passed to modules in YAML using various syntax;
user: "{{ USERNAME }}"
user={{ USERNAME }}
The ‘assemble’ module can be used to assemble (by concatenation) multiple files.
To debug a playbook, use the ‘fail’ module to stop execution after a config file has been generated, but before it is pushed to a device.
- fail: msg="Fail"