[Сценарий] Резервное копирование БД и каталогов сервера (для Linux)

Не требует установки программ или изменения файлов

Модераторы: immortal, newz20

skysilver
Сообщения: 3006
Зарегистрирован: Чт авг 21, 2014 8:28 am
Откуда: Киров, Россия
Благодарил (а): 400 раз
Поблагодарили: 1753 раза
Контактная информация:

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение skysilver » Чт июн 30, 2016 11:55 am

eeak1 писал(а):Судя по всему "grant_type=password" прикрыли, т.к. ни вчера, ни сегодня бэкап не прошел и при проверке не удается получит токен с ошибкой "unauthorized_client". Я так понял что "grant_type=password" - была недокументированной возможностью.
Это вы о чем? Применяемый в сценарии бэкапа php-класс использует OAuth-авторизацию по токену.
У меня бэкапы заливаются в облако штатно, никаких проблем не замечал.
MajorDoMo (GitHub) на Cubietruck. ОС Debian 7 (wheezy) (kernel 3.4.105) с переносом на HDD.
Мой CONNECT | Блоги | Telegram
eeak1
Сообщения: 51
Зарегистрирован: Чт май 12, 2016 9:13 am
Благодарил (а): 22 раза
Поблагодарили: 11 раз
Контактная информация:

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение eeak1 » Чт июн 30, 2016 11:58 am

Это я о том что теперь невозможно использовать скрипт без токена. Если по токену, то да - всё работает.
Алиса живёт на нубуке с закрытой крышкой в Docker контейнере, соседствует с контейнерами nextcloud, plex, mosquitto, и т.д.
ранее в Docker контейнере на Raspberry Pi 4
ранее натив на Raspberry Pi 3
https://www.eeak.biz
Akorolev
Сообщения: 119
Зарегистрирован: Вт ноя 08, 2016 4:27 pm
Благодарил (а): 11 раз
Поблагодарили: 10 раз

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение Akorolev » Чт ноя 17, 2016 6:23 am

Создал сценарий backupServer при его выполнении по http://127.0.0.1/objects/?script=backupServer выдает ошибку:

Код: Выделить всё

Fatal error: Call to a member function trace() on a non-object in /var/www/modules/scripts/scripts.class.php(139) : eval()'d code on line 88
При это Алиса пишет: 11:03 Алиса: Начинаю архивацию данных на сервере.
И все больше ничего не происходит.
--------------
С командной строки выполнение sudo /var/www/lib/backup.sh -czpPf /home/my_etc_backup.tar.gz /etc происходит нормально!
skysilver
Сообщения: 3006
Зарегистрирован: Чт авг 21, 2014 8:28 am
Откуда: Киров, Россия
Благодарил (а): 400 раз
Поблагодарили: 1753 раза
Контактная информация:

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение skysilver » Чт ноя 17, 2016 9:53 am

Akorolev писал(а):Создал сценарий backupServer при его выполнении по http://127.0.0.1/objects/?script=backupServer выдает ошибку:

Код: Выделить всё

Fatal error: Call to a member function trace() on a non-object in /var/www/modules/scripts/scripts.class.php(139) : eval()'d code on line 88
Судя по всему какая-то проблема с объектом log и его методом trace, и все спотыкается здесь:

Код: Выделить всё

if ($reclog) { $log = getLogger('script.backupServer'); }
if ($reclog == 2) $log->trace('Начало резервного копирования данных на сервере.'); 
Из-за чего это происходит, не скажу. Возможно были какие-то изменения в обновлениях с тех пор, как был написан этот сценарий. Или именно в вашей конфигурации проблема с логированием.
Попробуйте закоментировать все, что связано с выводом в лог. Или заменить вывод в лог на команду say().
MajorDoMo (GitHub) на Cubietruck. ОС Debian 7 (wheezy) (kernel 3.4.105) с переносом на HDD.
Мой CONNECT | Блоги | Telegram
Akorolev
Сообщения: 119
Зарегистрирован: Вт ноя 08, 2016 4:27 pm
Благодарил (а): 11 раз
Поблагодарили: 10 раз

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение Akorolev » Чт ноя 17, 2016 11:10 am

