Ansible Introduction

Ansible Introduction

Here is a basic understanding of ansible configuration file, playbooks, modules, plugins, Handlers, Roles, Collections, and jinja2 Templates.

Ansible Configuration File

when you install, it creates a default configuration at the location :- /etc/ansible/ansible.cfg

but what if you want your custom config file outside of your playbook file ?
you can place your config file outside of your playbook file and specify the location of this configuration file through an environmental variable before running the ansible playbook.

ANSIBLE_CONFIG=/opt/ansibleweb.cfg ansible-playbook playbook.yaml

this time when a playbook runs, this time it will pick the custom config file.

and suppose you have configured all these files with different values for different different parameters, then which files will have what priority ?

the first priority will be for the configuration file you are specifying through environment variables

followed by the ansible.cfg in the current directory, where the ansible playbooks are running and then followed by the .ansible.cfg file in user home directory
and last the default configuration file.

Also if you want to change a single parameter for your playbook you can over-write the single parameter value by an environment variable.
you can set it up just right before executing the ansible playbook.

ansible-config list # to list all config files
ansible-config view # shows the current config file
ansible-config dump # shows the current settings

Ansible Inventory

Ansible needs to establish connection with the servers to work with them. There is no need of any agent to be installed in the target servers , That's why ansible is agentless. for Linux servers ansible use SSH based connectivity whereas for windows servers ansible use PowerShell remoting.

The Information about the target machines are being stored in an Inventory File. Ansible has it's default Inventory file located at /etc/ansible/hosts and if you don't create any new inventory file, ansible use it's default inventory file. we can specify our target machines in the inventory file

[common]
database_server1.learning.com
Loggingserver2.learning.com
webserver3.learning.com

[database]
database_server1.learning.com
database_server2.learning.com
database_server3.learning.com

[messaging]
messaging_server1.learning.com
messaging_server1.learning.com
messaging_server1.learning.com

we can add alias name for the servers by using ansible_host parameter.

database ansible_host=database_server1.learning.com

ansible_host is ana inventory parameter used to specify the FQDN or IP address of a server

Inventory parameters

there are multiple ansible inventory parameters are available.

ansible_connection-ssh/localhost/winrm
ansible_port-22
ansible_usr-root-admin
ansible_ssh_pass-mypassword

Inventory formats

  1. INI

  2. yaml

yaml format : Its more structured.

all:
   childeren:
       database:
             hosts:
                  database_server1.learning.com
                  database_server2.learning.com
                  database_server3.learning.com
        messaging:
              hosts:
                  messaging_server1.learning.com
                  messaging_server1.learning.com
                  messaging_server1.learning.com

Verifying playbooks

we can use check mode and diff mode to verify our ansible playbooks.
check:
Using this mode you can do the DRY RUN of your playbook and no actual modification happens here.

ansible-playbook install-nginx.yml --check

Note: all ansible modules does not support check mode. If a task uses a module that does not support check mode then task will be skipped when you run the playbook in check mode.

**diff:
**Using diff mode you can check the difference in playbook before and after changing

ansible-playbook install-nginx.yml --diff
ansible-playbook install-nginx.yml --check --diff # check and diff option both

Syntax check:
This helps us to ensure our playbook syntax is error free.

ansible-playbook install-nginx.yml --syntax-check

ansible-lint:
It checks our code for potential issues, bugs and stylistic errors etc.

ansible-lint install-nginx.yml

Conditions:

we can use conditional statements like when to execute a particular task if the condition satisfies.

---
- name: install-nginx
  hosts: all
  tasks:
    - name: install nginx on debian
      apt:
        name: nginx
        state: present
      when: ansible_os_family == 'Debian' and
            ansible_distribution_version == "16.04"
    - name: install nginx on Redhat
      apt:
        name: nginx
        state: present
      when: ansible_os_family == 'Redhat' or 
            ansible_os_family == 'SUSE'

we can use variables as well.

---
- name: install-multiple-packages.yml
  hosts: all
  vars:
    packages:
      - name: nginx
        required: True
      - name: mysql
        required: True
      - name: apache
        required: False
   tasks:
     - name: install "{{item.name}}" on Debian
       apt:
         name: "{{item.name}}"
         state: present
       when: item.required == True
       loop: "{{ packages }}"

