Ansible практика – урок №8: Использование notify и handler.

Предыдущий урок: Ansible практика – урок №7: Копирование файлов на удаленный сервер.

В прошлом уроке мы добавили таск для перезапуска MariaDB, такой же таск есть для Firewalld. Проблема в том, что в таком виде, перезапуск сервиса осуществляется при любой раскатке, даже когда изменений в настройках сервиса не произошло.

Зачем нужен notify и handler?

notify – параметр, присваиваемый текущей задаче, указывающий на используемый handler.

handler – вспомогательная задача, которую Ansible исполнит, если текущая задача произвела изменения на управляемом хосте.

Использование notify и handler

Внесем изменения в роли, работающие с сервисами MariaDB и Firewalld соответственно.

Шаг 1: Создаем handler

Создадим новые директории, с названием handlers, в каждой из ролей:

[root@Control-Node ansible]# mkdir roles/mariadb/handlers roles/firewalld/handlers
[root@Control-Node ansible]#

Создадим файл roles/mariadb/handlers/main.yml с содержанием:

---
- name: restart_mariadb
  ansible.builtin.service:
    name: mariadb
    state: restarted

Тут имя хендлера restart_mariadb.

Второй файл roles/firewalld/handlers/main.yml:

---
- name: restart_firewalld
  ansible.builtin.service:
    name: firewalld
    state: restarted

Имя хендлера – restart_firewalld.

Хендлеры готовы.

Шаг 2: Присваиваем handler

Отредактируем роли, убрав из них таски по перезапуску сервисов, и укажем хендлеры.

После редактирования файл roles/mariadb/tasks/main.yml выглядит так:

---
- name: "Role: MariaDB | Block: Installation"
  tags:
    - installation
    - mariadb
  block:
    - name: "Install MariaDB on CentOS"
      ansible.builtin.dnf:
        name: mariadb-server
        state: latest
      when: ansible_distribution == "CentOS"

    - name: "Install MariaDB on Ubuntu"
      ansible.builtin.apt:
        name: mariadb-server
        state: latest
      when: ansible_distribution == "Ubuntu"

- name: "Ensure MariaDB is started and enabled"
  ansible.builtin.service:
    name: mariadb
    state: started
    enabled: true
  tags:
    - start
    - mariadb

- name: "Role: MariaDB | Block: custom config"
  notify: restart_mariadb
  tags:
    - mariadb
  block:
    - name: "Copy custom config file to CentOS"
      ansible.builtin.copy:
        src: logs.cnf
        dest: /etc/my.cnf.d/logs.cnf
        owner: root
        group: root
        mode: '0644'
      when: ansible_distribution == "CentOS"

    - name: "Copy custom config file to Ubuntu"
      ansible.builtin.copy:
        src: logs.cnf
        dest: /etc/mysql/mariadb.conf.d/logs.cnf
        owner: root
        group: root
        mode: '0644'
      when: ansible_distribution == "Ubuntu"

С помощью notify мы присвоили хендлер restart_mariadb блоку “Role: MariaDB | Block: custom config”.

Модифицированный файл roles/firewalld/tasks/main.yml:

---
- name: "Role: Firewalld | Block: Installation"
  tags:
    - installation
    - firewalld
  block:
    - name: "Install firewalld on CentOS"
      ansible.builtin.dnf:
        name: firewalld
        state: latest
      when: ansible_distribution == "CentOS"

    - name: "Install firewalld on Ubuntu"
      ansible.builtin.apt:
        name: firewalld
        state: latest
      when: ansible_distribution == "Ubuntu"

- name: "Ensure Firewalld is started and enabled"
  ansible.builtin.service:
    name: firewalld
    state: started
    enabled: yes
  tags:
    - start
    - firewalld

- name: "Role: Firewalld | Block: allow services"
  notify: restart_firewalld
  tags:
    - firewalld
  block:
    - name: "Open SSH service permanently in public zone"
      ansible.posix.firewalld:
        zone: public
        service: ssh
        permanent: true
        state: enabled

    - name: "Open HTTP service permanently in public zone"
      ansible.posix.firewalld:
        zone: public
        service: http
        permanent: true
        state: enabled

    - name: "Open HTTPS service permanently in public zone"
      ansible.posix.firewalld:
        zone: public
        service: https
        permanent: true
        state: enabled

Тут хендлер restart_firewalld добавлен блоку “Role: Firewalld | Block: allow services”.

Шаг 3: Проверяем плейбук

Запустим Ansible и посмотрим, как отработают хендлеры. Чтобы исключить роли и задачи, которые не претерпели изменений в данном уроке, используем комбинацию включенных и исключенных тегов:

[root@Control-Node ansible]# ansible-playbook install_lemp.yml --tags mariadb,firewalld --skip-tags installation

PLAY [all] ******************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************
ok: [Managed-Node-2]
ok: [Managed-Node-1]
ok: [Managed-Node-3]