skysilver писал(а):
Akorolev писал(а):Создал сценарий backupServer при его выполнении по http://127.0.0.1/objects/?script=backupServer выдает ошибку:

Код: Выделить всё

Fatal error: Call to a member function trace() on a non-object in /var/www/modules/scripts/scripts.class.php(139) : eval()'d code on line 88
Судя по всему какая-то проблема с объектом log и его методом trace, и все спотыкается здесь:

Код: Выделить всё

if ($reclog) { $log = getLogger('script.backupServer'); }
if ($reclog == 2) $log->trace('Начало резервного копирования данных на сервере.');
Из-за чего это происходит, не скажу. Возможно были какие-то изменения в обновлениях с тех пор, как был написан этот сценарий. Или именно в вашей конфигурации проблема с логированием.
Попробуйте закоментировать все, что связано с выводом в лог. Или заменить вывод в лог на команду say().
Да точно, с логом проблема, пока временно поставил на say дальше переделаю.

И есть еще вопрос, собственно про диск:

Код: Выделить всё

16:06 Алиса: Завершение резервного копирования данных на сервере.
16:06 Алиса: Ротация резервных копий завершена.
16:06 Алиса: Ошибка запроса списка каталогов и файлов на Яндекс.Диск: Не авторизован.
16:06 Алиса: Архивов меньше (или равно) требуемого количества. Ничего не удаляем.
16:06 Алиса: Найдено 1 каталогов на локальном диске.
16:06 Алиса: Этап 3. Ротация бэкапов на локальном диске и в облаке.
16:06 Алиса: Начинаю ротацию резервных копий.
16:06 Алиса: Копирование локального бэкапа в облако завершено.
16:06 Алиса: Загрузка на Яндекс.Диск: mysql_mysql_2016-11-17_16-04.sql.gz [158422 Байт]
16:06 Алиса: Загрузка на Яндекс.Диск: mysql_db_terminal_2016-11-17_16-04.sql.gz [1365881 Байт] 
Исходя из лога алисы, пишет что: Ошибка запроса списка каталогов и файлов на Яндекс.Диск: Не авторизован.
Собственно сообщение о провальной авторизации появляется как в начале так и в конце, в чем может быть проблема?
ЯД конфиг у меня такой:

Код: Выделить всё

$yandexDiskConfig = [
    'app_id' => gg('YaDisk1.app_id'),            // идентификатор приложения
    'app_secret' => gg('YaDisk1.app_secret'),    // секретный ключ (пароль) приложения
    'token' => gg('YaDisk1.token'),                // OAuth-токен
    'login' => gg('YaDisk1.login'),                // логин пользователя
    'password' => gg('YaDisk1.password'),        // пароль пользователя
];
 
Так же реализован на свойствах объекта, они нормально получаются.
skysilver
Сообщения: 3006
Зарегистрирован: Чт авг 21, 2014 8:28 am
Откуда: Киров, Россия
Благодарил (а): 400 раз
Поблагодарили: 1753 раза
Контактная информация:

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение skysilver » Чт ноя 17, 2016 11:19 am

Akorolev писал(а):Исходя из лога алисы, пишет что: Ошибка запроса списка каталогов и файлов на Яндекс.Диск: Не авторизован.
Собственно сообщение о провальной авторизации появляется как в начале так и в конце, в чем может быть проблема?
В итоге что-то сохраняется на ЯДиск или нет?
Я бы проверил права для приложения на яндексе.
У меня такие:
YandexDisk PHP Client
PHP-клиент для Яндекс Диск.
Права:
Яндекс.Диск REST API
Доступ к папке приложения на Диске
Доступ к информации о Диске
Чтение всего Диска
Запись в любом месте на Диске
Яндекс.Диск WebDAV API
Доступ к Яндекс.Диску для приложений
MajorDoMo (GitHub) на Cubietruck. ОС Debian 7 (wheezy) (kernel 3.4.105) с переносом на HDD.
Мой CONNECT | Блоги | Telegram
Akorolev
Сообщения: 119
Зарегистрирован: Вт ноя 08, 2016 4:27 pm
Благодарил (а): 11 раз
Поблагодарили: 10 раз

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение Akorolev » Чт ноя 17, 2016 11:27 am

