How to use and build system roles
1. Control execution sequence
For each play in the playbook, tasks are executed in the order in the task list. After all tasks are executed, the handler of the task notification will be executed
After the role is added to the play, the role task will be added to the beginning of the task list. If the play contains a second role, its task list is added after the first role.
Role handlers are added to play in the same way that role tasks are added to play. Each play defines a list of handlers. The role handler is first added to the handler list, followed by any handler defined in the handlers section of play.
In some cases, you may need to perform some play tasks before the role. To support this scenario, you can configure pre for play_ Tasks section. All tasks listed in this section will be performed before performing any roles. If any of these tasks notifies the handler, these handler tasks are also executed before the role or normal task.
In addition, play also supports post_tasks keyword. These tasks are executed after the normal tasks of play and any handlers they notify run.
The following play demonstrates a with pre_tasks,roles,tasks,post_ Examples of tasks and handlers. A play usually does not contain all of these parts at the same time.
[root@master ansible]# cat httpd.tar/main.yml --- - hosts: 192.168.72.137 vars: timesync_ntp_servers: - hostname: time1.aliyun.com iburst: yes pre_tasks: - debug: msg: 'pre-tasks' notify: my handler roles: - timesync tasks: - debug: msg: 'first task' notify: my handler post_tasks: - debug: msg: 'post-task' notify: my handler handlers: - name: my handler debug: msg: running my handler [root@master ansible]# [root@master ansible]# ansible-playbook httpd.tar/main.yml / / execution succeeds PLAY [192.168.72.137] ********************************************************* TASK [Gathering Facts] ********************************************************* ok: [192.168.72.137] TASK [debug] ******************************************************************* ok: [192.168.72.137] => { "msg": "pre-tasks" } TASK [timesync : Set version specific variables] ******************************* ok: [192.168.72.137] TASK [timesync : Populate service facts] *************************************** ok: [192.168.72.137] TASK [Set variable `timesync_services` with filtered uniq service names] ******* ok: [192.168.72.137] TASK [Check that variable 'timesync_services' is defined] ********************** ok: [192.168.72.137] => { "changed": false, "msg": "All assertions passed" } TASK [timesync : Check if only NTP is needed] ********************************** ok: [192.168.72.137] TASK [timesync : Check if single PTP is needed] ******************************** skipping: [192.168.72.137] TASK [timesync : Check if both NTP and PTP are needed] ************************* skipping: [192.168.72.137] TASK [timesync : Determine current NTP provider] ******************************* ok: [192.168.72.137] TASK [timesync : Select NTP provider] ****************************************** ok: [192.168.72.137] TASK [timesync : Install chrony] *********************************************** ok: [192.168.72.137] TASK [timesync : Install ntp] ************************************************** skipping: [192.168.72.137] TASK [timesync : Install linuxptp] ********************************************* skipping: [192.168.72.137] TASK [timesync : Gather package facts] ***************************************** ok: [192.168.72.137] TASK [timesync : Run phc_ctl on PTP interface] ********************************* skipping: [192.168.72.137] TASK [timesync : Check if PTP interface supports HW timestamping] ************** skipping: [192.168.72.137] TASK [timesync : Generate chrony.conf file] ************************************ ok: [192.168.72.137] TASK [timesync : Generate chronyd sysconfig file] ****************************** ok: [192.168.72.137] TASK [timesync : Generate ntp.conf file] *************************************** skipping: [192.168.72.137] TASK [timesync : Generate ntpd sysconfig file] ********************************* skipping: [192.168.72.137] TASK [timesync : Generate ptp4l.conf file] ************************************* skipping: [192.168.72.137] TASK [timesync : Generate ptp4l sysconfig file] ******************************** skipping: [192.168.72.137] TASK [timesync : Generate phc2sys sysconfig file] ****************************** skipping: [192.168.72.137] TASK [timesync : Generate timemaster.conf file] ******************************** skipping: [192.168.72.137] TASK [timesync : Update network sysconfig file] ******************************** ok: [192.168.72.137] TASK [timesync : Disable chronyd] ********************************************** skipping: [192.168.72.137] TASK [timesync : Disable ntpd] ************************************************* skipping: [192.168.72.137] TASK [timesync : Disable ntpdate] ********************************************** skipping: [192.168.72.137] TASK [timesync : Disable sntp] ************************************************* skipping: [192.168.72.137] TASK [timesync : Disable ptp4l] ************************************************ skipping: [192.168.72.137] TASK [timesync : Disable phc2sys] ********************************************** skipping: [192.168.72.137] TASK [timesync : Disable timemaster] ******************************************* skipping: [192.168.72.137] TASK [timesync : Enable chronyd] *********************************************** ok: [192.168.72.137] TASK [timesync : Enable ntpd] ************************************************** skipping: [192.168.72.137] TASK [timesync : Enable ptp4l] ************************************************* skipping: [192.168.72.137] TASK [timesync : Enable phc2sys] *********************************************** skipping: [192.168.72.137] TASK [timesync : Enable timemaster] ******************************************** skipping: [192.168.72.137] TASK [debug] ******************************************************************* ok: [192.168.72.137] => { "msg": "first task" } TASK [debug] ******************************************************************* ok: [192.168.72.137] => { "msg": "post-task" } PLAY RECAP ********************************************************************* 192.168.72.137 : ok=17 changed=0 unreachable=0 failed=0 skipped=23 rescued=0 ignored=0 [root@master ansible]#
In the above example, the debug task is executed in each section to notify the my handler handler. The my handler task was executed three times
- After executing all pre_ After tasks
- After performing all the role tasks and tasks in the tasks section
- After all posts are executed_ After tasks
In addition to including roles in the roles section of the play, you can also add roles to the play using normal tasks. Use include_ The role module can dynamically include roles, using import_role module can statically import roles.
The following playbook demonstrates how to use include_role module to use tasks to include roles.
[root@master ansible]# cat httpd.tar/main.yml --- - hosts: 192.168.72.137 vars: timesync_ntp_servers: - hostname: time1.aliyun.com iburst: yes power: true tasks: - name: debug: msg: 'first task' - name: timesync include_role: name: timesync handlers: - name: my handler debug: msg: running my handler [root@master ansible]# [root@master ansible]# ansible-playbook httpd.tar/main.yml PLAY [192.168.72.137] ********************************************************* TASK [Gathering Facts] ********************************************************* ok: [192.168.72.137] TASK [debug] ******************************************************************* ok: [192.168.72.137] => { "msg": "first task" } TASK [timesync] **************************************************************** TASK [timesync : Set version specific variables] ******************************* ok: [192.168.72.137] TASK [timesync : Populate service facts] *************************************** ok: [192.168.72.137] TASK [Set variable `timesync_services` with filtered uniq service names] ******* ok: [192.168.72.137] TASK [Check that variable 'timesync_services' is defined] ********************** ok: [192.168.72.137] => { "changed": false, "msg": "All assertions passed" } TASK [timesync : Check if only NTP is needed] ********************************** ok: [192.168.72.137] TASK [timesync : Check if single PTP is needed] ******************************** skipping: [192.168.72.137] TASK [timesync : Check if both NTP and PTP are needed] ************************* skipping: [192.168.72.137] TASK [timesync : Determine current NTP provider] ******************************* ok: [192.168.72.137] TASK [timesync : Select NTP provider] ****************************************** ok: [192.168.72.137] TASK [timesync : Install chrony] *********************************************** ok: [192.168.72.137] TASK [timesync : Install ntp] ************************************************** skipping: [192.168.72.137] TASK [timesync : Install linuxptp] ********************************************* skipping: [192.168.72.137] TASK [timesync : Gather package facts] ***************************************** ok: [192.168.72.137] TASK [timesync : Run phc_ctl on PTP interface] ********************************* skipping: [192.168.72.137] TASK [timesync : Check if PTP interface supports HW timestamping] ************** skipping: [192.168.72.137] TASK [timesync : Generate chrony.conf file] ************************************ ok: [192.168.100.147] TASK [timesync : Generate chronyd sysconfig file] ****************************** ok: [192.168.100.147] TASK [timesync : Generate ntp.conf file] *************************************** skipping: [192.168.72.137] TASK [timesync : Generate ntpd sysconfig file] ********************************* skipping: [192.168.72.137] TASK [timesync : Generate ptp4l.conf file] ************************************* skipping: [192.168.72.137] TASK [timesync : Generate ptp4l sysconfig file] ******************************** skipping: [192.168.72.137] TASK [timesync : Generate phc2sys sysconfig file] ****************************** skipping: [192.168.72.137] TASK [timesync : Generate timemaster.conf file] ******************************** skipping: [192.168.72.137] TASK [timesync : Update network sysconfig file] ******************************** ok: [192.168.72.137] TASK [timesync : Disable chronyd] ********************************************** skipping: [192.168.72.137] TASK [timesync : Disable ntpd] ************************************************* skipping: [192.168.72.137] TASK [timesync : Disable ntpdate] ********************************************** skipping: [192.168.72.137] TASK [timesync : Disable sntp] ************************************************* skipping: [192.168.72.137] TASK [timesync : Disable ptp4l] ************************************************ skipping: [192.168.72.137] TASK [timesync : Disable phc2sys] ********************************************** skipping: [192.168.72.137] TASK [timesync : Disable timemaster] ******************************************* skipping: [192.168.72.137] TASK [timesync : Enable chronyd] *********************************************** ok: [192.168.72.137] TASK [timesync : Enable ntpd] ************************************************** skipping: [192.168.72.137] TASK [timesync : Enable ptp4l] ************************************************* skipping: [192.168.72.137] TASK [timesync : Enable phc2sys] *********************************************** skipping: [192.168.72.137] TASK [timesync : Enable timemaster] ******************************************** skipping: [192.168.72.137] PLAY RECAP ********************************************************************* 192.168.72.137 : ok=15 changed=0 unreachable=0 failed=0 skipped=23 rescued=0 ignored=0 [root@master ansible]#
2.selinux role instance
rhel-system-roles.selinux role can simplify the management of SELinux configuration settings. It is implemented by using the Ansible module related to SELinux. The advantage of using this role over writing tasks yourself is that it frees users from the responsibility of writing these tasks. Instead, the user will provide variables to the role to configure it, and the code maintained in the role will ensure that the SELinux configuration required by the user is applied.
The tasks that this role can perform include:
- Set the enforcing or permissive mode
- Run restorecon on parts of the file system hierarchy
- Set SELinux Boolean
- Permanently set SELinux file context
- Set SELinux user mapping
Sometimes, the SELinux role must ensure that the managed host is rebooted so that its changes can be fully applied. However, it never reboots the host itself. In this way, the user can control how the reboot is handled.
It works by placing a boolean variable SELinux in the role_ reboot_ Required is set to true and fails if a reboot is required. You can use the block / resume structure to recover from failures. The specific operations are: if the variable is not set to true, let play fail; if the value is true, reboot the managed host and re run the role. The blocks in play should look like:
[root@master ansible]# cat httpd.tar/main.yml --- - hosts: 192.168.72.137 tasks: - name: Apply SELinux role block: - name: role user include_role: name: selinux rescue: - name: Check for failure for other reasons than required reboot fail: when: not selinux_reboot_required - name: Restart managed host reboot: - name: Reapply SELinux role to complete changes include_role: name: selinux [root@master ansible]# [root@localhost ~]# getenforce Disabled [root@localhost ~]#
3. Configure selinux role
Used to configure RHEL system roles The detailed record of the variables of the SELinux role is located in its readme MD file. The following example demonstrates some ways to use this role.
selinux_ The state variable sets the running mode of SELinux. It can be set to enforced, permitted, or disabled. If not set, the mode is not changed
[root@master ansible]# cat /etc/selinux/config # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=enforcing # SELINUXTYPE= can take one of these three values: # targeted - Targeted processes are protected, # minimum - Modification of targeted policy. Only selected processes are protected. # mls - Multi Level Security protection. SELINUXTYPE=targeted [root@master ansible]#
selinux_ The boolean variable takes a list of SELinux Boolean values to be adjusted as the value. Each item in the list is a hash / dictionary of variables: the name and state of the Boolean value (should it be on or off), and whether the setting should persist after reboot
[root@master ansible]# cat httpd.tar/httpd1.yml --- - hosts: 192.168.72.137 vars: PORT: 82 tasks: - name: install httpd yum: name: httpd state: present - name: config httpd template: src: /etc/ansible/files/httpd.conf.j2 dest: /etc/httpd/conf/httpd.conf - name: serivce httpd service: name: httpd state: started [root@master ansible]# [root@master ansible]# ansible-playbook httpd.tar/httpd1.yml PLAY [192.168.72.137] ********************************************************* TASK [Gathering Facts] ********************************************************* ok: [192.168.72.137] TASK [install httpd] *********************************************************** ok: [192.168.72.137] TASK [config httpd] ************************************************************ changed: [192.168.72.137] TASK [serivce httpd] *********************************************************** changed: [192.168.72.137] PLAY RECAP ********************************************************************* 192.168.72.137 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
selinux_ The ports variable takes the list of ports that should have a specific SELinux type as its value.
selinux_ports: - ports: '82' setype: 'http_port_t' proto: 'tcp' state: 'present'
4. Create roles
Role creation process
Creating roles in Ansible does not require special development tools. Creating and using roles involves three steps:
Create role directory structure
Define role content
Using roles in playbook
By default, Ansible finds roles in the roles subdirectory of the directory where Ansible Playbook is located. In this way, users can use playbook and other supporting files to store roles.
If Ansible cannot find roles in this location, it will set roles in Ansible configuration in order_ Path. This variable contains a colon delimited list of directories to search. The default value of this variable is:
[root@master ~]# ls /usr/share/ansible/roles/ linux-system-roles.certificate linux-system-roles.crypto_policies linux-system-roles.ha_cluster linux-system-roles.kdump linux-system-roles.kernel_settings linux-system-roles.logging linux-system-roles.metrics linux-system-roles.nbde_client linux-system-roles.nbde_server linux-system-roles.network linux-system-roles.postfix linux-system-roles.selinux linux-system-roles.ssh linux-system-roles.sshd linux-system-roles.storage linux-system-roles.timesync linux-system-roles.tlog linux-system-roles.vpn rhel-system-roles.certificate rhel-system-roles.crypto_policies rhel-system-roles.ha_cluster rhel-system-roles.kdump rhel-system-roles.kernel_settings rhel-system-roles.logging rhel-system-roles.metrics rhel-system-roles.nbde_client rhel-system-roles.nbde_server rhel-system-roles.network rhel-system-roles.postfix rhel-system-roles.selinux rhel-system-roles.ssh rhel-system-roles.sshd rhel-system-roles.storage rhel-system-roles.timesync rhel-system-roles.tlog rhel-system-roles.vpn [root@master ~]#
This allows users to install roles on systems shared by multiple projects. For example, users may install their roles in ~ /. In their home directory In the accessible / roles subdirectory, and the system may install the roles of all users in the / usr / share / accessible / roles directory.
Each role has its own directory and adopts a standardized directory structure. For example, the following directory structure contains the files that define the motd role.
[root@master ansible]# tree roles/ roles/ ├── php.tar │ ├── php-7.2.8.tar.xz │ ├── php.sh │ └── php.yml └── timesync ├── ansible_pytest_extra_requirements.txt ├── COPYING ├── custom_requirements.txt ├── defaults │ └── main.yml ├── handlers │ └── main.yml ├── library │ └── timesync_provider.sh ├── meta │ └── main.yml ├── molecule_extra_requirements.txt ├── pylint_extra_requirements.txt ├── pylintrc ├── pytest_extra_requirements.txt ├── README.html ├── README.md ├── tasks │ └── main.yml ├── templates │ ├── chrony.conf.j2 │ ├── chronyd.sysconfig.j2 │ ├── ntp.conf.j2 │ ├── ntpd.sysconfig.j2 │ ├── phc2sys.sysconfig.j2 │ ├── ptp4l.conf.j2 │ ├── ptp4l.sysconfig.j2 │ └── timemaster.conf.j2 ├── tests │ ├── inventory.yaml.j2 │ ├── provision.fmf │ ├── roles │ ├── tests_chrony.yml │ ├── tests_default_vars.yml │ ├── tests_default_wrapper.yml │ ├── tests_default.yml │ ├── tests_ntp_provider1.yml │ ├── tests_ntp_provider2.yml │ ├── tests_ntp_provider3.yml │ ├── tests_ntp_provider4.yml │ ├── tests_ntp_provider5.yml │ ├── tests_ntp_provider6.yml │ ├── tests_ntp_ptp.yml │ ├── tests_ntp.yml │ ├── tests_ptp_multi.yml │ └── tests_ptp_single.yml ├── tox.ini └── vars ├── CentOS_6.yml ├── CentOS_9.yml ├── default.yml ├── Fedora_33.yml ├── main.yml ├── RedHat_6.yml └── RedHat_9.yml 11 directories, 49 files [root@master ansible]#
5. Create role framework
You can use standard Linux commands to create all subdirectories and files required for a new role. In addition, you can automate the new role creation process through the command-line utility.
The Ansible Galaxy command line tool can be used to manage Ansible roles, including the creation of new roles. Users can run Ansible Galaxy init to create a directory structure for new roles. Specify the name of the role as an argument to the command, which creates a subdirectory for the new role in the current working directory.
[root@ansible opt]# cd roles/ [root@ansible roles]# ansible-galaxy init my_new_role - Role my_new_role was created successfully [root@ansible roles]# ls my_new_role/ defaults handlers README.md templates vars files meta tasks tests