Как известно, администраторы делятся на тех кто делает и не делает бекап. В свою очередь те кто делают, еще подразделяются на тех, кто их проверяет или нет. Сам факт наличия бекапов я делаю через простое отображение в Комплексном экране заббикса списка файлов в директории, т.е. просто
ls -oth /DATA/BACKUP/ldap/`date +%m.%Y`/ | grep -v ^total | head -n 6 | cut -d " " -f4-
Следующим шагом захотелось более-менее автоматически проверять бекапы mysql и ldap. Периодически для работы использую ансибл, поэтому решил на нем реализовать.
Предварительно, необходимо где-либо развернуть сервер для проверки бекапов (будем называеть его checkup-server). Сервер будет на дебиане.
- Для установки mysql достаточно просто apt-get install mysql-server
- Для установки ldap-сервера: apt-get install slapd. Сам рабочий лдап-сервер поднят на freebsd + плюс есть самописные схемы для собственных атрибутов, все конфиги находятся в /usr/local/etc/openldap. Для настройки лдап на checkup-server достаточно просто перенести содержимое этой папки в папку /etc/ldap. В случае необходимости подправить пути в /etc/ldap/slapd.conf.
Потом сделать systemctl start slapd. Если не стартует, то смотрим логи в /var/log/syslog и исправляем возникающие ошибки (например неправильные пути до схем, недостаточно прав на какую-либо директорию).
Считаем что mysql-server и ldap на checlup-server функционируют нормально. Также заранее настраиваем пользователя (прописываем ключи и даем права USER ALL = (root) NOPASSWD: ALL в /ect/sudoers), под которым ансибл будет пушить свои задачи.
Сами плэйбуки
1) mysql.yml
--- - hosts: backup name: copy dumps from backup.server tasks: - synchronize: src=/DATA/BACKUP/mysql/{{ ansible_date_time.month }}.{{ ansible_date_time.year }}/sql/DMZ/{{ item }}.{{ day }}.{{ ansible_date_time.month }}.{{ ansible_date_time.year }}.sql dest=/tmp mode=pull with_items: - db1 - db2 - db3 - hosts: checkup-server name: copy and restore mysql databases to checkup-server tasks: - copy: src=/tmp/{{ item }}.{{ day }}.{{ ansible_date_time.month }}.{{ ansible_date_time.year }}.sql dest=/home/ansible with_items: - db1 - db2 - db3 - mysql_db: name={{ item }}_test state=absent login_user=root login_password=PASS with_items: - db1 - db2 - db3 - mysql_db: name={{ item }}_test state=present login_user=root login_password=PASS with_items: - db1 - db2 - db3 - mysql_db: name={{ item }}_test state=import target=~ansible/{{ item }}.{{ day }}.{{ ansible_date_time.month }}.{{ ansible_date_time.year }}.sql login_user=root login_password=PASS with_items: - db1 - db2 - db3 - file: path=~ansible/{{ item }}.{{ day }}.{{ ansible_date_time.month }}.{{ ansible_date_time.year }}.sql state=absent with_items: - db1 - db2 - db3 - shell: /usr/bin/mysql -uroot -PASS -e "use db1_test; show tables" | wc -l register: s1 - debug: msg="ALARM - DB db1; has {{ s1.stdout }} tables" when: s1.stdout == "0" - shell: /usr/bin/mysql -uroot -PASS -e "use db2_test; show tables" | wc -l register: s2 - debug: msg="ALARM - DB db2 has {{ s2.stdout }} tables" when: s2.stdout == "0" - shell: /usr/bin/mysql -uroot -pPASS -e "use db3_test; show tables" | wc -l register: s3 - debug: msg="ALARM - DB db3 has {{ s3.stdout }} tables" when: s3.stdout == "0" - hosts: localhost name: rm dumps sql from /tmp on ansible tasks: - file: path=/tmp/{{ item }}.{{ day }}.{{ ansible_date_time.month }}.{{ ansible_date_time.year }}.sql state=absent with_items: - db1 - db2 - db3
Некоторые пометки:
- путь до бекапа выглядит как /DATA/BACKUP/mysql/02.2017/sql/DMZ/db1.01.02.2017.sql
- стандартный модуль fetch для скачивания файлов (более 1Гб) не подошел, т.к. выдавал в процессе скачивания большого файла MemoryError, поэтому в интернете советуют использовать модуль synchronize, который является оберткой над rsync
- проверкой нормального развернутого дампа является кол-во таблиц в бд, если 0, то выводим debug message (можно вместо этого например отправлять письмо). В словарях s1, s2, s3 сохраняется инфа по сработке команды /usr/bin/mysql -uroot ... Сам вывод команды сохраняется в переменной s1.stdout
- команде /usr/bin/mysql -uroot -pPASS передаем открыто пароль, т.к. нет смысла заморачиваться за безопасность - сервер mysql работает локально и ни у кого лишнего не должно быть доступа к checkup-server
2) ldap.yml
--- - hosts: backup name: copy ldif from backup.server tasks: - synchronize: src=/DATA/BACKUP/ldap/{{ ansible_date_time.month }}.{{ ansible_date_time.year }}/{{ day }}-{{ ansible_date_time.month }}-{{ ansible_date_time.year }}.ldif dest=/tmp mode=pull - hosts: checkup-server name: copy and restore ldap to checkup-server sudo: yes tasks: - copy: src=/tmp/{{ day }}-{{ ansible_date_time.month }}-{{ ansible_date_time.year }}.ldif dest=/home/ansible - shell: name=slapd state=stopped - shell: rm -rf /var/db/openldap-data/* - shell: /usr/sbin/slapadd -l /home/ansible/{{ day }}-{{ ansible_date_time.month }}-{{ ansible_date_time.year }}.ldif - file: path=/var/db/openldap-data recurse=yes owner=openldap group=openldap state=directory - service: name=slapd state=restarted - file: path=~ansible/{{ day }}-{{ ansible_date_time.month }}-{{ ansible_date_time.year }}.ldif state=absent - shell: /usr/bin/ldapsearch -h localhost -x -b "dc=test.com" '(uid=testuser)' | grep "^result" | awk '{ print $2 }' register: s - debug: msg="ALARM - LDAP db is empty" when: s.stdout != "0" - hosts: localhost name: rm ldif from /tmp on ansible tasks: - file: path=/tmp/{{ day }}-{{ ansible_date_time.month }}-{{ ansible_date_time.year }}.ldif state=absent
Некоторые пометки:
- путь до бекапа имеет вид /DATA/BACKUP/ldap/03.2017/01-03-2017.ldif
- проверкой бекапа является ldapsearch в определенной ветке. В случае, если например дамп будет пустой, соответственно ветка не будет существовать и ldapsearch вернет ответ "result: 32 No such object"
Сами плэйбуки запускаем так:
ansible-playbook mysql.yml -e "day=12" ansible-playbook ldap.yml -e "day=06"