Hello!

So what is a role in Ansible? Roles are a logical organization of Ansible code. For example, you can create a role that will install a MySQL database, put it in a separate repository, and make it publicly available or shared with other teams, and everyone should be able to use it

Create a Role

So how to create a role? You can create all the necessary files and folders manually or use the command ansible-galaxy role init ROLE_NAME.

ansible-galaxy role init roles/httpd
- Role roles/httpd was created successfully

I specify roles/httpd for ansible to create the roles folder. If roles/ is not specified, the role will be created in the folder where the command was executed.

$ tree roles
roles
└── httpd
    ├── README.md
    ├── defaults
    │   └── main.yml
    ├── files
    ├── handlers
    │   └── main.yml
    ├── meta
    │   └── main.yml
    ├── tasks
    │   └── main.yml
    ├── templates
    ├── tests
    │   ├── inventory
    │   └── test.yml
    └── vars
        └── main.yml

9 directories, 8 files

What is inside the roles/httpd folder?

  • defaults - here are the parameters that have the lowest priority, that is, the default values ​​of the parameters that can then be overwritten.
  • files - static files required for the role
  • handlers - handlers, this is code that is always executed at the very end, under certain conditions. For example, restart the service if the configuration file has changed.
  • meta - meta-information about the role. Title, version, author, etc
  • tasks - here are the tasks that will be performed by Ansible
  • templates - a place for files that will be dynamically generated using jinja2
  • tests - tests
  • vars - parameters that have a higher priority than the default

The main folder in which we will work tasks. Our role will install httpd, so in main.yml we will add the code that will install httpd depending on the OS.

- name: Install apache on Redhat
  ansible.builtin.yum:
    name: httpd
    state: latest
  become: yes
  when: ansible_facts['os_family'] == "RedHat"

- name: Install apache on Debian
  ansible.builtin.apt:
    name: apache2
    state: latest
  become: yes
  when: ansible_facts['os_family'] == "Debian"

After running the playbook, the httpd package will be installed but not started. To start it and enable automatic start after OS restart, we will use the service module

- name: Start service httpd, if not started
  ansible.builtin.service:
    name: apache2
    state: started
    enabled: yes
  become: yes
  when: ansible_facts['os_family'] == "Debian"

- name: Start service httpd, if not started
  ansible.builtin.service:
    name: httpd
    state: started
    enabled: yes
  become: yes
  when: ansible_facts['os_family'] == "RedHat"

Now ansible will start the httpd service on the server. Let’s add the index.html page using a template. To do this, I will create an index.html.j2 file with the following content in the templates folder

<b>Hello {{ user_name }}!</b>

Where {{ user_name }} is an ansible parameter that will be inserted into the generated file. But for this, you need to create a parameter. I will create it in defaults/main.yml.

user_name: Maksym

And finally, there is a task that will generate the file. I will add it to tasks/main.yml.

- name: Generate index.html
  template:
    src: index.html.j2
    dest: /var/www/html/index.html
  become: true

We can also use handlers. For example, if you want httpd to restart every time index.html is updated. To do this, I will add the following to handlers/main.yml

- name: Restart service httpd Debian
  ansible.builtin.service:
    name: apache2
    state: restarted
  become: yes
  when: ansible_facts['os_family'] == "Debian"

- name: Restart service httpd Redhat
  ansible.builtin.service:
    name: httpd
    state: restarted
  become: yes
  when: ansible_facts['os_family'] == "RedHat"

This is similar to the code that start httpd in the tasks folder. But this code will be called only when someone notifies handlers to run, and in our case, it will be called by creating index.html. In the code where we create index.html, we need to add a handler call.

- name: Generate index.html
  template:
    src: index.html.j2
    dest: /var/www/html/index.html
  become: true
  notify:
  - Restart service httpd Debian
  - Restart service httpd Redhat

Here I am calling two handlers, but only one will actually be executed depending on the OS.

Now the role can be used. To do this, in our main main.yml we can specify the role which we are going to use. But without roles/ in the name.

---
- name: Configure webserver
  hosts: web
  gather_facts: true

  roles:
    - httpd

main.yml located outside of roles folders. This is what the final file structure looks like

$ tree ansible
ansible
├── inventory
├── main.yml
└── roles
    └── httpd
        ├── README.md
        ├── defaults
        │   └── main.yml
        ├── files
        ├── handlers
        │   └── main.yml
        ├── meta
        │   └── main.yml
        ├── tasks
        │   └── main.yml
        ├── templates
        │   └── index.html.j2
        ├── tests
        │   ├── inventory
        │   └── test.yml
        └── vars
            └── main.yml

