[Из песочницы] Автоматизация обновления темплейтов OpenVZ на Proxmox

Однажды появилась такая необходимость обновить версии темплейтов OpenVZ загруженных в кэш Proxmox’а.

Задача в общем-то простая и тривиальная. Всего то и необходимо, это скачать новый темплейт и заменить им старый. Но в глобальном плане задача мне виделась шире, а именно периодически проверять обновления и загружать по необходимости новые версии темплейтов. То есть постоянно поддерживать их в актуальном состоянии.

Желание вполне естественное и понятное. И было бы глупо выполнять эти рутинные и простые операции каждый раз вручную, а по сему, решение вопроса напрашивалось само собой: сделать некий скрипт, который сам будет всё это делать, в то время как админ будет отдыхать и лишь время от времени проверять работает ли обновление.

Итак, есть желание и пора приступать к его осуществлению. Для начала решим, что же конкретно должен делать наш скрипт.

Постановка задачи


1. Время от времени, через определённые промежутки, скрипт должен запускаться.
2. Подключаться к серверу на котором лежат официальные обновлённые темплейты OpenVZ.
3. Сравнивать темплейты, которые есть на сервере с теми, которые загружены в кэш.
4. Загружать новый темплейт (если он есть), и заменять им старый в том случае, если версия на сервере отличается от локальной.
5. Вести лог того что загружено, а что нет, и когда загружено (обновлено).

Вот собственно и всё.

Реализация


Для написания скрипта мной был выбран старый и надёжный Perl, по причине моей давней с ним дружбы, а так же потому что для этого языка уже написано огромное количество готовых модулей на все случаи жизни для выполнения системных задач и не только.

Пропускаем первый пункт задания, о нём будет написано в самом конце, когда скрипт уже будет готов к работе. Тем более что это задача не относящаяся к самому скрипту и выполняться будет сторонними средствами, а именно, всю ответственность за своевременный запуск нашего скрипта мы возложим на Cron. Это его задача и обязаннось всё планировать и запускать. Мы же двинемся дальше и вернёмся к вопросу планирования позже.

В качестве источника темплейтов будем использовать официальный FTP сервер openvz.org, а для подключения к нему средствами Perl воспользуемся стандартным модулем Net: FTP.

Далее следует описание самого скрипта с пояснениями.

Для начала подключаем модули.

#!/usr/bin/perl -w

use strict;
use Fcntl qw(:DEFAULT :flock);
use Net::FTP;



Теперь объявим необходимые нам переменные, с которыми будет работать скрипт. По сути это константы, которые не будут меняться в ходе выполнения скрипта.

# директория темлейтов OpenVZ на ноде Proxmox
my $vzdir = "/var/lib/vz/template/cache";

# Путь на FTP сервере, по которому нужно искать обновления
my $urldir = "ftp://ftp.openvz.org/template/precreated/";

# Директория в которой будет лежать log-файл с результатами выполнения скрипта
my $logdir ="/var/log/";

# Собственно сам log-файл, его имя
my $logfile = "ovzupdate.log";



Как можно догадаться из имени log-файла, сам скрипт называется ovzupdate. Расширение .pl необязательно, достаточно того, что первой строкой скрипта указан интерпретатор, который обработает этот файл.

Итак, продолжим…

# Открываем log-файл для записи
open(STDOUT, '>>',$logdir.$logfile) or die "Can't open file '$logfile' $!";

# Наводим красоту :) Чтобы всё выглядело прилично, а не выводилось как попало.
print "\n=========================\n".getdate()."\n=========================\n";
print gettime()." * Starting OpenVZ templates update\n";



И наконец-то мы добрались до настоящей работы и подошли к тому, для чего собственно и создавался сам скрипт. Подключаемся к FTP серверу openvz.org.

# Подключение к ftp-серверу
my $server_name = 'ftp.openvz.org';
my $ftp_username = 'anonymous';
my $ftp_password = '';
my $ftp_source_dir = '/template/precreated';

my $ftp = Net::FTP->new($server_name, Debug => 1);
$ftp->login($ftp_username,$ftp_password);
$ftp->cwd($ftp_source_dir);
$ftp->binary();



Теперь объявим переменную, в которой будет храниться список (массив) имён локальных темплейтов и открываем локальную директорию (кэш Proxmox’а) в которой хранятся уже загруженные темплейты для проверки актуальности файлов.

my $file;
opendir(DIR, $vzdir) or die "Can't open $vzdir: $!";



