Linux backup time machine на базе Python + Rsync + Mysql

в корпоративном чате:
xxx: я очень наделся, что в этом проекте не скажу этих слов, но обстоятельства заставляют.
xxx: господа.
xxx: а бэкапы кто-то делал?

Очередной велосипед для резервного копирования для систем на базе Linux, был собран из Python-а и Rsync-а, когда существующие решения оказались либо слишком сложными, либо не обладающими достаточным функционалом.
Особенности и плюсы Linux Time Machine:

  • Работа по принципу TimeMachine из MacOs, а именно — создание инкрементальных копий в отдельных папках с возможностью быстро восстановить или как-то ещё использовать файлы за произвольную дату
  • Инкрементальные копии, основанные на Hard-Link’ах, то есть в каждой папке находится «как-бы» полная копия, однако не изменившиеся файлы являются Hard-link’ами на свои предыдущие версии в папках за старые даты
  • Лёгкое прореживание инкрементальных копий, так как Hard-link’и позволят не терять сами файлы при удалении одной из их версий
  • Моментальный доступ к файлам за счёт того что они хранятся в чистом виде (в отличии от rdiff-backup и других)
  • Встроенный функционал для создания инкрементальных SQL-дампов баз данных MySql (чтобы можно было бэкапить также и mysql-таблицы в виде файлов)
  • Автоматическое возобновление резервного копирования с того места, на котором оно остановилось, если было прервано
  • Резервное копирование может быть запущено с сервера, на котором хранятся исходные данные, с сервера, на котором находятся резервные копии, а также с любого другого сервера, имеющего доступ к двум предыдущим по ssh (Прямо сейчас эта функция сломана, копировать можно либо с локального сервера, либо на локальный (на котором запускается скрипт) 🙁 )
  • Можно ограничивать частоту резервного копирования (копировать не чаще определённого), и, таким образом, оставить информацию о частоте копирования в конфигурации, не вынося её в crontab.
  • С помощью API систему можно легко и быстро расширить, например, добавить копирование на несколько серверов-хранилищ
  • Копирование как всей файловой системы так и произвольных папок
  • Возможность исключения папок, файлов и масок файлов (например *.log)
  • Возможность автоматической очистки старых копий по гибким правилам
  • Можно настроить отправку уведомлений об ошибках в систему getSentry(веб-интерфейс собирающий и отображающий информацию по ошибкам)

Есть и минусы:

  • Данные хранятся в чистом виде, без сжатия, поэтому могут занимать в несколько раз больше оригинала (в несколько — потому что копий несколько)
  • Для копирования на каждом из «концов» должен быть установлен Rsync
  • Без доступа по ssh резервное копирование работать не будет
  • Доступ по ssh работает только по ключу
  • При вычисления занятого резервными копиями места, один и тот же файл за счёт жестких ссылок учитывается по нескольку раз, так что занятое место может вычисляться неверно (однако, консольная команда du вычисляет занятое место верно)

Данный велосипед основан на идеях, изложенных в статье: http://habrahabr.ru/post/149059/

Принцип работы:

  • При запуске считывается конфигурация о так называемых «вариантах» резервного копирования. Каждый «вариант» описывается то, что нужно копировать, откуда и куда, а также опции этого копирования.
  • Поочередно запускается резервное копирование каждого из «вариантов»
    • Если требуется, запускается mysqldump, складывающий указанные базы и таблицы в виде sql-файлов в указанное место. При этом, если какие-то файлы там уже есть, они проверяются на обновления, и если таковых нет — дамп не делается
    • В папке назначения создаётся папка вида «in-progress-2015-05-11_10:30:43» (либо используется последняя существующая с подобным именем)
    • С помощью rsync в эту папку копируется содержимое удалённой резервируемой папки, но не всё, а только то, чего ещё нет в папке Latest (если она существует), то что уже есть — связывается hardlink’ами, в результате мы имеем полную копию файловой системы
    • По окончанию копирования, из имени папки удаляется префикс «in-progress-» и на неё создаётся симлинк Latest, который является указателем на «последнюю копию» и как раз используется rsync-ом при копировании
    • Если надо, дампы mysql удаляются с резервируемой машины