10 directories, 11 files

And the result

$ ansible-playbook -i inventory main.yml

PLAY [Configure webserver] *************************************************************************************************

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

TASK [httpd : Install apache on redhat] ************************************************************************************
changed: [44.201.242.83]

TASK [httpd : Start httpd] *************************************************************************************************
changed: [44.201.242.83]

TASK [httpd : Generate index.html] *****************************************************************************************
changed: [44.201.242.83]

RUNNING HANDLER [httpd : Restart httpd] ************************************************************************************
changed: [44.201.242.83]

PLAY RECAP *****************************************************************************************************************
44.201.242.83              : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

Ansible galaxy

The Ansible community has many great roles created. You can find them at ansible galaxy. For example, after entering httpd in the search, I found a role that installs httpd. Here you can read the role documentation and instructions on how to download it. This would normally be ansible-galaxy install ROLE_NAME

$ ansible-galaxy install buluma.httpd
Starting galaxy role install process
- downloading role 'httpd', owned by buluma
- downloading role from https://github.com/buluma/ansible-role-httpd/archive/1.0.9.tar.gz
- extracting buluma.httpd to /home/maksym/.ansible/roles/buluma.httpd
- buluma.httpd (1.0.9) was installed successfully

Now I can specify this role in main.yml

---
- name: Configure webserver
  hosts: web
  gather_facts: true
  become: true

  roles:
    - buluma.httpd
ansible-playbook -i inventory main.yml

PLAY [Configure webserver] *************************************************************************************************

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

TASK [buluma.httpd : Test if httpd_servername is set correctly] ************************************************************
ok: [44.201.242.83 -> localhost]

TASK [buluma.httpd : Test if httpd_port is set correctly] ******************************************************************
ok: [44.201.242.83 -> localhost]

TASK [buluma.httpd : Test if https_ssl_enable is set correctly] ************************************************************
ok: [44.201.242.83 -> localhost]

TASK [buluma.httpd : Test if httpd_ssl_servername is set correctly] ********************************************************
ok: [44.201.242.83 -> localhost]

TASK [buluma.httpd : Test if httpd_ssl_port is set correctly] **************************************************************
ok: [44.201.242.83 -> localhost]

TASK [buluma.httpd : Test if httpd_locations is set correctly] *************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if item in httpd_locations is set correctly] *****************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if httpd_vhosts is set correctly] ****************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if item in httpd_vhosts is set correctly] ********************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if item.create_docroot in httpd_vhosts is set correctly] *****************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if item.serveralias in httpd_vhosts is set correctly] ********************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if httpd_directories is set correctly] ***********************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if item.name in httpd_directories is set correctly] **********************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if item.options in httpd_directories is set correctly] *******************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if item.allow_override in httpd_directories is set correctly] ************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Test if httpd_remove_example is set correctly] ********************************************************
ok: [44.201.242.83 -> localhost]

TASK [buluma.httpd : Install apache httpd] *********************************************************************************
ok: [44.201.242.83]

TASK [buluma.httpd : Modify selinux settings] ******************************************************************************
skipping: [44.201.242.83] => (item=httpd_can_network_connect)

TASK [buluma.httpd : Allow connections to custom port] *********************************************************************
skipping: [44.201.242.83] => (item=80)
skipping: [44.201.242.83] => (item=443)

TASK [buluma.httpd : Configure httpd] **************************************************************************************
changed: [44.201.242.83]

TASK [buluma.httpd : Install ssl packages] *********************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Place configuration] **********************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Configure redirect from http to https] ****************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Enable modules] ***************************************************************************************
skipping: [44.201.242.83] => (item=proxy)
skipping: [44.201.242.83] => (item=proxy_http)

TASK [buluma.httpd : Configure locations] **********************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Create docroot] ***************************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Configure vhosts] *************************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Configure ports] **************************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Create directories] ***********************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Configure directories] ********************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Flush handlers] ***************************************************************************************

RUNNING HANDLER [buluma.httpd : Test httpd configuration validity] *********************************************************
ok: [44.201.242.83]

RUNNING HANDLER [buluma.httpd : Restart httpd] *****************************************************************************
changed: [44.201.242.83]

TASK [buluma.httpd : Removing default html] ********************************************************************************
skipping: [44.201.242.83]

TASK [buluma.httpd : Start and enable httpd] *******************************************************************************
ok: [44.201.242.83]

PLAY RECAP *****************************************************************************************************************
44.201.242.83              : ok=12   changed=2    unreachable=0    failed=0    skipped=23   rescued=0    ignored=0

Video