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 🙂

Encrypt your files by Ansible Vault

So, in previous blog I have given you a brief description about ansible roles. In this blog I am going to discuss about another very important topic that is ansible vault.

Why we need encryption?

We write our ansible playbook, jinja templates and other files in normal unencrypted format but we can’t keep our crucial information such as password in unencrypted format so that’s why we need encryption.

How we can encrypt?

Just like we use ansible-playbook to run our ansible playbooks we have a option called ansible-vault to do our encryption and decryption work. Here below some important and useful commands –

  • we use ansible-vault create a_file to create a encrypted file
$ ansible-vault create a_file
New Vault password: 
Confirm New Vault password:
  • we use ansible-vault encrypt a_existing_file to encrypt a existing file
$ ansible-vault encrypt a_existing_file 
New Vault password: 
Confirm New Vault password: 
Encryption successful
  • we use ansible-vault view a_file to view the encrypted file
$ ansible-vault view a_file 
Vault password: 
You are reading Aniruddha's Blog ;)
  • we use ansible-vault decrypt a_file to decrypt any encrypted file
$ ansible-vault decrypt a_file 
Vault password: 
Decryption successful

What is vault ID?

A vault ID is an identifier for one or more vault secrets. Vault IDs, you must provide an ID of your choosing and a source to obtain it’s password (either prompt or a file path). We use --vault-id to provide the ID. Here below examples how we do –

  • We encrypt a file with ID
$ ansible-vault encrypt --vault-id id1@prompt a_file 
New vault password (id1): 
Confirm vew vault password (id1): 
Encryption successful
  • we view a file with ID
$ ansible-vault view --vault-id id1@prompt a_file 
Vault password (id1): 
You are reading Aniruddha's Blog ;)
  • we decrypt a file with ID
$ ansible-vault decrypt --vault-id id1@prompt a_file 
Vault password (id1): 
Decryption successful

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 🙂