{"id":1254,"date":"2024-04-23T07:28:46","date_gmt":"2024-04-23T07:28:46","guid":{"rendered":"http:\/\/shijuvarghese.com\/?p=1254"},"modified":"2025-08-13T13:51:54","modified_gmt":"2025-08-13T13:51:54","slug":"ansible-roles","status":"publish","type":"post","link":"http:\/\/shijuvarghese.com\/?p=1254","title":{"rendered":"Ansible: Roles"},"content":{"rendered":"<p>Roles is a feature provided by Ansible were once a\u00a0standardized directory structure is created, you can automatically load related vars, files, tasks, handlers, and other Ansible artifacts. Using roles\u00a0we\u00a0have opportunities to\u00a0reuse code from playbooks that you wrote previously. We can copy a role from project to project by copying\u00a0the directory, then calling the role within a play.\u00a0Also, a well planned\u00a0role can take variables from the playbook that is calling the role. It is a collection of YAML task files and supporting items arranged in a specific structure.<\/p>\n<p>Below is an example of know directory structure of role:<\/p>\n<p><a href=\"http:\/\/shijuvarghese.com\/wp-content\/uploads\/2024\/04\/ansible-roles.jpg\" rel=\"attachment wp-att-1257\"><img loading=\"lazy\" decoding=\"async\" class=\"aligncenter size-full wp-image-1257\" src=\"http:\/\/shijuvarghese.com\/wp-content\/uploads\/2024\/04\/ansible-roles.jpg\" alt=\"ansible-roles\" width=\"309\" height=\"382\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>In the above directory structure, the <em>files<\/em> subdirectory contains fixed content files and the <em>templates<\/em> subdirectory contains\u00a0templates such as\u00a0one in\u00a0Jinja format, etc that the role can deploy.<\/p>\n<p>You can create the directory structure and files needed for a new role by using standard Linux<br \/>\ncommands, or alternatively we can use command-line utilities such as ansible-galaxy to automate the process of new role<br \/>\ncreation.<\/p>\n<p>The value\u00a0associated with any variable presentin a role\u2019s <strong>defaults<\/strong> directory is overwritten if that same<br \/>\nvariable is defined:<\/p>\n<p>\u2022 In an inventory file<br \/>\n\u2022 In a playbook<\/p>\n<p>The <em>main.yml<\/em> file in <strong>meta<\/strong> subdirectory in a role directory structure specifies information about the author, license, compatibility, and\u00a0<em>dependencies<\/em> for the module.<\/p>\n<p><em>Role dependencies<\/em> enables a role to include other roles as dependencies.<\/p>\n<p><strong>Ansible Galaxy<\/strong> is a free site for downloading all kinds of community-developed Ansible roles, and can thus speed-up your automation projects.<\/p>\n<p>The ansible-galaxy client tool allows you to download roles from Ansible Galaxy and provides an excellent default framework for creating your own roles.<\/p>\n<p>The below comment creates a role for myhost<\/p>\n<p><strong>[root@centos9vm ~]#\u00a0<\/strong>ansible-galaxy init roles\/myvhost<\/p>\n<p><strong>[root@centos9vm ~]#<\/strong> ls -l myvhost\/<\/p>\n<p>==== ==<br \/>\n<em>total 4<\/em><br \/>\n<em>drwxr-xr-x. 2 root root 22 Apr 17 14:21 defaults<\/em><br \/>\n<em>drwxr-xr-x. 2 root root 6 Apr 17 14:21 files<\/em><br \/>\n<em>drwxr-xr-x. 2 root root 22 Apr 22 17:40 handlers<\/em><br \/>\n<em>drwxr-xr-x. 2 root root 22 Apr 17 14:21 meta<\/em><br \/>\n<em>-rw-r&#8211;r&#8211;. 1 root root 1328 Apr 17 14:21 README.md<\/em><br \/>\n<em>drwxr-xr-x. 2 root root 22 Apr 22 22:33 tasks<\/em><br \/>\n<em>drwxr-xr-x. 2 root root 27 Apr 22 21:59 templates<\/em><br \/>\n<em>drwxr-xr-x. 2 root root 39 Apr 17 14:21 tests<\/em><br \/>\n<em>drwxr-xr-x. 2 root root 22 Apr 17 14:21 vars<\/em><\/p>\n<p>==== =<\/p>\n<p>Let us create a yml file that creates 3 task under the\u00a0myvhost\/tasks folder. One is to install httpd, another to start httpd, and creates a config file in the managed node using template.<\/p>\n<p><strong>[root@centos9vm roles]#<\/strong> cat myvhost\/tasks\/main.yml<\/p>\n<p>==== ===<br \/>\n<em>&#8211; &#8211; &#8211;<\/em><br \/>\n<em># tasks file for myvhost<\/em><br \/>\n<em>&#8211; name: Ensure httpd is installed<\/em><br \/>\n<em>\u00a0\u00a0 ansible.builtin.dnf:<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 name: httpd<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 state: latest<\/em><\/p>\n<p><em>&#8211; name: Start httpd service<\/em><br \/>\n<em>\u00a0\u00a0 ansible.builtin.service:<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 name: httpd<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 state: started<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 enabled: true<\/em><\/p>\n<p><em>&#8211; name: vhost file is installed<\/em><br \/>\n<em>\u00a0\u00a0 ansible.builtin.template:<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 src: vhost.conf.j2<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 dest: \/etc\/httpd\/conf.d\/vhost.conf<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 owner: root<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 group: root<\/em><br \/>\n<em>\u00a0\u00a0 \u00a0\u00a0 mode: 0644<\/em><br \/>\n<em>\u00a0\u00a0 notify: Restart httpd<\/em><\/p>\n<p>=== ===<\/p>\n<p>If we notice in the above file, we have a task to use &#8220;<em>vhost.conf.j2<\/em>&#8220;, but have not provided a full path of the jinja file. As we are using roles, ansible will search for the file in the &#8220;<em>template<\/em>&#8221; directory created.<\/p>\n<p><strong>[root@centos9vm roles]#<\/strong> cat myvhost\/templates\/vhost.conf.j2<\/p>\n<p>===== ====<br \/>\n# {{ ansible_managed }}<\/p>\n<p>&lt;VirtualHost *:80&gt;<br \/>\nServerAdmin webmaster@{{ ansible_fqdn }}<br \/>\nServerName {{ ansible_fqdn }}<br \/>\nErrorLog logs\/{{ ansible_hostname }}-error.log<br \/>\nCustomLog logs\/{{ ansible_hostname }}-common.log common<br \/>\nDocumentRoot \/var\/www\/vhosts\/{{ ansible_hostname }}\/<br \/>\n&lt;Directory \/var\/www\/vhosts\/{{ ansible_hostname }}\/&gt;<br \/>\nOptions +Indexes +FollowSymlinks +Includes<br \/>\nOrder allow,deny<br \/>\nAllow from all<br \/>\n&lt;\/Directory&gt;<br \/>\n&lt;\/VirtualHost&gt;<\/p>\n<p>===== ===<\/p>\n<p>As we can notice in the first yml file &#8220;<em>myvhost\/tasks\/main.yml<\/em>&#8221; the last task calls a handler named &#8220;<em>Restart httpd<\/em>&#8220;. The expectancy is that role will search for the handlers in the &#8220;<em><strong>handlers<\/strong><\/em>&#8221; directory.<\/p>\n<p><strong>[root@centos9vm roles]#<\/strong> cat myvhost\/handlers\/main.yml<\/p>\n<p>===== ====<br \/>\n<em>&#8211; &#8211; &#8211;<\/em><br \/>\n<em> # handlers file for myvhost<\/em><\/p>\n<p><em>&#8211; name: Restart httpd<\/em><br \/>\n<em>\u00a0 \u00a0ansible.builtin.service:<\/em><br \/>\n<em>\u00a0 \u00a0name: httpd<\/em><br \/>\n<em>\u00a0 \u00a0state: restarted<\/em><\/p>\n<p>===== ===<\/p>\n<p>Now let us tie and execute all these using role feature, by creating a playbook.<\/p>\n<p><strong>[root@centos9vm roles]#<\/strong> cat use-vhost-role.yml<\/p>\n<p>==== === ==<br \/>\n<em>&#8211; &#8211; &#8211;<\/em><br \/>\n<em> &#8211; name: Use vhost role playbook<\/em><br \/>\n<em>\u00a0 \u00a0hosts: 192.168.48.129<\/em><br \/>\n<em>\u00a0 \u00a0pre_tasks:<\/em><br \/>\n<em>\u00a0 \u00a0\u00a0 \u00a0&#8211; name: pre_tasks message<\/em><br \/>\n<em>\u00a0 \u00a0\u00a0 \u00a0\u00a0 \u00a0ansible.builtin.debug:<\/em><br \/>\n<em>\u00a0 \u00a0\u00a0 \u00a0\u00a0 \u00a0\u00a0 \u00a0msg: &#8216;Ensure web server configuration.&#8217;<\/em><\/p>\n<p><em>\u00a0 \u00a0roles:<\/em><br \/>\n<em> \u00a0 \u00a0\u00a0 \u00a0&#8211; myvhost<\/em><\/p>\n<p><em>\u00a0 \u00a0post_tasks:<\/em><\/p>\n<p><em>\u00a0 \u00a0&#8211; name: post_tasks message<\/em><br \/>\n<em> \u00a0 \u00a0\u00a0 \u00a0ansible.builtin.debug:<\/em><br \/>\n<em> \u00a0 \u00a0\u00a0 \u00a0\u00a0 \u00a0msg: &#8216;Web server is configured.&#8217;<\/em><\/p>\n<p>=== === ==<\/p>\n<p>If we notice above the roles block calls myhost role, which in turn will execute tasks from &#8220;tasks&#8221; folder in the directory structure.<\/p>\n<p>Now let us run the playbook and see the results.<\/p>\n<p><strong>[root@centos9vm ~]#<\/strong> ansible-navigator run -m stdout use-vhost-role.yml<\/p>\n<p>==== ======<\/p>\n<p>PLAY [Use vhost role playbook] *************************************************<\/p>\n<p>TASK [Gathering Facts] *********************************************************<br \/>\nok: [192.168.48.129]<\/p>\n<p>TASK [pre_tasks message] *******************************************************<br \/>\nok: [192.168.48.129] =&gt; {<br \/>\n&#8220;msg&#8221;: &#8220;Ensure web server configuration.&#8221;<br \/>\n}<\/p>\n<p>TASK [myvhost : Ensure httpd is installed] *************************************<br \/>\nchanged: [192.168.48.129]<\/p>\n<p>TASK [myvhost : Start httpd service] *******************************************<br \/>\nchanged: [192.168.48.129]<\/p>\n<p>TASK [myvhost : vhost file is installed] ***************************************<br \/>\nchanged: [192.168.48.129]<\/p>\n<p>RUNNING HANDLER [myvhost : Restart httpd] **************************************<br \/>\nchanged: [192.168.48.129]<\/p>\n<p>TASK [HTML content is included] ************************************************<br \/>\nok: [192.168.48.129]<\/p>\n<p>TASK [post_tasks message] ******************************************************<br \/>\nok: [192.168.48.129] =&gt; {<br \/>\n&#8220;msg&#8221;: &#8220;Web server is configured.&#8221;<br \/>\n}<\/p>\n<p>PLAY RECAP *********************************************************************<br \/>\n192.168.48.129 : ok=8 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0<\/p>\n<p style=\"text-align: center;\"><strong><span style=\"text-decoration: underline;\">Roles from External Content Sources<\/span><\/strong><\/p>\n<p style=\"text-align: left;\">We can deploy roles if needed from external content sources such as from\u00a0<strong>Git repositories<\/strong> or <strong>Ansible Galaxy<\/strong>.<\/p>\n<p style=\"text-align: left;\">A\u00a0<strong>role<\/strong> may be pulled from a\u00a0<strong>git<\/strong> repository, or even downloaded as a\u00a0<strong>tar achieve<\/strong> downloadable from some source.<\/p>\n<p style=\"text-align: left;\">A public library of Ansible content is available at https:\/\/galaxy.ansible.com[Ansible Galaxy]. It is written by several Ansible administrators and users. The\u00a0<strong>ansible-galaxy<\/strong> is used to download and use these roles.<\/p>\n<p style=\"text-align: left;\">If you have a playbook that must have specific roles installed, you can create &#8220;requirements.yml&#8221; file in the roles folder\u00a0in the project directory that specifies which roles are needed.\u00a0In this case the <em>ansible-galaxy command<\/em> should be run before you run ansible-navigator to install those roles in your project\u2019s roles directory.<\/p>\n<p style=\"text-align: left;\">Few examples of &#8220;requirements.yml&#8221; are as follows:<\/p>\n<p style=\"text-align: left;\"><strong>[root@centos9vm ~]#<\/strong> cat roles\/requirements.yml<\/p>\n<p style=\"text-align: left;\">===== ==<\/p>\n<p style=\"text-align: left;\">&#8211; &#8211; &#8211;<br \/>\n<em>&#8211; src: https:\/\/git.example.com\/someuser\/someuser.myrole<\/em><br \/>\n<em>\u00a0 \u00a0scm: git<\/em><br \/>\n<em>\u00a0 \u00a0version: &#8220;1.5.0&#8221;<\/em><\/p>\n<p style=\"text-align: left;\">==== ==<\/p>\n<p style=\"text-align: left;\"><strong>[root@centos9vm ~]#<\/strong>\u00a0ansible-galaxy role install -r roles\/requirements.yml\u00a0-p roles<\/p>\n<p style=\"text-align: left;\">===== ==<br \/>\n<em>Starting galaxy role install process<\/em><br \/>\n<em>&#8211; downloading role from https:\/\/git.example.com\/someuser\/someuser.myrole<\/em><br \/>\n<em>&#8211; extracting myrole to \/home\/user\/project\/roles\/someuser.myrole<\/em><br \/>\n<em>&#8211; someuser.myrole (1.5.0) was installed successfully<\/em><\/p>\n<p style=\"text-align: left;\">==== ===<\/p>\n<p style=\"text-align: left;\">Examples of &#8220;requirements.yml&#8221; to download tar files are as follows:<\/p>\n<p style=\"text-align: left;\">=== ===<\/p>\n<p style=\"text-align: left;\"><em>&#8211; src: file:\/\/\/opt\/local\/roles\/tarrole.tar<\/em><br \/>\n<em>\u00a0 \u00a0name: tarrole<\/em><\/p>\n<p style=\"text-align: left;\"><em>&#8211; src: https:\/\/www.example.com\/role-archive\/someuser.otherrole.tar<\/em><br \/>\n<em>\u00a0 \u00a0name: someuser.otherrole<\/em><\/p>\n<p style=\"text-align: left;\">==== ===<\/p>\n<p style=\"text-align: left;\">The command to list the roles downloaded from Ansible Galaxy is as follows:<\/p>\n<p style=\"text-align: left;\"><strong>[root@centos9vm pre-exam]#<\/strong> ansible-galaxy list<\/p>\n<p style=\"text-align: left;\">==== ===<br \/>\n# \/usr\/share\/ansible\/roles<br \/>\n&#8211; linux-system-roles.fapolicyd, (unknown version)<br \/>\n&#8211; linux-system-roles.firewall, (unknown version)<br \/>\n&#8211; linux-system-roles.gfs2, (unknown version)<br \/>\n&#8211; linux-system-roles.ha_cluster, (unknown version)<\/p>\n<p style=\"text-align: left;\">.<br \/>\n.<br \/>\n.<\/p>\n<p style=\"text-align: left;\">======<\/p>\n<p style=\"text-align: left;\">If any dowloaded and installed role is stores in a specific folder, then you can run the command with\u00a0<strong>-p<\/strong> switch as below:<\/p>\n<p style=\"text-align: left;\"><strong>[root@centos9vm role-galaxy]#<\/strong> ansible-galaxy list -p system-storage\/<\/p>\n<p style=\"text-align: left;\">===== =<br \/>\n<em># \/root\/role-galaxy\/system-storage<\/em><br \/>\n<em>&#8211; rhel-system-roles.storage, (unknown version)<\/em><br \/>\n<em># \/usr\/share\/ansible\/roles<\/em><br \/>\n<em>&#8211; linux-system-roles.fapolicyd, (unknown version)<\/em><br \/>\n<em>&#8211; linux-system-roles.firewall, (unknown version)<\/em><br \/>\n<em>&#8211; linux-system-roles.gfs2, (unknown version)<\/em><br \/>\n<em>&#8211; linux-syst<\/em><\/p>\n<p style=\"text-align: center;\"><strong>Searching Roles from Ansibe-Galaxy<\/strong><br \/>\n<strong> ======*******======<\/strong><\/p>\n<p style=\"text-align: left;\">We can search for roles from Ansible Galaxy using the following command.<\/p>\n<p><strong>[root@centos9vm ~]#<\/strong> ansible-galaxy search &#8216;storage&#8217;<\/p>\n<p>======= ==<em><br \/>\n<\/em><\/p>\n<p><em>Found 42 roles matching your search:<\/em><\/p>\n<p><em>Name Description<\/em><br \/>\n<em> &#8212;- &#8212;&#8212;&#8212;&#8211;<\/em><br \/>\n<em> Akrog.storage Storage management and consumption<\/em><br \/>\n<em> ashleykleynhans.ovirt_storage_domain Ansible role to get a list of oVirt storage domains through the oVirt REST API, and return the name of the sto&gt;<\/em><br \/>\n<em>linux-system-roles.storage Configure volumes and filesystems<\/em><br \/>\n.<br \/>\n.<br \/>\n.<\/p>\n<p>======= ===<\/p>\n<p>Information regarding a role can be found using the following command:<\/p>\n<p><strong>[root@centos9vm ~]#<\/strong> ansible-galaxy info linux-system-roles.storage<br \/>\n====== ====<\/p>\n<p>Role: linux-system-roles.storage<br \/>\ndescription: Configure volumes and filesystems<br \/>\ncommit: bd70d66ac8188db09b183e7e9b0f86eec8412b10<br \/>\n====== ====<\/p>\n<p>The above role can be downloaded using the requirements.yml file<\/p>\n<p><strong>[root@centos9vm ~]#<\/strong> cat pre-exam\/roles\/requirements.yml<\/p>\n<p>====== ==<br \/>\n<em>&#8211; &#8211; &#8211;<\/em><br \/>\n<em>&#8211; src: linux-system-roles.storage<\/em><\/p>\n<p>==== ===<\/p>\n<p><strong>[root@centos9vm ~]#<\/strong>\u00a0ls pre-exam\/roles\/<\/p>\n<p><strong>[root@centos9vm ~]#<\/strong> ansible-galaxy role install -r roles\/requirements.yml -p pre-exam\/roles\/<\/p>\n<p><em>====<\/em><br \/>\n<em>Starting galaxy role install process<\/em><br \/>\n<em>&#8211; downloading role &#8216;storage&#8217;, owned by linux-system-roles<\/em><br \/>\n<em>&#8211; downloading role from https:\/\/github<\/em><br \/>\n<em>====<\/em><\/p>\n<p><strong>[root@centos9vm ~]#<\/strong> ls -lA pre-exam\/roles\/<br \/>\n<em>total 8<\/em><br \/>\n<em>drwxr-xr-x. 12 root root 4096 Jun 24 02:53 linux-system-roles.storage<\/em><br \/>\n<em>-rw-r&#8211;r&#8211;. 1 root root 38 Jun 24 02:53 requirements.yml<\/em><br \/>\n<em>==== ===<\/em><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p>Roles is a feature provided by Ansible were once a\u00a0standardized directory structure is created, you can automatically load related vars, files, tasks, handlers, and other <a class=\"mh-excerpt-more\" href=\"http:\/\/shijuvarghese.com\/?p=1254\" title=\"Ansible: Roles\">[&#8230;]<\/a><\/p>\n<\/div>","protected":false},"author":1,"featured_media":1792,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[32,21,3],"tags":[],"class_list":["post-1254","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ansible","category-devops","category-linux"],"_links":{"self":[{"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=\/wp\/v2\/posts\/1254","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1254"}],"version-history":[{"count":47,"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=\/wp\/v2\/posts\/1254\/revisions"}],"predecessor-version":[{"id":1542,"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=\/wp\/v2\/posts\/1254\/revisions\/1542"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=\/wp\/v2\/media\/1792"}],"wp:attachment":[{"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1254"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1254"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/shijuvarghese.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1254"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}