skysilver писал(а):
Akorolev писал(а):Исходя из лога алисы, пишет что: Ошибка запроса списка каталогов и файлов на Яндекс.Диск: Не авторизован.
Собственно сообщение о провальной авторизации появляется как в начале так и в конце, в чем может быть проблема?
В итоге что-то сохраняется на ЯДиск или нет?
Я бы проверил права для приложения на яндексе.
У меня такие:
YandexDisk PHP Client
PHP-клиент для Яндекс Диск.
Права:
Яндекс.Диск REST API
Доступ к папке приложения на Диске
Доступ к информации о Диске
Чтение всего Диска
Запись в любом месте на Диске
Яндекс.Диск WebDAV API
Доступ к Яндекс.Диску для приложений
Файлы нет не сохраняет, не может авторизоваться почему то...
А настройки такие:
Изображение
Callback url - он должен быть заполнен или нет?
skysilver
Сообщения: 3006
Зарегистрирован: Чт авг 21, 2014 8:28 am
Откуда: Киров, Россия
Благодарил (а): 400 раз
Поблагодарили: 1753 раза
Контактная информация:

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение skysilver » Чт ноя 17, 2016 11:42 am

Akorolev писал(а):Callback url - он должен быть заполнен или нет?
Не нужен, не используется. У меня все точно также. Даже не знаю, где затык. Надо дебажить. ))
MajorDoMo (GitHub) на Cubietruck. ОС Debian 7 (wheezy) (kernel 3.4.105) с переносом на HDD.
Мой CONNECT | Блоги | Telegram
Akorolev
Сообщения: 119
Зарегистрирован: Вт ноя 08, 2016 4:27 pm
Благодарил (а): 11 раз
Поблагодарили: 10 раз

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение Akorolev » Чт ноя 17, 2016 11:51 am

skysilver писал(а):
Akorolev писал(а):Callback url - он должен быть заполнен или нет?
Не нужен, не используется. У меня все точно также. Даже не знаю, где затык. Надо дебажить. ))
Все нашел, там проблема с токеном была, заново его перерегистрировал и все заработало! Видимо пока с ошибками бился - время токена истекло!

На свякий случай код сценария:
СпойлерПоказать

Код: Выделить всё

/* 
*    Сценарий для ежедневного создания резервных копий БД и каталогов.
*
*    Архивы сохраняются на локальный диск и загружаются в облако (на Яндекс.Диск средствами REST API и OAuth-авторизации).
*    Предусмотрена ротация архивных копий (хранится не более заданного числа архивов, остальные удаляются).
*    На каждый ежедневный архив создается собственный каталог с именем вида "год-месяц-день", в который
*    помещаются файлы с архивами БД и каталогов.
*
*    Для использования облачного хранилища Яндекс.Диск предварительно необходимо авторизоваться на Яндексе
*    и создать приложение здесь https://oauth.yandex.ru/client/new (указать название приложения, дать все права 
*    в разделе Яндекс.Диск REST API, в Callback URL подставить URL для разработки). В свойствах созданного приложения
*    будут приведены ID и пароль приложения.
*
*    OAuth-токен можно получить вручную согласно этой инструкции https://tech.yandex.ru/oauth/doc/dg/tasks/get-oauth-token-docpage/
*   Либо, оставив поле token в $yandexDiskConfig пустым, указать в этом сценарии свои логин и пароль для доступа к сервисам Яндекса,
*   тогда токен будет запрашиваться у Яндекса при каждом запуске сценария. Рекомендую запросить токен таким образом однократно, а в 
*    дальнейшем полученный токен указывать непосредственно в $yandexDiskConfig).
*    
*   Если имеется несколько учеток к Яндекс.Диск, то достаточно создать только одно приложение и указывать его ID и пароль при
*   получении токена для другой учетки.
*
*    Copyright (C) 2014-2015 Agaphonov Dmitri aka skysilver [mailto:skysilver.da@gmail.com]
*/