Установка:

Пока установка работает только из github, так как проект постоянно находится в состоянии доработки, и выкладывать его в PyPi пока считаю преждевременным.
Итак:

1. Склонировать репозиторий:

$ git clone https://github.com/MihanEntalpo/LinuxTimeMachine.git

2. Установить rsync:

# apt-get install rsync

3. Установить Python, пакетный менеджер pip и питоньи пакеты, необходимые для работы скрипта:

# apt-get install python3 python3-pip
# pip3 install pexpect pyyaml click

4. Установить rsync на всех машинах, откуда нужно делать резервные копии, а также, куда их нужно сохранять.

Настройка

Простейший файл конфигурации выглядит так:

# наличие этой переменной ожидается от конфиг-файла написанного на python
variants = {
    # название "варианта" резервного копирования
    "user_dir": {
        # Откуда копируем (путь и ssh-хост)
        'src': {'path':'/home/user, 'host':''},
        # Куда копируем (Путь и ssh-хост)
        'dest': {'path':'/home/backuper/user_backup', 'host':'backuper@myserver.local'}
    }
}

Конфигурация скрипта резервного копирования представляет собой файл в форматах JSON, YAML либо на языке Python. Этот файл должен содержать в себе набор «вариантов» резервного копирования.
Каждый из вариантов определяет, откуда нужно делать резервную копию, куда её сохранять, какие файлы исключить из копирования, нужно ли перед началом резервной копии делать дамп базы данных Mysql, и, если нужно, то какие таблицы и базы нужно сохранять, а какие — нет, и так далее…

Соответственно, файлы должны иметь расширения *.py, *.json, *.yaml, *.yml, чтобы система могла определить, какого типа данный файл.

Приведу здесь примеры файлов конфигурации в формате Python config.py, так как в нём (в отличии от json и yaml) можно писать комментарии, которые достаточно подробно всё объясняют. Файлы json и yaml должны иметь аналогичный формат.

Подробный вариант конфиг-файла, где расписаны все возможные опции

variants = {
    # Это будет резервная копия домашней папки пользователя
    "laptop_home_user" : {
        # откуда копировать
        "src": {
            "path": "/home/user",  # Исходная папка
            "host": "user@laptop"  # Хост SSH, в формате user@host, используется для работы с SSH
        },
        # куда копировать (аналогично "откуда")
        "dest":{      
            "path": "/home/backuper/backup/machines/my_laptop/user", 
            "host": ""
        },
        # Исключения
        "exclude":[   
            # исключение файлов по маске
            "*.bak", "*~", "*.log", "*.pyc",    
            # исключение конкретных папок
            "user/Downloads", "user/Torrents",  
            # исключение файлов по маске в папках 
            "user/.*errors",                    
            # исключение конкретного файла
            "user/mysqldump_big"                
        ],
        # Настройка создания дампов базы данных
        "mysqldump": { 
            # Пользователь и пароль базы данных
            "user": "mysqluser", "password", "mysqlpassword",  
            # SSH-хост на котором находится mysql-сервер
            "host": "user@laptop",  
            # Фильтр баз данных и таблиц (которые надо дампить), правила применяются последовательно.
            "dbs_filter": [
                # Добавим все базы и все таблицы
                ["include", "*", "*"],   
                # Исключим все базы, заканчивающиеся на _recovery (регулярное выражение!)
                ["exclude", ".*_recovery", ""],  
                # Исключим все таблицы с названием "logs", или кончающийся на "_logs" из всех баз
                ["exclude", "*", ["logs", ".*_logs"]], 
                # Теперь добавим таблицу "logs" для базы "mydb"
                ["include", "mydb", "logs"], 
                # Исключим большую таблицу (её будем дампить отдельным конфигом)
                ["exclude", "sentry", "sentry_message"]
            ],
            # Папка на удалённом хосте (там же где mysql-сервре)
            # Эта папка должно быть внутри папки ['src']['path']
            # для того, чтобы дампы были скопированы (дампы делаются до начала бэкапов файлов)
            "folder": "/home/user/mysqldump",
            # Делать дамп даже тех таблиц, дампы которых ещё не устарели
            # (перед дампом проводится проверка, не устарели ли таблицы)
            "force_dump": False  
        },
        # Минимальный промежуток между бэкапами 1.5 часа
        "min_timedelta": "1 hours 30 minutes",
        # Настройка очистки старых резервных копий
        "sweep": {
            # В течении последних суток храним все копии
            "last day": "all",
            # В течении последней недели храним не более 2 копий в сутки
            "last week": "2 per day",
            # В течении последнего месяца храним не более 1 копии в сутки
            "last month": "1 per day",
            # В течении последних 3-х месяцев храним не более 1 копии на каждые 2-е суток
            "last 3 months": "1 per 2 days",
            # В течении последних 6 месяцев храним не более 1 копии в неделю
            "last 6 months": "1 per week",
            # В течении последнего года храним не более 1 копии в месяц
            "last year":"1 per month"
        } 
    },
    # Это бэкап по сути одной большой таблицы, которую мы исключили в прошлом бэкапе:
    "laptop_sentry_message": {
        # откуда копировать
        "src": {      
            "path": "/home/user",  # Исходная папка
            "host": "user@laptop"  # Хост SSH, в формате user@host, используется для работы с SSH
        },
        # куда копировать (аналогично "откуда")
        "dest":{      
            "path": "/home/backuper/backup/machines/my_laptop/user", 
            "host": ""
        },
        # Исключения
        "exclude":[   
             # Сейчас тут пусто
        ],
        # Настройка создания дампов базы данных
        "mysqldump": { 
            # Пользователь и пароль базы данных
            "user": "mysqluser", "password", "mysqlpassword",  
            # SSH-хост на котором находится mysql-сервер
            "host": "user@laptop",  
            # Фильтр баз данных и таблиц (которые надо дампить), правила применяются последовательно.
            "filters": [
                # Добавим большую таблицу
                ["exclude", "sentry", "sentry_message"]
            ],
            # Папка на удалённом хосте (там же где mysql-сервре)
            "folder": "/home/user/mysqldump_big",
            # Удалить дамп после создания резервной копии 
            # (если таблица большая, то это поможет чтобы не занимать лишнее место)
            "remove_after_backup": True
        },
        # Минимальный промежуток между бэкапами 2 дня и 12 часов (т.е. 2.5 суток)
        "min_timedelta": {"days":2, "hours":12},
        # Настройка очистки старых резервных копий
        "sweep": {
            # В течении последних суток храним все копии
            "last day": "all",
            # В течении последнего месяца храним не более 1 копии в сутки
            "last month": "1 per day",
            # В течении последнего года храним не более 1 копии в месяц
            "last year":"1 per month",
            # В течении последних 10 лет храним по 2 копии в год
            "last 10 years": "2 per year"
        }
    }
}

По умолчанию файлы конфигурации ищутся в папке ~/.config/LinuxTimeMachine/variants, но при запуске можно указать другое расположение папки с этими файлами, или даже отдельные конкретные файлы.

Файл «основной конфигурации»

Для настроек глобальных параметров, применимых для всех «вариантов» резервного копирования, используется так называемый файл «основной конфигурации», который можно указать параметром —mainconf, обычно же он ищется по адресу ~/.config/LinuxTimeMachine/mainconf.json
Также, конфигурационный файл может быть в формате *.yaml или *.py, в последнем случае, в корневой области видимости скрипта должна быть переменная conf, содержащая dict с настройками (или что-то схожее).

Пример файла:

conf = {
    # Адрес DSN для подключения к getSentry (если надо)
    "raven_dsn":"https://457bd9f35ecc0a79adb542f90:461fffffffbac2565faa2269a1b5e@sentry.mihanentalpo.me/17",
    # Настройка очистки по умолчанию (для тех вариантов, где она не настроена)
    "defaults":{
        "sweep": {
            # В течении последних суток храним все копии
            "last day": "all",
            # В течении последней недели храним не более 2 копий в сутки
            "last week": "2 per day",
            # В течении последнего месяца храним не более 1 копии в сутки
            "last month": "1 per day",
            # В течении последних 3-х месяцев храним не более 1 копии на каждые 2-е суток
            "last 3 months": "1 per 2 days",
            # В течении последних 6 месяцев храним не более 1 копии в неделю
            "last 6 months": "1 per week",
            # В течении последнего года храним не более 1 копии в месяц
            "last year":"1 per month"
            # Для всех остальных не более 2 копий в год
            "all other":"2 per year"
        }
    }
}

Запуск

Для запуска достаточно выполнить скрипт go.py, указав ему команду backup, он прочитает варианты из файлов конфигурации, и пройдётся по ним, делая резервные копии этих вариантов.
Для удобства создан скрипт ltm который запускает go.py, и, при этом может работать через символическую ссылку. То есть вы можете создать симлинк в папку bin и пользоваться командой ltm из любой точки файловой системы:

# ln -s /home/user/LinuxTimeMachine/ltm /usr/bin/ltm

Примеры:

Запустить все варианты из конфигурационных файлов, расположенных в ~/.config/LinuxTimeMachine/variants

$ ltm backup

Запустить все варианты из 3-х конфигурационных файлов, указанных в командной строке:

$ ltm backup --conf ./mainconf.py --conf ./additionalconf.yaml --conf ./mylocalpc.json

Запустить варианты с названиями «home_user» и «var_www» из файлов с настройками, лежащими в папке /etc/ltmbackup/

$ ltm backup --conf_dir /etc/ltmbackup --run home_user --run var_www

При загрузке нескольких конфигурационных файлов, варианты, которые они определяют будут объединены в один список, при этом, если будут попадаться варианты с одинаковыми названиями, оставляться будет тот, что прочитан последним. При указании папки с конфиг-файлами, они читаются оттуда в алфавитном порядке. При указании отдельных файлов с помощью опции —conf, они будут читаться в той последовательности, в которой указаны.

Очистка старых резервных копий

Для очистки старых резервных копий используется команда sweep, параметры у неё примерно такие же как у backup, за исключением того, что есть параметр —imitate, который заставляет команду sweep имитировать деятельность, то есть не удалять старые резервные копии, а просто сообщить, какие из них подлежать удалению, а какие — нет.
Очистка будет проведена только если у она настроена в варианте через параметр «sweep».

Примеры:

Провести очистку для всех вариантов, для каких она сконфигурирована (варианты считываются из конфиг-файлов в папке ~/.config/LinuxTimeMachine/variants):

ltm sweep

Провести имитацию очистки с подробной информацией о действиях для всех вариантов, найденных в папке /etc/ltmbackup

ltm sweep --conf_dir /etc/ltmbackup --imitate --verbose

Конфигурация очистки:

Как уже указывалось ранее, очистка настраивается в поле «sweep» массива.

Пример:

{
    ...
    'sweep': {
        "last day": "all",
        "last week": "2 per day",
        "last month": "1 per day",
        "last 3 months": "1 per 2 days",
        "last 6 months": "1 per week",
        "last year":"1 per month"
    }
    ...
}

Каждый ключ массива указывает период времени начиная от последней резервной копии. Формат его: «last day|week|month|year», где слово «last» — обязательно, означает «последние столько-то времени». Вместо надо вставить число, сколько дней, месяцев или недель вы хотите задать. Если не указывать число, оно будет принято равным 1. Кстати, число может быть и дробным. Например, допустима конструкция «last 1.5 months». После числа (либо вместо него) нужно указать «единицу измерения», дни — «day», недели — «week», месяцы — «month», годы — «year». К «единице измерения» можно дописать букву «s» для множественного числа, то есть «days», «weeks», «months», «years». Это ни на что не влияет, но позволяет формировать более благозвучные периоды, к примеру, «last 2 days» — звучит логичнее чем «last 2 day». Несмотря на то, что «единицы измерения» меньше чем «day» нет, задавая дробным числом, можно добиться любой длительности интервала, скажем, «last 0.041667 days» будет означать «последний час».

Примеры:
«last 1 day» — последние сутки (здесь 1 указано явно)
«last 1.5 months» — последние 1.5 месяца»
«last 2 weeks» — последние 2 недели»
«last year» — последний год (здесь 1 не указано, но подразумевается)
«last 0.00069444 days»- последняя минута 🙂

Все периоды при чтении сортируются по возрастанию длительности, так что не важно, в какой последовательности они указаны.

Каждое значение массива — это указание того, сколько копий в единицу времени может существовать в заданный ранее период. Формат: « per day|week|month|year», где -количество копий (число), «per» — обязательное слово, означающее «каждые столько-то времени», — количество дней, недель, месяцев или лет, за которые позволено иметь не более копий. Вместо можно ничего не писать, тогда это число будет принято равным 1. В конце указывается «единица измерения», аналогично тому, как это делается в периоде (ключе массива), то есть day,week,month,year, окончание «s» также доступно для использования.

Также, есть специальное значение «all» — означающее, что сохранить нужно все резервные копии, очистка в данный период не нужна.

Особенности работы LinuxTimeMachine

Ограничение минимального промежутка

В параметре «min_timedelta» можно задать минимальный промежуток, чаще которого бэкапы не будут делаться (при запуске такой вариант, если он был сделан ближе к последней копией, чем min_timedelta, будет проигнорирован).

Эта возможность полезна чтобы не выносить информацию о частоте резервных копий в другое место (например в crontab). Допустим, у вас есть 2 папки, одну из которых вы хотите копировать раз в день, а другую — раз в час. Вы можете создать 2 задания в crontab, где одно будет выполнять резервное копирование только первой папки, а другое — только второй, указав им соответствующее время.
А с помощью опции «min_timedelta» можно задать интервалы «1 hours» и «1 days» соответственно у каждой из папок, а в crontab добавить только одно задание, запускающееся раз в час — тогда его хватит для обоих папок.

Формат параметра может быть таким:
1. Объект datetime.timedelta
2. Объект dict, содержащий поля с именами weeks, days, hours, minutes, seconds, milliseconds, microseconds, и значениями, равными количествам соответствующих интервалов. Этот объект используется при конструировании datetime.timedelta.
3. Строка:
«min_timedelta»: «1 weeks 5 days 11 hours 43 minutes 55 seconds 650 milliseconds 7901 microseconds», все параметры суммируются. Любые из них можно пропускать, а числа могут быть любыми целыми числами. Например, можно задать интервал только через секунды: «86400 seconds» (это как раз 1 сутки). Разделителями между словами могут быть пробелы и запятые.

Работа по SSH

1) Все действия, которые нужно осуществлять на удалённых серверах, выполняются с помощью консольных команд через ssh. Например, для переименования папки на удалённой машине, программой выполняется консольная команда типа такой:

