# 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:

  1. Extra vars (from command-line) always win
  2. Play vars_files
  3. Playbook host_vars
  4. Playbook group_vars
  5. Inventory host_vars
  6. Inventory group_vars
  7. Inventory vars

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 -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

  1. opt 1: built in modules.
    1. opt1.1: napalm
    2. ntc # multi-vendor based on netmiko. eg: ntc_show_command
# 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:


~~~
- 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

FACT GATHERING:

  1. All via the setup module
  2. It goes to a variable called “ansible_factswhich is not an env variable and is only accessible via ansible. Nonetheless we can dump them to a file.
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.


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

ansible-galaxy role init <my-role>

roles for Junos

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


AWX

Install minikube (ubuntu) with:

minikube start --cpus=4 --memory=6g --addons=ingress --vm-driver=docker