/* 
    Конфигурация и параметры
*/
$numberOfCloudBackups = gg('dailyBackup.numberOfCloudBackups');    // количество хранимых бэкапов в облаке (в днях)
$numberOfLocalBackups = gg('dailyBackup.numberOfLocalBackups');    // количество хранимых бэкапов локально (в днях)
$cloudBackupFolder = gg('dailyBackup.cloudBackupFolder');        // каталог для бэкапов в облаке (например, /backups)
$localBackupFolder = gg('dailyBackup.localBackupFolder');        // локальный каталог для бэкапов (например, /home/skysilver/backups)

// Путь к вспомогательному shell-скрипту
//     У пользователя www-data нет права чтения некоторых каталогов. Поэтому, чтобы была возможность такие
//     каталоги архивировать, для запуска линуксовых команд используется shell-скрипт, который благодаря sudo
//     может запускаться с правами root под пользователем www-data.
//     Чтобы дать пользователю www-data возможность запускать этот скрипт от root,
//     необходимо в /etc/sudoers добавить строку www-data ALL=(root) NOPASSWD: /путь_до_скрипта/backup.sh
$shellScript = "/var/www/lib/backup.sh";

// Определим путь к текущему (сегодняшнему) локальному каталогу и каталогу на Яндекс Диск
$todayLocalFolder = $localBackupFolder."/".date('Y-m-d');
$todayCloudFolder = $cloudBackupFolder."/".date('Y-m-d');

// Архивируемые БД и реквизиты доступа к ним.
$databases = [
    ['login' => gg('dailyBackup.mysqlUser'), 'password' => gg('dailyBackup.mysqlPassword'), 'dbname' => 'db_terminal'],
    ['login' => gg('dailyBackup.mysqlUser'), 'password' => gg('dailyBackup.mysqlPassword'), 'dbname' => 'mysql'],
];

// Архивируемые каталоги
$dirs = [
    ['name' => 'etc', 'path' => '/etc'],
    ['name' => 'mysql', 'path' => '/var/lib/mysql'],
    ['name' => 'logs', 'path' => '/var/log'],
    ['name' => 'www', 'path' => '/var/www'],
];

// Реквизиты доступа к Яндекс Диск
// Если токен уже получен, то параметры app_id, app_secret, login и password можно не заполнять.
// Если токена нет, то заполняем все поля, а поле token оставляем пустым (равным '').
$yandexDiskConfig = [
    'app_id' => gg('YaDisk1.app_id'),            // идентификатор приложения
    'app_secret' => gg('YaDisk1.app_secret'),    // секретный ключ (пароль) приложения
    'token' => gg('YaDisk1.token'),                // OAuth-токен
    'login' => gg('YaDisk1.login'),                // логин пользователя
    'password' => gg('YaDisk1.password'),        // пароль пользователя
];

// Писать логи ( 0-нет, 1-только критические, 2-все )
$reclog = 2;

// Т.к. архивирование и загрузка файлов в облако может занимать неопределенное время,
// то снимем ограничение на время выполнения php-скрипта (по умолчанию в моем конфиге php.ini задано 90 секунд).
set_time_limit(0);


/* 
    Оповещение
*/

say('Начинаю архивацию данных на сервере.', 1);

say("Начало резервного копирования данных на сервере.",1);
 


/* 
    Архивация БД и каталогов сервера на локальный диск
*/

say('Этап 1. Архивация БД и каталогов сервера на локальный диск.',1);

// Проверяем, создан или нет общий каталог для бэкапов. Если нет, то создаем.
if (!is_dir($localBackupFolder)) {
    say('Создаем общий каталог %s на локальном диске.', 1);
    if (!mkdir($localBackupFolder, 0777)) {
        say('Не удалось создать общий каталог на локальном диске.',1);
         return;
    } else {
        say('Общий каталог успешно создан.',1);
    }    
} else {
    say('Общий каталог для бэкапов уже создан на локальном диске.',1);
}