ssh user@host mv '/var/backup/in-progress-2016-07-11_10:20:30' '/var/backup/2016-07-11_10:20:20'

если же действие выполняется на локальном (по отношению к скрипту резервного копирования) сервере, выполняется та же самая команда но без вызова ssh.

2) Для подключения по ssh требуется имя хоста, которое во многих командах системы именуется sshhost, и всюду просто в сыром виде подставляется в команду ssh. Таким образом, в этот параметр можно указать просто «host.com», «user@host.com», а также добавить дополнительные параметры подключения, например, порт или путь к файлу закрытого ключа:
sshhost = «user@server.ru —port=22000 -i ./keys/server.ru/admin.rsa», параметры, разумеется, должны быть валидными. При первом же доступе к серверу по ssh, будет проведена проверка на работоспособность параметров.

3) Подключение по SSH с указанием пароля пока не поддерживается.

4) При выполнении резервных копий между двумя удалёнными хостами, rsync запускается не на управляющем хосте, а на том, на который проводится сохранение данных. При этом вам достаточно иметь доступ по SSH с вашего управляющего хоста на исходный и конечный хосты. Прямого доступа по SSH между ними не требуется. Для подключения с хоста dest на хост src, между ними автоматически пробрасывается тоннель, проходящий через управляющих хост, через который и производится доступ из dest в src, который требуется rsync’у.
Для того, чтобы эта схема работала, и можно было подключиться из хоста dest к хосту src используя ключ, расположенный на управляющем хосте, этот ключ должен быть добавлен в агент авторизации ssh.
Делается это так (нужно указывать закрытый ключ):