register:

to record a output of one task we can use register directive. and we can use this for next task as required.

---
- name: send a email if service is down
  hosts: all
  tasks:
    - name: check service status
      command: service httpd status
      register: result 
    - mail:
        to: abinashmishra@005gmail.com
        subject: service alerts
        body: http is down
        when: result.stdout.find('down') != -1

ansible facts

Variables related to remote systems are called facts in ansible. ansible facts are system defined variables that can be used in the playbooks. To see all available facts, add this task to a play:

- name: Print all available facts
  ansible.builtin.debug:
    var: ansible_facts

ansible facts collects information about the server during the execution of the playbook.

- name: install nginx
    apt:
       name: nginx=1.18.0
       state: present
    when: ansible_facts{os_family} == 'Debian' and ansible_facts{distribution_major_version} == '18'

another example:

- name: start service 
   service: 
       name: abiapp
       state: started
   when: environment == 'production'

loops:

loop is a looping directive that executes same task multiple number of times. Each time it runs, It store value of each item in the loop in a variable named item. and then you can simply replace the user name as variable like this '{{ item }}' general way:

- name: create users
   hosts: localhost
   tasks:
       user: name=abi             state: present
       user: name=krishna      state: present
       user: name=john           state: present

using loops:

- name: create users
  hosts: localhost
  tasks:
   - user: name='{{ item.name }}' state: present UID: '{{ item.UID }}'
     loop:
       - name: abi
          UID: 1234
       - name: krishna
          UID: 0001
       - name: john
          UID: 4567

with_*

- name: create users 
  hosts: localhost
  tasks:
   - user: name='{{ item.name }}' state: present UID: '{{ item.UID }}' 
     with_item:
        - name: abi
           UID: 0002
        - name: krishna 
           UID: 0001
        - name: john 
           UID: 4567

many other options:

with_file
with_url
with_mangodb
with_env
with_filetree

Modules

click here for ansible modules documentation page.
Idempotency:
An action which, when performed multiple times, has no further effect on its subject after the first time it is performed.

command:
executes a command on a remote node.

- name: add dns entry to resolve.conf
  host: localhost
  tasks:
   - name: execute a command
     command: date
   - name: display a file content
     command: cat abc.txt

script:
run a local script on a remote node after transferring it.
it works in 2 steps

  1. copy script in all remote server nodes

  2. execute the script in those nodes

- name: run a local script
  host: localhost
  tasks:
   - name: execute a script
     script: /usr/abi/abc.sh

service:
manage services such as srtart stop restart

- name: add dns entry to resolve.conf
  host: localhost
  tasks:
   - name: start nginxservice
     service:
        name: nginx
        state: started
or,
     service: name=nginx state=started

lineinfile:
This module search for a line in a file and replace it or add if doesn't exist.

- name: add dns entry to resolve.conf
  host: localhost
  tasks:
   - linefile:
       path: /etc/resolve.conf
       line: nameserver 10.250.0.1

plugins

In ansible plugin is a piece of code which augments ansible's core functionality.
Plugins can be used to enhance various functionality of ansible such as inventory, filters, callback and modules etc.

click here for ansible plugin documentation page

dynamic inventory plugin: It helps ansible to fetch data from various sources like cloud provider
module plugin: Modules are the main building blocks of Ansible playbooks. Although we do not generally speak of “module plugins”, a module is a type of plugin.
action plugin: Action plugins act in conjunction with modules to execute the actions required by playbook tasks. They usually execute automatically in the background doing prerequisite work before modules execute.
lookup plugin - fetch data from external sources like databases and APIs and allow you to use the data in your playbook.
filter plugins: It manipulates data. With the right filter, you can extract a particular value, transform data types and formats, perform mathematical calculations etc.
connection plugin: It helps ansible to connect various target system like SSH, WinRM, docker
Callback plugins : It allows you to capture events and perform custom actions during execution of playbook

Also we have modules and plugins index to check what to use and how to