// Проверяем, создан или нет каталог для ежедневного бэкапа. Если нет, то создаем.
if (!is_dir($todayLocalFolder)) {
    say(sprintf('Создаем каталог для ежедневного бэкапа %s на локальном диске.', $todayLocalFolder),1);
    if (!mkdir($todayLocalFolder, 0777)) {
         say('Не удалось создать каталог для ежедневного бэкапа на локальном диске.',1);
         return;
    } else {
        say('Каталог для ежедневного бэкапа успешно создан.',1);
    }    
} else {
    say(sprintf('Каталог для ежедневного бэкапа %s уже создан на локальном диске.', $todayLocalFolder),1);
}

    /*     Архивирование баз данных    */

    $date = date('Y-m-d_H-i');
    foreach ($databases as $db) {
        $filename = "$todayLocalFolder/mysql_{$db['dbname']}_$date.sql.gz";
        // f - force overwrite of output file and compress links
        // 1 - compress faster
        // 9 - compress better
         // mysqldump  --opt - аккумулирует в себя сразу несколько опций
        // (--add-drop-table, --add-locks, --all, --extended-insert, --quick, --lock-tables)
        $cmd = "mysqldump --user={$db['login']} --password={$db['password']} --no-create-db --add-drop-table {$db['dbname']} | gzip -f -4 > $filename";
        exec($cmd, $out);
        if (!file_exists($filename) || filesize($filename) < 100) {
             say(sprintf('Резервная копия БД %s не создана: %s', $db['dbname'], $out),1);
        } else {
            say(sprintf('Резервная копия БД %s успешно создана на локальном диске.', $db['dbname']),1);
        }
    }
    
    
    foreach ($dirs as $dir) {
        $filename = "$todayLocalFolder/files_{$dir['name']}_$date.tar.gz";
        //c - создать архив,
        //v - выводить информацию о процессе,
        //z - использовать сжатие gzip,
        //p - сохраняем данные о владельцах и правах доступа,
        //f - пишем архив в файл
        //P - don't strip leading `/'s from file names 
        $cmd = "sudo ".$shellScript." -czpPf $filename {$dir['path']}";
        //var_dump($cmd);
        exec($cmd, $out);
        //var_dump($op);
        if (!file_exists($filename) || filesize($filename) < 100) {
            say(sprintf('Резервная копия каталога %s не создана: %s', $dir['name'], $out),1);
        } else {
            say(sprintf('Резервная копия каталога %s успешно создана на локальном диске.', $dir['name']),1);
        }
    }

say('Архивация данных на сервере закончена.', 1);
    
/* 
    Копирование локального бэкапа в облако
*/

say('Начинаю копирование локального бэкапа в облако.', 1);

say('Этап 2. Копирование локального бэкапа в облако.',1);

// Создаем объект класса Yandex_Disk
// Если токен еще не получен (не указан в конфиге), то запросим его.
if( $yandexDiskConfig['token'] == '' ) {
    $ynd = new Yandex_Disk($yandexDiskConfig);
    $myToken = $ynd->getToken();
    //echo "<br> Токен = ".$myToken." <br>";
     //sg('YaDisk1.token', $myToken);
     say(sprintf('Мой OAuth-токен: %s', $myToken),1);
    if( isset($ynd->error) ) {
         say(sprintf('Ошибка запроса OAuth-токена: %s', $ynd->error),1);
    }
}
else $ynd = new Yandex_Disk($yandexDiskConfig);