ssh-add ~/.ssh/id_rsa

(Прямо сейчас функция копирования с одного удалённого хоста на другой, к сожалению, сломана)

Дампы Mysql

1) Дампы делаются при помощи mysqldump на тот же сервер, с которого осуществляется подключение к mysql, собственно резервные копии делаются как и для обычных файлов.

2) Список баз данных и таблиц, а также даты их изменения считываются с сервера с помощью консольного mysql-клиента.

3) В каждый sql-файл с дампом помещается специальная метка с информацией о последнем обновлении данной таблицы. Также, перед началом дампов запрашивается информация об обновлении таблиц.
Соответственно, заново делается дамп только тех таблиц, которые изменились с прошлого раза.
Опцией force_dump (приведена выше в примере конфига) можно заставить делать полные дампы всегда, независимо от изменений.

3.1) Для того, чтобы за одну консольную команду выяснить, какие таблицы нуждаются в обновлении, используется bash-скрипт, который автоматически создаётся на удалённом хосте опять же посредством SSH-команды, после чего запускается и собирает информацию в папке с дампами, а затем удаляется. Содержимое этого bash-файла можно посмотреть в исходном коде.

4) Дамп mysql-базы делается ДО копирования файлов, и подразумевается, что дамп вы будете делать в папку, которая включена в путь копируемых файлов (поскольку дампы sql копируются также как и все обычные файлы).