А теперь собственно прописываем сам цикл сравнения файлов. Надо сказать, что мы не будем обновлять и качать все файлы с FTP без разбора, а будем выбирать только те, которые уже находятся в нашем локальном кэше и будем сравнивать их по размеру с файлами на ftp-сервере. Если размер файла в локальном кэше будет отличаться от размера файла с таким же именем на удалённом сервере, то файл в кэше будет удалён, а на его место загружен новый файл с FTP.

# Заносим в переменную список файлов в директории кэша
while( defined ($file = readdir (DIR)) ) {

# Исключаем из списка обработку ссылок на директории находящиеся выше
  if ($file ne "." and $file ne "..")  {

# Определяем размер локального файла
     my $local_file_size = -s $vzdir."/".$file;

# Определяем размер файла с таким же именем, находящегося в директории ftp-сервера
     my $remote_file_size = $ftp->size($file);

# Здесь мы просто выводим в log размеры одного и другого файла
# В принципе, эти две строчки можно закоментировать, 
# если не хотите перегружать лог лишней информацией
     print gettime()."   Удалённый файл: $file -> ",$remote_file_size,"\n";
     print gettime()."   Локальный файл: $file -> ",$local_file_size,"\n";

# Собственно сравнение размеров файлов
     if ($local_file_size ne $remote_file_size) {

# Если размер не совпадает, удаляем локальный файл
        unlink $vzdir."/".$file;

# и скачиваем актуальную версию файла темплейта
        system ("wget -P ".$vzdir." ".$urldir.$file);

# Пишем в log отчёт о том, что файл обновлён
        print gettime()." + Загрузка новой версии ".$file."\n";
     }
     else {

# Иначе, пишем в log что файл является актуальным
        print gettime()."   Версия ".$file." актуальна\n"
     }
  }
}



Закрываем директорию, ftp-соединение и стандартный поток вывода.

closedir(DIR);
$ftp->quit;
print gettime()." * Проверка обновлений окончена\n";
close STDOUT;



Ну вот, практически и всё. Сам скрипт содержит три дополнительных функции, которые выполняют всего лишь вспомогательную роль и к сути вопроса не относятся. Готовый скрипт можно посмотреть тут.

Завершение


А теперь, как и обещал, вернёмся к пункту номер один. Скрипт можно положить на сервере Proxmox’а в любое удобное место. И остаётся только прописать его в crontab, чтобы он запускался на выполнение через нужный период времени. Периодичность выбирайте сами, но думаю что нет необходимости запускать его чаще раза в неделю.

Чтобы добавить задание обновления, зайдем в режим редактирования заданий crontab.

crontab -e

И последней добавляем строку, которая и будет выполнять наш скрипт обновления в определённое время и день. Для примера, в приведённой ниже строке указано, что скрипт будет выполняться каждый четверг в три часа ночи.

0 3 * * 4 /root/bin/ovzupdate 2>/dev/null


2>/dev/null — перенаправляет вывод потока STDERR в «чёрную дыру» нигде не сохраняя, но это уже на личное усмотрение, можно тоже сохранять в лог.

Сохраняем сделанные нами изменения и на этом всё, автоматическое обновление настроено. Теперь нам остаётся только время от времени проверять лог /var/log/ovzupdate.log, чтобы знать было или нет обновление. И когда это произойдёт, мы увидим что-то наподобие этого:

=========================
12-03-2015
=========================
03:00:01 * Начало обновления OpenVZ templates
03:00:03   Удалённый файл: debian-7.0-x86_64.tar.gz -> 235043942
03:00:03   Локальный файл: debian-7.0-x86_64.tar.gz -> 235004350
03:01:52 + Загрузка новой версии debian-7.0-x86_64.tar.gz
03:01:52   Удалённый файл: ubuntu-12.04-x86_64.tar.gz -> 131011759
03:01:52   Локальный файл: ubuntu-12.04-x86_64.tar.gz -> 130987444
03:02:48 + Загрузка новой версии ubuntu-12.04-x86_64.tar.gz
03:02:48   Удалённый файл: scientific-6-x86_64.tar.gz -> 221101244
03:02:48   Локальный файл: scientific-6-x86_64.tar.gz -> 219898164
03:03:45 + Загрузка новой версии scientific-6-x86_64.tar.gz
03:03:45   Удалённый файл: centos-7-x86_64.tar.gz -> 211178690
03:03:45   Локальный файл: centos-7-x86_64.tar.gz -> 211139455
...
03:16:31 * Проверка обновлений окончена


Удачного обновления!

© Habrahabr.ru