TASK [mariadb : Ensure MariaDB is started and enabled] **********************************************************************************************************************************************
ok: [Managed-Node-1]
ok: [Managed-Node-3]
ok: [Managed-Node-2]

TASK [mariadb : Copy custom config file to CentOS] **************************************************************************************************************************************************
skipping: [Managed-Node-3]
ok: [Managed-Node-2]
ok: [Managed-Node-1]

TASK [mariadb : Copy custom config file to Ubuntu] **************************************************************************************************************************************************
skipping: [Managed-Node-1]
skipping: [Managed-Node-2]
ok: [Managed-Node-3]

TASK [firewalld : Ensure Firewalld is started and enabled] ******************************************************************************************************************************************
ok: [Managed-Node-1]
ok: [Managed-Node-2]
ok: [Managed-Node-3]

TASK [firewalld : Open SSH service permanently in public zone] **************************************************************************************************************************************
ok: [Managed-Node-3]
ok: [Managed-Node-1]
ok: [Managed-Node-2]

TASK [firewalld : Open HTTP service permanently in public zone] *************************************************************************************************************************************
ok: [Managed-Node-1]
ok: [Managed-Node-3]
ok: [Managed-Node-2]

TASK [firewalld : Open HTTPS service permanently in public zone] ************************************************************************************************************************************
ok: [Managed-Node-3]
ok: [Managed-Node-1]
ok: [Managed-Node-2]

PLAY RECAP ******************************************************************************************************************************************************************************************
Managed-Node-1             : ok=7    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
Managed-Node-2             : ok=7    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
Managed-Node-3             : ok=7    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

[root@Control-Node ansible]#

Ansible отработал без ошибок, но мы нигде не видим работу хэндлеров. Это потому, что задачи, к которым прикреплены хендлеры, не внесли никаких изменений, а значит и причин вызывать хендлер тоже нет.

Давайте подкинем Ansible работенку, зайдем на какую-нибудь Managed Node и и выведем систему из соответствия плейбуку.

Удалим файл /etc/my.cnf.d/logs.cnf:

[root@Managed-Node-1 ~]# rm -f /etc/my.cnf.d/logs.cnf
[root@Managed-Node-1 ~]#

И уберем http из разрешенных сервисов Firewalld:

[root@Managed-Node-1 ~]# firewall-cmd --zone=public --remove-service=http --permanent
success
[root@Managed-Node-1 ~]# 

Теперь Ansible будет чем заняться. Повторим раскатку, только ограничимся хостом, на котором мы делали изменения:

[root@Control-Node ansible]# ansible-playbook install_lemp.yml --tags mariadb,firewalld --skip-tags installation --limit Managed-Node-1

PLAY [all] ******************************************************************************************************************************************************************************************

TASK [Gathering Facts] ******************************************************************************************************************************************************************************
ok: [Managed-Node-1]

TASK [mariadb : Ensure MariaDB is started and enabled] **********************************************************************************************************************************************
ok: [Managed-Node-1]

TASK [mariadb : Copy custom config file to CentOS] **************************************************************************************************************************************************
changed: [Managed-Node-1]

TASK [mariadb : Copy custom config file to Ubuntu] **************************************************************************************************************************************************
skipping: [Managed-Node-1]

TASK [firewalld : Ensure Firewalld is started and enabled] ******************************************************************************************************************************************
ok: [Managed-Node-1]

TASK [firewalld : Open SSH service permanently in public zone] **************************************************************************************************************************************
ok: [Managed-Node-1]

TASK [firewalld : Open HTTP service permanently in public zone] *************************************************************************************************************************************
changed: [Managed-Node-1]

TASK [firewalld : Open HTTPS service permanently in public zone] ************************************************************************************************************************************
ok: [Managed-Node-1]

RUNNING HANDLER [mariadb : restart_mariadb] *********************************************************************************************************************************************************
changed: [Managed-Node-1]

RUNNING HANDLER [firewalld : restart_firewalld] *****************************************************************************************************************************************************
changed: [Managed-Node-1]

PLAY RECAP ******************************************************************************************************************************************************************************************
Managed-Node-1             : ok=9    changed=4    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

[root@Control-Node ansible]#

На этот раз задачи [mariadb : Copy custom config file to CentOS] и [firewalld : Open HTTP service permanently in public zone] закончились с результатом changed. Что вызвало срабатывание хендлеров (RUNNING HANDLER).

Ansible запускает хендлеры в конце, после того как все таски исполнены. И если несколько задач вызывают один и тот же хендлер, он будет исполнен один раз, исключая избыточные вызовы.

Итоги:

Мы рассмотрели, как в Ansible работают хендлеры. Связка notify – handler отлично позволяет контролировать состояние сервисов и реагировать на внесенные изменения.

Следующий урок: Ansible практика – урок №9: Как использовать переменные в playbook.