Date created: 02/14/20 16:26:41. Last modified: 04/20/20 18:00:13

Ansible Notes

References:

Ansible network modules == https://docs.ansible.com/ansible/latest/modules/list_of_network_modules.html

ansible_network_os == https://github.com/ansible/ansible/blob/devel/docs/docsite/rst/network/user_guide/platform_index.rst

Nested dicts == https://www.jeffgeerling.com/blog/2017/changing-deeply-nested-dict-variable-ansible-playbook

 

CLI Args:

ansible -vvvv -i hosts -u james.bensley -k -a "ls -l" linux_servers

# Ansible CLI args:
#
# -vvvv
# Verbosity level
#
# -i
# Inventory file name, or specify a comma seperated list of hostnames/IPs
#
# -u
# Username for SSH auth to remote device
#
# -k
# Prompt for password for SSH auth to remote device
#
# -c
# How to connect to the remote system (default=smart)
#
# -m
# Ansible module to use (default=command)
#
# -a
# Ansible module args
#
# -e
# Set additional key/value pairs like a network device os (-e "ansible_network_os=iosxr")
#
# Finish with hosts file group or match glob/pattern

 

Connection methods and jump hosts / bastion hosts:

# Ansible will fail to connect to a network device if the host keys are unknown:
$ansible -i sr1.lab, all -u james.bensley -k -m sros_command -a "commands='show ver'" -c local -e "ansible_network_os=sros"
SSH password:
sr1.lab | FAILED! => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"msg": "Unable to decode JSON from response to exec_command({\"answer\": null, \"command\": \"show ver\", \"prompt\": null}). Received 'None'.",
"rc": 1
}

$ssh sr7.lab
The authenticity of host 'sr1.lab (192.168.0.1)' can't be established.
DSA key fingerprint is SHA256:XXXXXXXXXXXXXXXXX/YYYYYYYYYYYYYYYYYYYYYYYYY.
Are you sure you want to continue connecting (yes/no)?

# To skip host checking (WHICH IS POTENTIALLY INSECURE) set the environment variable ANSIBLE_HOST_KEY_CHECKING to False:
$ANSIBLE_HOST_KEY_CHECKING=False ansible -i sr1.lab, all -u james.bensley -k -m sros_command -a "commands='show ver'" -c local -e "ansible_network_os=sros"
SSH password:
sr1.lab | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"stdout": [
"show version \nTiMOS-C-15.0.R7 cpm/hops64 Nokia 7750 SR Copyright (c) 2000-2018 Nokia.\nAll rights reserved. All use subject to applicable license agreements.\nBuilt on Wed Jan 10 15:24:09 PST 2018 by builder in /builds/150B/R7/panos/main"
],
"stdout_lines": [
[
"show version ",
"TiMOS-C-15.0.R7 cpm/hops64 Nokia 7750 SR Copyright (c) 2000-2018 Nokia.",
"All rights reserved. All use subject to applicable license agreements.",
"Built on Wed Jan 10 15:24:09 PST 2018 by builder in /builds/150B/R7/panos/main"
]
]
}


# This will use the default connection method of "smart" which will in turn default to SSH,
# and requires sshpass to be installed, because SSH won't use a user supplied password (-k option)
# without sshpass:
ansible -i hosts -u james.bensley -k linux_servers -a "ls -l"

# To install sshpass on MacOS use:
# xcode-select --install
# brew install https://raw.githubusercontent.com/esolitos/homebrew-ipa/master/Formula/sshpass.rb

# One can explicitly chose ssh using "-c ssh":
ansible -i hosts -u james.bensley -k linux_servers -c ssh -a "ls -l"


# The network_cli connection type is for device with proprietary SSH CLIs like network devices.
# It doesn't require an SSH key for example:
ansible -i hosts lab --limit r1.lab -u james.bensley -k -m iosxr_facts -c network_cli -e "ansible_network_os=iosxr"
ansible -i ar1.lab, all -u james.bensley -k -m iosxr_command -a "commands='show ver'" -c network_cli -e "ansible_network_os=iosxr"
ansible -i rr0.lab, all -u james.bensley -k -m ios_command -a "commands='show ver'" -c network_cli -e "ansible_network_os=ios"
ansible -i me1.lab, all -u james.bensley -k -m ce_command -a "commands='display ver'" -c network_cli -e "ansible_network_os=ce"
# The following works with 7750s but not with a 7210:
ansible -i sr1.lab, all -u james.bensley -k -m sros_command -a "commands='show ver'" -c network_cli -e "ansible_network_os=sros"
# Set the OS to a Cisco Nexus (like with NAPALM) to get 7210 to work:
ansible -i as1.lab, all -u james.bensley -k -m sros_command -a "commands='show ver'" -c network_cli -e "ansible_network_os=nxos"

# One can use paramiko as a wrapper to SSH, this is helpful if sshpass is unavailable (like on MacOS)
# however, paramiko can't work with jump hosts / bastion hosts:
ansible -i hosts -u james.bensley -k linux_servers -c paramiko -a "ls -l"

# One can set the default connection type for each hosts so that it doesn't need to specified on the CLI:
[linux_servers]
s1.a1.example.com ansible_connection=paramiko
s1.a2.example.com ansible_connection=paramiko


# A jump host / bastion host will be used automatically if already configured in ~/.ssh/config.
# It is also possible to specify an Ansible specific SSH config file by adding the following
# to ansible.cfg:
[ssh_connection]
ssh_args = -F /path/to/ansible_ssh.cfg

 

Filters

The example below shows how to use the combine() filter to append a new key/value (testb) to an exist dict (vals) or it will update the existing key/value if it exists:


---
- hosts: GROUP_TEST
gather_facts: no
connection: local
tasks:

- name: Set test val A
set_fact:
vals:
testa: 123

- name: Set test val B
set_fact:
vals: "{{ vals|combine({'testb': 789}, recursive=True) }}"
when: inventory_hostname == "host2"

- name: Print before
debug:
msg: "{{ hostvars[inventory_hostname]['vals'] }}"

- name: Clear results variable
set_fact:
vals: null

- name: Print after
debug:
msg: "{{ hostvars[inventory_hostname]['vals'] }}"


$ansible-playbook -i hosts test.yml -v
Using /etc/ansible/ansible.cfg as config file

PLAY [GROUP_TEST] ************************************************************************************************

TASK [Set test val A] **********************************************************************************************
ok: [host1] => {"ansible_facts": {"vals": {"testa": 123}}, "changed": false}
ok: [host2] => {"ansible_facts": {"vals": {"testa": 123}}, "changed": false}

TASK [Set test val B] **********************************************************************************************
ok: [host2] => {"ansible_facts": {"vals": {"testa": 123, "testb": 789}}, "changed": false}
skipping: [host1] => {"changed": false, "skip_reason": "Conditional result was False"}

TASK [Print before] ************************************************************************************************
ok: [host1] => {
"msg": {
"testa": 123
}
}
ok: [host2] => {
"msg": {
"testa": 123,
"testb": 789
}
}

TASK [Clear results variable] **************************************************************************************
ok: [host1] => {"ansible_facts": {"vals": null}, "changed": false}
ok: [host2] => {"ansible_facts": {"vals": null}, "changed": false}

TASK [Print after] *************************************************************************************************
ok: [host1] => {
"msg": ""
}
ok: [host2] => {
"msg": ""
}