// Узнаем доступное место на Яндекс Диске (для справки)
$req = $ynd->get();
if( isset($req['error']) ) {
     say(sprintf('Ошибка запроса метаинформации о диске: %s', $req['message']),1);
 } else {
    //Получаем свободное и занятое место
    sg('YaDisk1.totalSpace', round(($req['total_space']) / 1024 / 1024 / 1024, 2));
      sg('YaDisk1.usedSpace', round(($req['used_space']) / 1024 / 1024 / 1024, 2));
      sg('YaDisk1.freeSpace', round(($req['total_space'] - $req['used_space']) / 1024 / 1024 / 1024, 2));
      say(sprintf('Всего места на Яндекс.Диске: %s ГБ.', gg('YaDisk1.totalSpace')),1);
      say(sprintf('Занято данными: %s ГБ.', gg('YaDisk1.usedSpace')),1);
      say(sprintf('Свободно: %s ГБ.', gg('YaDisk1.freeSpace')),1);     
 }

// Проверяем, создан или нет общий каталог для бэкапов на Яндекс Диске. Если нет, то создаем.
$req = $ynd->resources_get($cloudBackupFolder);
if( isset($req['error']) || $req['path'] != 'disk:'.$cloudBackupFolder) {
    say(sprintf('Создаем общий каталог %s на Яндекс.Диске.', $todayCloudFolder),1);
    $req = $ynd->resources_put($cloudBackupFolder);
    if( isset($ynd->error) ) {
         say(sprintf('Ошибка создания общего каталога на Яндекс.Диск: %s', $ynd->error),1);
     } else {
        say('Общий каталог успешно создан.',1);
     }    
 } else {
    say('Общий каталог для бэкапов уже создан на Яндекс.Диске.',1);
 }
 
// Если локальный каталог с архивами существует
if (is_dir($todayLocalFolder)) {
    // Узнаем содержимое каталога
    $files = scandir($todayLocalFolder);
    // Проверяем, создан или нет каталог для ежедневного бэкапа на Яндекс Диске. Если нет, то создаем.
    $req = $ynd->resources_get($todayCloudFolder);
    if( isset($req['error']) || $req['path'] != 'disk:'.$todayCloudFolder) {
        say(sprintf('Создаем каталог для ежедневного бэкапа %s на Яндекс.Диске.', $todayCloudFolder),1);
        $req = $ynd->resources_put($todayCloudFolder);
        if( isset($ynd->error) ) {
             say(sprintf('Ошибка создания каталога для ежедневного бэкапа на Яндекс.Диск: %s', $ynd->error),1);
        } else {
            say('Каталог для ежедневного бэкапа успешно создан.',1);    
        }    
    } else {
        say(sprintf('Каталог для ежедневного бэкапа %s уже создан на Яндекс.Диске.', $todayCloudFolder),1);
    }
    
    // Загрузим все файлы архивов на Яндекс Диск
    foreach($files as $file) {
        if(($file != ".") && ($file != "..")) {
            if(is_file($todayLocalFolder."/".$file)) {
                $fileCloudPath = $todayCloudFolder."/".$file;
                $fileLocalPath = $todayLocalFolder."/".$file;
                 // Если файл с таким же именем уже существует, то будет переписан.
                say(sprintf('Загрузка на Яндекс.Диск: %s [%s Байт]', $file, filesize($fileLocalPath)),1);
                 $req = $ynd->file_upload($fileCloudPath, $fileLocalPath);                 
            }
        }
    }
    
}

say('Копирование локального бэкапа в облако завершено.', 1);

/* 
    Ротация бэкапов на локальном диске и в облаке
*/

say('Начинаю ротацию резервных копий.', 1);

