This is an old revision of the document!
# install ansible in virtual environmenty source bin/activate python -m pip install ansible # The below is required so ansible recognises its path (deactivate and activate) deactivate && source bin/activate ansible --version
—-
Before we start is important to know the variable precedence. See this External Link and most important bits below:
vars_fileshost_varsgroup_varshost_varsgroup_varsvars
Here to find a quick definition of tasks, roles, plays, playbooks and so on External Link
Modules can be: standard, installed or included in the project itself as python-scripts, we just add a folder library and we add the modules as name_of_the_module.py. libraries I might require on those py scripts are: configparser, git, shutil, AnsibleModule
cat > ansible.cfg [defaults] gathering = explicit inventory = inv.yml. # calling it hosts can be very confusing, better inv.yml retry_files_enabled = False # disable host checking to automatically add hosts to known_hosts host_key_checking = False
JINJA2 TEMPLATES:
To use it in local (to test things or just to generate configurations to use them later)External Link:
IPADDR FILTERS:
They are used extensively in j2 to validate and manipulate IPs.
See the official docs and the cheatsheet:
FLAGS USAGE:
ansible_run_tags reserved keywork: Contents of the –tags CLI option, which specifies which tags will be included for the current run. Note that if –tags is not passed, this variable will default to [“all”].
So in theory this can only be used when starting an ansible script via CLI. However we can write a central playbook and then divert to other subplaybooks depending on the tag passed by any shceduling system like AWX:
name: Process Port-Channel Summary on Cisco NXOS import_playbook: port_channel/playbook_nxos.yml when: - "'nxos' in ansible_run_tags" - "'port_channel' in ansible_run_tags" name: Process Port-Channel Summary on Cisco IOSXE import_playbook: port_channel/playbook_iosxe.yml when: - "'iosxe' in ansible_run_tags" - "'port_channel' in ansible_run_tags"
Tags can also be set inside the play itself and inherited. See this External Link
AD-HOC COMMANDS:
'raw' command > (unlike shell) raw does not require python to be installed in the target server, hence so used with network devices
ansible all -i inventory -m setup # this collects facts ansible all -i inventory -m setup # this collects facts ansible -i hosts all -m ping --private-key /home/student/ansible_key # PING module, useful to test connectivity to the hosts ansible all -i "sw-b05.dc.mycompany1.co.uk," -m raw -a "show version" -u jaime_santos # comma and double quotes are needed ansible -i ini/hosts "linux1," -m raw -a "/usr/sbin/ip route" ansible all -m raw -a "show version" -u jaime_santos -i ini/hosts # raw module doesn't require python installed in the remote 'router' ansible <host1> -m command -a "grep lisa /etc/shadow" # this is more for linux, it uses module 'command'
The 'command' module above ^, when used in the playbook, dumps the output in the 'register' variable
PLAYBOOKS
YAML SYNTAX:
Follow this recommendatrions: External Link
ansible-playbook -i vyos.example.net, -u jaime_santos first_playbook.yml ansible-playbook -i ini/hosts -l all get_dev_facts_screen.yml # Output in screen, facts defined in the playbook ansible-playbook -i ini/hosts -l all get_all_facts.yml # Output in 'results_facts' folder, all available facts downloaded.
FLAGS:
For more info: External Link
ANSIBLE.CFG NOTES:
Note example below where we place all variable in a var file:
~ hosts: crpnycnetdev02
connection: local
gather_facts: no
vars_files:
~ vars/sflinx.yml
~ vars/env_site.yml
tasks:
~ name: Generate Configsc
template:
src: "templates/cspolicy.j2"
dest: "configs/api_{{filter_condition}}_{{item.key}}.cfg"
with_dict: "{{ sites }}
The var file simply looks like this:
~~~
# ./vars/name_vars.yml
name: World # then, in another playbook, the var can be referred as {{name}}
This is another way to parse jinja2 templates into result files External Link. Remember lookups are just plugins, so multiple functions. See External Link
set_fact: data="{{lookup('template','templates/node-model.j2')}}" # returns a string containing the results of processing that template.
ACCESS TO DICTIONARY EXAMPLES AND MORE:
Example of lists and dictionaries. If we add register to the play's loop, the variable specified will contain all responses from the module:
~~~
~ name: Test loop over list and dict
hosts: all
become: true
vars:
my_grocery_list:
~ milk
~ butter
my_car_preferences:
brand: mercedes
model: G
tasks:
~ name: Loop over list
debug:
msg: "(( item }}"
loop: "{{ my_grocery_list }}"
tasks:
~ name: Loop over dict
debug:
msg: "{{ item.key }} {{ item.value }}"
loop: "{{ my_car_preferences | dict2items }}"
ITERITEMS AND MAP
If we want a loop on a dictionary, we use dict2items
!! This is the template
! note: 'map' filter does not transform. It either applies a filter to all a sequence of objects and/or looks up an attribute.
{
"vlans": {
{% for customer,svc in services.iteritems()
if inventory_hostname in svc.ports|map(attribute='node')
and svc.state|default("") != "absent" %}
"{{svc.vlan}}": "{{customer}}"{% if not(loop.last) %},{% endif %}
{% endfor %}
!
!! This is the vars file (included in the play with ''include_vars'')
---
ACME:
vlan: 100
ports:
- { node: leaf-1, port: "Ethernet2/1", site: "ACME Downtown" }
- { node: leaf-2, port: "Ethernet2/3", site: "ACME Remote" }
Wonka: ...
>>> with_dict: "{{ sites }}
>>> loop: "{{ my_car_preferences | dict2items }}"
>>> if inventory_hostname in svc.ports|map(attribute='node')
# Configuration management. After templeting, we need to push the configurations to the box
# ansible-playbook playbook.yml --tags-push # ansible-playbook playbook.yml --tags-push --limit csr1 # limit this job to this group/device # ansible-playbook playbook.yml --tags=connfig
Example of a module's parameters(1) in playbooks:
(1) (I would call them commands instead). See https://docs.ansible.com/ansible/asa_config_module.html
INVENTORY
ansible-inventory -i ./hosts.yml --list # to expand and verify the inventory file
We can also use dynamic inventories (mostly useful when we connect to clouds). There are py scripts for this which , for example spits in json format all hosts it finds in dns etc/hosts and anywhere else.
VARIABLES:
These are all the Reserved Variables in Ansible
Variable: referenced with Double Curly braces var
Use subl to edit/create the yaml files. See if pycharm is up for it too or just np++ can equally do.
Variables can be:
~ hosts: all
vars:
web_package: httpd
~ hosts: all
vars_files:
~ var/users.yml
Precedence can be found in this Link.
Basically is : 1.- extra vars (-e in the command line) always win ; 2.- vars in play ; 3.- play vars_files ; 4.- facts ; 5.- inventory
http://docs.ansible.com/ansible/playbooks_variables.html
# - inventory_hostname is the name of the hostname as configured in Ansible’s inventory host file. ansible-playbook -e "var=value" # overrides everything
REGEX:
To modify parts of existing configuration files depending on what is already there: lineinfile. It uses classical linux regex types.
~ name: Ensure SELinux is set to enforcing mode
lineinfile:
path: /etc/selinux/config
regexp: '^SELINUX='
line: SELINUX=enforcing
CONDITIONALS:
LOOPS TO PROCESS A LIST OF ITEMS:
loop (legacy: or with_<lookup>)item keyword to go through the list.
~~~
- name: install and start services
hosts: ansible1
tasks:
- name: install packages
yum:
name:
- vsftpd
- httpd
- samba
state: latest
- name: start the services
service:
name: "{{ item }}"
state: started
enabled: yes
loop:
- vsftpd
- httpd
- smb
loopwith_file : the item contains a file, which contents are used to loop throughwith can be replaced with filters
FACT GATHERING:
ansible all -m setup -a "filter=*ipv4" ansible ubuntu -m setup # adhoc command, to see the whole fact ansible -i host localhost -m setup
This is how you go down the facts json tree and select one field. This to add the different parts of the fact (list, dictionaries..) Link
~~~
~ name: Facts2
hosts: localhost
gather_facts: yes
tasks:
~ name: task1
debug:
msg: "{{ ansible_facts['distribution'] }}"
This is to apply a when statement to the result of a fact section:
~~~
~ name: Facts2
hosts: localhost
tasks:
~ name: show fact element
debug:
msg: "{{ ansible_default_ipv4.mtu }}"
~ name: do something when mtu is 9000
debug:
msg: "THE_INTERFACE_IS_JUMBO!!!"
when: ansible_default_ipv4.mtu == 9000
This is how you go down the facts json tree and assign the value to a variable: TODO
~~TODO~~
ASSERT
Checks the veracity of an expression A bot like the fail module but with more advanced features.
fail_msg and success_msg
Example:
~~~
- hosts: localhost
vars_prompt:
- name: filesize
prompt: "specify file size"
private: no
tasks:
- name: check file size is valid
assert:
that:
- filesize <= 100
- filesize >= 1
fail_msg: "size has to be between 0 and 100!"
success_msg: "correct size, continue"
NOW FOR JUNOS DEVICES
ANSIBLE DEGUB (ansible troubleshooting):
Check this guide/section: docs.ansible.com
# Specify the location for the log file export ANSIBLE_LOG_PATH=~/ansible.log # Enable Debug export ANSIBLE_DEBUG=True # Run with 4*v for connection level verbosity ansible-playbook -vvvv ...
ROLES and Junos specifics
The below is part of the junos_facts (galaxy juniper.junos module) Juniper.junos. Use these as examples:https://junos-ansible-modules.readthedocs.io/en/2.4.0/ ; Junos galaxy page: Link
~~~
~ name: Facts2
hosts: GYRON
connection: local
gather_facts: no
roles:
~ Juniper.junos
tasks:
~ name: Gather Junos facts with no configuration
juniper_junos_facts:
Example of juniper_junos_facts
ENABLE SSH KEY AUTHENTICATION
MY TEMPLATES
add_addresses_asa1.txt
ansible_config_generator1.txt
ACUMOS PROJECT (linux fundation project, machine learning for networking):
https://www.acumos.org/author/acumos/
https://www.linuxfoundation.org/press-release/2018/03/the-linux-foundation-launches-open-source-acumos-ai-project/
All tools in a docker instance:: https://packetpushers.net/building-a-docker-network-automation-container/
ANSIBLE CUSTOM FILTERS
See Pluralsight folder: PLURALSIGHT/automating-networks-ansible-right-way/05/demos/m5/tests/tasks/test_rt_diff.yml
# Note that for a filter to get two arguments, first is left to the pipe and rests are between parenthesis
- name: "Find route-target differences"
set_fact:
rt_updates: "{{ int_vrf_list | rt_diff(run_vrf_dict) }}"
MANAGE FAILURES
ignore_errorsforce_handlers : to force a handler that has been triggered to run, even if (another) task fails.