вторник, 2 июля 2019 г.

Bacula. Скрипт для поиска и удаления из системы неиспользуемых томов

Столкнулся с интересной проблемой:

Стоит сервер с системой резервного копирования Bacula. Все настроено, все отлично работает. Но вот недавно обнаружилась нехватка дискового пространства, хотя по всем расчетам места было достаточно. В итоге анализа выяснилось следующее:
Для большинства серверов настроена схема резервирования 1/m Full, 1/w Diff, 1/d Increment (раз в месяц Полный, раз в неделю дифференциальный, в остальные дни инкрементный). Полные и дифференциальные бэкапы хранятся год, а инкрементные неделю-месяц, в зависимости от сервера. Кроме того выставлена опция делать полный бэкап при изменении конфига - в ней собака и зарыта. По определению дифф. или инкремент. бэкапы меньше полного и когда Вы меняете конфиг для сервера, то полный бэкап создается в пуле для типа бэкапа по планировщику (например сегодня задача инкрементного бэкапа, а в пуле для daily выполнился Full). Еще такой эффект будет наблюдаться в случае уменьшение файлсета или в любом другом случае, когда естественная ротация бэкапов приводит к уменьшению объема хранимой в пуле информации. В случае использования каких то продвинутых систем хранения в Bacula есть механизм переноса томов из пула в пул, но в моем случае неиспользуемые тома необходимо просто выявить и удалить.
Вот так ситуация выглядит в Bacula Admin Tool

Смотрим задачи для тома (List Jobs on Volume)
Резульнат:
Как видим том не используется, а место занимает, мне проще такие тома удалить, а задачи, которым нужны новые просто их создадут себе.
Скрипт предполагает наличие определенного соглашения об именах, а именно:
  1. Имя клиента - "полное DNS имя"-fd
  2. Название пулов - "короткое DNS имя"-daily/weekly/monthly
  3. FileSet - короткое имя
  4. Job Name - короткое имя
  5. Storage Name - короткое имя
  6. Label Format - "короткое имя"-daily/weekly/monthly-date

Собственно скрипт(Python):


#!/usr/bin/env python2.7
# -*- coding: utf8 -*-
import subprocess,os,sys
clients=[]
for i in subprocess.check_output("echo 'list clients' | bconsole | grep fd | cut -d '|' -f3 | cut -d '.' -f1",shell=True).split('\n'):
    if (i !=''):
        clients.append(i.strip())

listMedia=[]
for i in subprocess.check_output("echo 'list media' | bconsole | grep -E \"(Used | Append | Full)\"  | cut -d '|' -f3",shell=True).split('\n'):
    if i !='':
        listMedia.append(i.strip())

listJobMedia=[]
for n in clients:
    for i in subprocess.check_output(["echo 'list jobmedia' | bconsole |grep "+n+" | cut -d '|' -f3"],shell=True).split('\n'):
        if (i !='') :
            listJobMedia.append(i.strip())

f = open('delVol.txt', 'a')
for i in listMedia:
    if i not in listJobMedia:
        f.write(i+'\n')
        cm=['purge', 'delete']
        for k in cm:
            comd="echo '"+k+" volume="+i+" yes' | bconsole"
            subprocess.call(comd, shell=True)
f.close

Что делает?

С помощью парсинга вывода bconsole, получаем:
  1. Список clients - список клиентских серверов(вспомогательный для парсинга listJobMedia)
  2. Список listMedia - список всех томов системы
  3. Список listJobMedia - список томов, используемыз для хранения данных заданий.
Далее в цикле проверяем есть ли том из listMedia в listJobMedia, если нет - заносим его в файл-список delVol.txt и выролняем для него purge и delete.

В итоге:

Мы удалили пустые тома из bacula и получили список для физического удаления файлов, так  как тома для каждого клиента хранятся в разных местах процес удаления физики в скрипте не реализован чтоб не усложнять - при желании можно скрипт доработать, но это уже без меня.

P.S.

Следует иметь ввиду, что скрипт написан с учетом используемой мной системы в именовании fd и томов хранилища, что позволило парсить вывод bconsole именно таким образом.

Комментариев нет:

Отправить комментарий