say('Этап 3. Ротация бэкапов на локальном диске и в облаке.',1);

    /*     Ротация бэкапов на локальном диске    */
    
    // Если локальный каталог с архивами существует
    if (is_dir($localBackupFolder)) {
        // Узнаем содержимое каталога
        $req = scandir($localBackupFolder);
        // Если каталог с архивами не пустой (не учитываем текущую '.' и родительскую '..' директории)
        if ((count($req) - 2) != 0) {
            // Составим список всех подкаталогов
            for ($i = 0, $j = 0; $i < count($req); $i++) {
                if ((is_dir($localBackupFolder."/".$req[$i])) && ($req[$i] != ".") && ($req[$i] != "..")) {
                    // Берем имя (путь) подкаталога и время создания
                    $locallist[$j]['path'] = $localBackupFolder."/".$req[$i];
                    $locallist[$j]['created'] = filemtime($localBackupFolder."/".$req[$i]);
                    $j += 1;
                }    
            }
            say(sprintf('Найдено %s каталогов на локальном диске.', count($locallist)),1);
            // Если архивов больше, чем требуется, то удалим часть старых.
            if (count($locallist) > $numberOfLocalBackups) {
                say('Архивов больше, чем требуется. Удалим часть старых.',1);
                // Отсортируем по дате создания
                arraySort($locallist, 'created');
                // Исключим из удаляемых нужное количество "свежих" архивов 
                array_splice($locallist, -$numberOfLocalBackups);
                say(sprintf('Для удаления %s каталогов.', count($locallist)),1);
                // Удалим старые каталоги с архивами из облака
                foreach($locallist as $l) {
                    removeDirectory($l['path']);
                     say(sprintf('Каталог %s удален с локального диска.', $l['path']),1);
                }        
            } else {             
                say('Архивов меньше (или равно) требуемого количества. Ничего не удаляем.',1);
            }
        }

    }
    
    
    /*     Ротация бэкапов на Яндекс Диске    */
    
    // Узнаем содержимое каталога
    $req = $ynd->resources_get($cloudBackupFolder, '_embedded.path,_embedded.total,_embedded.items.name,_embedded.items.type,_embedded.items.path,_embedded.items.created');
    if( isset($req['error']) ) {
        say(sprintf('Ошибка запроса списка каталогов и файлов на Яндекс.Диск: %s', $req['message']),1);
    } else {
         // Если каталог с архивами не пустой
        if (count($req['_embedded']['items']) != 0) {
            // Составим список всех подкаталогов
            for ($i = 0; $i < count($req['_embedded']['items']); $i++) {
                if ($req['_embedded']['items'][$i]['type'] == 'dir') {
                    // Берем имя (путь) подкаталога и время создания
                    $cloudlist[$i]['path'] = $req['_embedded']['items'][$i]['path'];
                    $cloudlist[$i]['created'] = strtotime($req['_embedded']['items'][$i]['created']);
                }    
            }
            say(sprintf('Найдено %s каталогов на Яндекс.Диске.', count($cloudlist)),1);
            // Если архивов больше, чем требуется, то удалим часть старых.
            if (count($cloudlist) > $numberOfCloudBackups) {
                say('Архивов больше, чем требуется. Удалим часть старых.',1);
                // Отсортируем по дате создания
                arraySort($cloudlist, 'created');
                // Исключим из удаляемых нужное количество "свежих" архивов 
                array_splice($cloudlist, -$numberOfCloudBackups);
                say(sprintf('Для удаления %s каталогов.', count($cloudlist)),1);
                // Удалим старые каталоги с архивами из облака
                foreach($cloudlist as $l) {
                    $req = $ynd->resources_delete($l['path'], false, true);
                    if( isset($req['error']) ) {
                        say(sprintf('Ошибка удаления каталога %s с Яндекс.Диск: %s', $l['path'], $req['message']),1);
                    } else {             
                         say(sprintf('Каталог %s удален с Яндекс.Диска.', $l['path']),1);
                    }
                }        
            }
            else {
                say('Архивов меньше (или равно) требуемого количества. Ничего не удаляем.',1);
            }
        }
    }

say('Ротация резервных копий завершена.', 1);

say('Завершение резервного копирования данных на сервере.',1); 
directman66
Сообщения: 2801
Зарегистрирован: Пн дек 26, 2016 9:51 am
Откуда: Екатеринбург
Благодарил (а): 380 раз
Поблагодарили: 693 раза
Контактная информация:

Re: Резервное копирование БД и каталогов сервера (для Linux)

Сообщение directman66 » Пн апр 10, 2017 8:36 pm

Очень познавательный сценарий. Но к сожалению сломал sudoers. Будьте внимательны при редактировании этого файла.
Если вам помогло данное сообщение, не поленитесь нажать кнопку "спасибо".
CONNECT | Оборудование | Блог | Дополнения | Email | Telegram
Ответить