API для использование в своих скриптах

Вы можете написать свой скрипт резервного копирования с более сложной логикой, для этого достаточно подключить к вашему скрипту файл backup.py, и использовать объекты, находящиеся в нём.

Примеры того, что можно сделать

Допустим это будет файл mybackup.py, лежащий рядом с файлом backup.py:

Работа с консолью и Mysql:

# Подключаем модуль backup:
import backup
# Подключим модуль datetime (пригодится пару раз)
import datetime
 
# Можно проверить, есть ли беспарольный доступ к ssh определённого сервера:
# если нет - будет брошено исключение
# Обычно эта проверка делается автоматически, если выполняется некий запрос SSH.
backup.Console.check_ssh_or_throw("myuser@myhost.com")
 
# Выполнить команду mv на удалённом хосте: (а можно и на локальном)
backup.Console.mv("/tmp/1.txt", "/tmp/2.txt", "user@server.ru")
 
# Выполнить команду rm на удалённом (или локальном) хосте
backup.Console.rm("/tmp/1.txt", "user@server.ru")
 
# Получить имя папки для резервной копии из объекта datetime
# обычно имеет формат 2016-05-11_23:11:05
dirname = backup.Console.get_dirname_by_datetime(datetime.datetime.now())
 
# Получить дату и время по имени папки, которое должно быть
# в том же формате, что выдаёт функция get_dirname_by_datetime
date = backup.Console.get_datetime_by_dirname("2016-11-03_10:45:17")
 
