Send emails through ansible

Recently I was watching this video and got to know about `mail` attribute in ansible and we can send emails through it and I gave it a try and finally after some hacks I sent an email from my one account to another.

Here below code I have written to send the email –

---
- hosts: webservers
  tasks:
  - name: Sending an e-mail using Gmail SMTP servers
    mail:
      host: smtp.gmail.com
      port: 587
      username: your@email.com
      password: yourPassword
      to: Aniruddha Basak <some@email.com>
      subject: Ansible check email
      body: I am using {{ ansible_facts['os_family'] }}.
    delegate_to: localhost

Above we are using gmail SMTP server. In case you are using 2FA of google then you have to add a device password for that and write the password in the password field.

Take user input by ansible prompts

In ansible we generally execute instruction written in playbook one after another. In some cases we have to collect some data from the user that can be a sensitive data or not. In this scenario we use prompts to collect the data from the user. We write all our prompts inside vars_prompt section. By default the data we write as input is private and we can change it by private: no . Below there is a basic example of ansible prompt.

---
- hosts: webservers
  vars_prompt:
    - name: username
      prompt: "What is your username?"
      private: no
    
    - name: password_1
      prompt: "What is your password?"

Here is the result –

$ ansible-playbook prompt.yml 
What is your username?: ani
What is your password?: 

PLAY [webservers] ***************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************
ok: [localhost]

PLAY RECAP **********************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0 

We can even set a default value for any prompt and by default: 'value' and if there is a need of verifying any value like password then we can do this by confirm: yes . Below there is a example –

---
- hosts: webservers
  vars_prompt:
    - name: release_version
      prompt: "What is product release version?"
      private: no
      default: "1.0"
    
    - name: password_2
      prompt: "Enter password_2"
      confirm: yes

Here is the result of the above playbook –

$ ansible-playbook prompt.yml 
What is product release version? [1.0]: 2.0
Enter password_2: 
confirm Enter password_2: 
***** VALUES ENTERED DO NOT MATCH ****
Enter password_2: 
confirm Enter password_2: 

PLAY [webservers] ***************************************************************************************************************************

TASK [Gathering Facts] **********************************************************************************************************************
ok: [localhost]

PLAY RECAP **********************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

In the above you can see that the default value in the square bracket what we have mention in the playbook and if we skip that part then ansible will take the default value. You can see that we have entered the confirmed password wrong so it is showing a warning like this **** VALUES ENTERED DO NOT MATCH **** and second time we have entered the right value that’s why everything is ok.

Thank you 🙂

Reusable playbooks, Ansible roles

So, in this blog I have told you about “what is Ansible, playbooks, hosts?” now it is the time to go further with roles. In the world of programming we have a principle called DRY which is “Don’t repeat yourself” means don’t do any work again and again. For that we try to make a process that we have to write the code one time and we can use it again and again without rewriting the whole code again and again.

In the era of automation Ansible also gives us a certain technique that if we need a part of playbook multiple files then we can write it inside a role and use it again and again. It also helps us to reduce the complexity of the code like it is always better to break down a big playbook in a small parts and use it.

Basically for the role we define it inside a roles directory. inside this directory we define or every role and inside the role their will be multiple directories below you can see it –

$ tree .
.
├── roles
│   └── webservers
│       ├── defaults
│       ├── files
│       ├── handlers
│       ├── meta
│       ├── tasks
│       ├── templates
│       └── vars
└── web.yml

Roles expect files to be in certain directory names. Roles must include at least one of these directories, however it is perfectly ok to exclude any which are not being used. When in use, each directory must contain a main.yml file, which contains the relevant content:

  • tasks – contains the main list of tasks to be executed by the role.
  • handlers contains handlers which may be used by the roles or elsewhere in the code.
  • defaults contains variables for the roles.
  • vars contains other variables for the roles.
  • files contains files which will deploy by the roles.
  • templates contains templates which can be deployed via roles.
  • meta contains meta data.

So, now see by example how roles helps us in the various aspects of automation. Below the code is without roles –


---
- hosts: webservers
  gather_facts: yes
  remote_user: root
  become: true
  tasks:
    - name: Ensure group {{ item }} exist
    group:
      name: "{{ item }}"
      state: present
    loop:
      - mozilla
      - dgplug
  - name: add several users to several group
    user:
      name: "{{ item.name }}"
      state: present
      groups: "{{ item.groups }}"
    loop:
      - { name: 'testuser1', groups: 'mozilla' }
      - { name: 'testuser2', groups: 'dgplug' }
  - name: remove several users to several group
    user:
      name: "{{ item.name }}"
      state: absent
      groups: "{{ item.groups }}"
    loop:
      - { name: 'testuser1', groups: 'mozilla' }
      - { name: 'testuser2', groups: 'dgplug' }

Now see how we can implement this via roles –

# web.yml
---
- hosts: webservers
  become: true
  roles:
    - role: '/home/aniruddha/Desktop/ansible-playbook/roles/webservers'

# roles/webservers/tasks/add_group/main.yml
---
tasks:
  - name: Ensure group {{ item }} exist
  group:
    name: "{{ item }}"
    state: present
  loop:
    - mozilla
    - dgplug

# roles/webservers/tasks/add_user_to_group/main.yml
---
tasks:
  - name: add several users to several group
  user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  loop:
    - { name: 'testuser1', groups: 'mozilla' }
    - { name: 'testuser2', groups: 'dgplug' }

# roles/webservers/tasks/remove_user_from_group/main.yml
---
tasks:
  - name: Remove several users from different group
  user:
    name: "{{ item.name }}"
    state: absent
    group: "{{ item.groups }}"
  loop:
    - { name: 'testuser1', groups: 'mozilla' }
    - { name: 'testuser2', groups: 'dgplug' }

Thank you 🙂