# Получить список уже существующих папок с резервными копиями
# (возвращает list содержащий строки вида "2016-07-04_10:30:00",
# рассортированные по убыванию даты)
backupdirs = backup.console.get_backup_dirs(
    "/home/backuper/webites/mysite.com", 
    "user@backuper.local"
)
 
# Создаём объект для работы с локальной или удалённой базой данных:
# (Все запросы делаются с помощью консольных команд, никаких драйверов Mysql 
# не нужно)
mysql = backup.Mysql("username", "password", "sshuser@sshhost")
# Можно получить список баз данных и таблиц в них из базы mysql:
dbs = mysql.get_dbs_and_tbls()
# Функция возвращает dict, ключи в котором - имена баз данных, а значения 
# - list'ы с именами таблиц
 
# Можно отфильтровать список баз данных и таблиц, с которыми мы 
# хотим работать:
# (В качестве первого параметра передаётся dict, аналогичный тому, 
# что возвращает get_dbs_and_tbls)
filtered_dbs = mysql.filter_dbs_and_tbls(dbs, 
    [
        # включить в список все базы данных и все таблицы в них
        ["include", "*", "*"], 
        # исключить все базы данных, начинающихся с recovery_
        ["exclude", re.compile("^recovery_"), "*"] 
        # исключить из списка таблицы, заканчивающиеся на "_log"
        ["exclude", "*", re.compile("_log$")], 
        # включить таблицу userfull_data из базы recovery_common_db
        ["include", "recovery_common_db", "usefull_data"], 
    ]
)
 
# Можно просто выполнить произвольный sql-запрос 
# (ответ будет возвращён в виде строки, которую выдал консольный клиент mysql)
data = mysql.query("USE information_schema; SELECT * FROM `TABLES`")
 
# Можно запустить mysqldump с параметрами, указанными вручную 
# (довольно-таки не удобно):
# (Последний параметр передаётся в опции mysqldump без изменений)
mysql.call_dump(" databasename tablename ")
 
# Можно запустить само резервное копирование указанных баз данных 
mysql.dump_dbs(dbs, "/tmp/sql_dump_folder")
 
# Можно выяснить дату последнего изменения некоторой таблицы:
mytable_change_date = mysql.get_table_change_date("mytable")
 
# Можно получить данные о дате изменения таблицы:
# (Делается один запрос, после чего данные по всем таблицам и базам данных кэшируются)
table_update_date = mysql.get_table_change_date("databasename", "tablename")
 
# Можно получить данные о датах изменения таблиц, записанные в уже существующих дампах
# (используется для того, чтобы выяснить, изменилась ли таблица с момента последнего дампа)
mysql.get_table_change_date("database_name", "table_name")

Работа с конфигурацией и собственно timemechine:

import backup
 
# Считаем конфигурацию из одного файла
conf1 = backup.Conf.read_conf_file("../conf1.json")
 
# Считаем конфиграцию из нескольких файлов
confs = backup.Conf.read_conf_files(["../conf1.json", "../conf2.yaml", "../conf3.py"])
 
# Считаем конфигурацию из всех файлов лежащих в папке
dir_confs = backup.Conf.read_conf_dir("/etc/ltmbackup/conf.d")
 
# Создадим объект rsync:
rsync = backup.Rsync()
 
# Напишем обработчик сообщений от rsync, взяв в качестве примера тот, который находится в backup.Rsync.default_callback:
 
def rsync_callback(data):
    if data['type'] == "progress":
        try:
            speed = data['speed']
            if speed > 1024**3:
                data['speed'] = str(round(speed / (1024**3), 2)) + "GB/s"
            elif speed > 1024**2:
                data['speed'] = str(round(speed / (1024**2), 2)) + "MB/s"
            elif speed > 1024:
                data['speed'] = str(round(speed / (1024), 2)) + "KB/s"
            print("Прогресс:{progress}%, скорость: {speed}".format(**data))
        except Exception as e:
            print(e)
            print(data)
    elif data['type'] == "message":
        print("Информация: " + data['message'])
 
# запустим резервное копирование вручную:
rsync.timemechine(
    {"path":"/home/user", "host":""}, 
    {"path":"/home/backuper/backup/user_home", "host":"backuper@back_server.local"},
    ["*.log", "*~", "*.bak"],
    rsync_callback
)
 
# Запустим резервное копирование вариантов, считанных ранее из конфигурационных файлов:
backup.go(dir_confs, rsync_callback)

Дальнейшие планы:

  • Написать GUI для того чтобы удобно создавать конфиг-файлы
  • Написать скрипт для анализа резервных копий, с целью выявления слишком часто меняющихся файлов
  • Создать инструмент для анализа изменений файлов, путём сравнения различных версий копий
  • Доработать скрипт, чтобы его можно было использовать не только на Linux-машинах
  • Хотя восстановление из бэкапов и сейчас не сложно сделать с помощью rsync (да или даже простого копирования файлов) и mysql, всё-таки стоит написать автоматизированный скрипт, который сумеет в одно нажатии восстановить указанную резервную копию.
  • Доработать ядро так, чтобы копирование различных типов данных, отличных от файлов, проводилось с помощью плагинов. Например тот же mysqldump должен стать плагином.

Если вдруг в скрипте обнаружатся ошибки, можно писать об этом в комментариях здесь, или создать баг в https://github.com/MihanEntalpo/LinuxTimeMachine/issues


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