Как легко и быстро сделать создание snapshot’ов и их автоматическое удаление

от автора

История о том, как у меня была задача на решение которой ушло 2 дня. Обнаружилось несоответствие в документации и реальном мире яндекс облака в Яндекс писалось, но ответа не получилось.

Yandex.Cloud

Задача:

По расписанию, создавать SNAPSHOT дисков в используемых instance. При этом должна быть возможность помечать диски, которые нужно подвергать процедуре резервного копирования, а какие нет.

Подзадачи:

  • Snapshot’ы старше n дней должны автоматически удаляться из хранилища. При этом должна быть возможность изменять n.
  • Snapshot’ы должны иметь человеко-читаемый вид названия. И соответствовать следующему шаблону:
    %имя диска оригинала%-дата создания%-%уникальное имя диска%

Для того, чтобы в случае необходимости, человеку было очевидно из чего разворачивать новые машины. (в финальном варианте реализовано отдельным bash скриптом исполняемым со сторонней машины).

Ход выполнения:

В Y.cloud нет штатной функции выполняющей подобную задачу.

Решение — реализовать за счет function внутри самого Y.cloud, для экономии ресурсов. Для создания snapshot’ов была написана функция на NodeJS12

const ycsdk = require("yandex-cloud/api/compute/v1"); const FOLDER_ID = process.env.FOLDER_ID; async function handler(event, context) {     const snapshotService = new ycsdk.SnapshotService();     const diskService = new ycsdk.DiskService();     const diskList = await diskService.list({         folderId: FOLDER_ID,     });     for (const disk of diskList.disks) {         if ('snapshot' in disk.labels) {             snapshotService.create({                 folderId: FOLDER_ID,                 diskId: disk.id             });         }     } } exports.handler = handler; 

*При вызове данной функции, нужно через окружение передать FODLER_ID и указать служебную учетную запись.

Далее добавляется вызов данной функции по расписанию. И задача решена.

Подзадача 1.

Первоначально было решено делать через такую же функцию NodeJS12
Логика работы: анализируем дату создания snapshot’a сравниваем с разницей между текущей датой и n и в случае превышения лимита – удаляем.

Для этого, обращаемся к официальной документации и видим, что параметр CreatedAt должен иметь тип string.

Ок. Пишем функцию, которая удалит snapshot’ы которые моложе 1 часа от рождения (для теста). Запускаем. Получаем ничего. Совсем ничего. Ни ошибки в поле вывода ошибок, но нужного нам действия.

Итерация 1.

const ycsdk = require("yandex-cloud/api/compute/v1");  const FOLDER_ID = process.env.FOLDER_ID;  const date = new Date(); date.setHours( date.getHours() - 1 );  async function handler(event, context) {   const snapshotService = new ycsdk.SnapshotService();    const {snapshots} = await snapshotService.list({folderId: FOLDER_ID});   for ( let snapshot in snapshots ) {     const dateSnapshot = new Date( snapshot.createdAt );     if ( dateSnapshot.getTime() > date.getTime() ) snapshotService.delete({snapshotId: snapshot.id});   } }  exports.handler = handler; 

Итерация 2.

Изменяем функцию так, чтобы она в теле ошибки вывела нам ответное сообщение.

const ycsdk = require("yandex-cloud/api/compute/v1");  const FOLDER_ID = process.env.FOLDER_ID;  const date = new Date(); date.setHours( date.getHours() - 1 );  async function handler(event, context) {   const snapshotService = new ycsdk.SnapshotService();    const {snapshots} = await snapshotService.list({folderId: FOLDER_ID});   throw Error( JSON.stringify( snapshots ) ); }  exports.handler = handler;  Получаем в ответ ошибку: «"errorMessage": "[{\"labels\":{},\"productIds\":[],\"id\":\"fd813o0n3p753lhqphie\",\"folderId\":\"b1gfub3omefcfvchsd0f\",\"createdAt\":{\"seconds\":{\"low\":1594137358,\"high\":0,\"unsigned\":false}},\"diskSize\":{\"low\":1073741824,\"high\":0,\"unsigned\":false},\"status\":2,\"sourceDiskId\":\"ef3ivjn6340h9e8incbq\"},…..»

Причесав который, мы видим следующее:

{     "labels": {},     "productIds": [],     "id": "fd813o0n3p753lhqphie",     "folderId": "b1gfub3omefcfvchsd0f",     "createdAt": {       "seconds": {         "low": 1594137358,         "high": 0,         "unsigned": false       }

Отсюда делаем заключение. CreatedAt не строка а, объект.

Итерация3.

Пытаемся работать с CreatedAt. Меняем функцию.

const ycsdk = require("yandex-cloud/api/compute/v1");  const FOLDER_ID = process.env.FOLDER_ID;  const date = new Date(); date.setHours( date.getHours() - 1 );  async function handler(event, context) {   const snapshotService = new ycsdk.SnapshotService();    const {snapshots} = await snapshotService.list({folderId: FOLDER_ID});   for ( let snapshot in snapshots ) {      if ( snapshot.createdAt.seconds.low > date.getTime() / 1000 ) {       snapshotService.delete({snapshotId: snapshot.id});     }   } }  exports.handler = handler;

Получаем ошибку:

{     "errorMessage": "Cannot read property 'seconds' of undefined",     "errorType": "TypeError",     "stackTrace": [         {             "function": "Runtime.handler",             "file": "/function/code/index.js",             "line": 14,             "column": 29         }     ]

Ошибка говорит нам о том, мы пытаемся взять свойство seconds у несуществующего объекта, хотя ранее мы наблюдали вывод свойств объекта ответа "createdAt":{"seconds":{"low":1594137358,"high":0,"unsigned":false}}
Итерация 4.

const ycsdk = require("yandex-cloud/api/compute/v1");  const FOLDER_ID = process.env.FOLDER_ID;  const date = new Date(); date.setHours( date.getHours() - 1 );  async function handler(event, context) {   const snapshotService = new ycsdk.SnapshotService();    const {snapshots} = await snapshotService.list({folderId: FOLDER_ID});   for ( let i = 0; i < 5; i++ ) {     throw Error( JSON.stringify( snapshots[i].createdAt ) );   }  }  exports.handler = handler;

Получаем ошибку:

{     "errorMessage": "{\"seconds\":{\"low\":1594137358,\"high\":0,\"unsigned\":false}}",     "errorType": "Error",     "stackTrace": [         {             "function": "Runtime.handler",             "file": "/function/code/index.js",             "line": 13,             "column": 11         }     ] }

Сократили цикл до 5 итераций для удобства.

Итерация 5.

const ycsdk = require("yandex-cloud/api/compute/v1");  const FOLDER_ID = process.env.FOLDER_ID;  const date = new Date(); date.setHours( date.getHours() - 1 );  async function handler(event, context) {   const snapshotService = new ycsdk.SnapshotService();    const {snapshots} = await snapshotService.list({folderId: FOLDER_ID});   const list = [];   list.push( date.getTime() / 1000 );   for ( let i in snapshots ) {     const d = new Date( snapshots[i].createdAt );     list.push( d.getTime() / 1000 );   }   throw Error( JSON.stringify( list ) );  }  exports.handler = handler; ;

Получаем ошибку:

{     "errorMessage": "[1594135869.705,null,null,null,null,null,null,null]",     "errorType": "Error",     "stackTrace": [         {             "function": "Runtime.handler",             "file": "/function/code/index.js",             "line": 18,             "column": 9         }     ] } 

Этот ответ говорит нам о том, что функция Date не смогла распарсить якобы строку свойства createdAt, которая должна содержать дату и время в виде строки, согласно документации.

Итого — в платформе Яндекс Облако найдено еще одно не соответствие документации и реального положения дел. Если у вас стоит такая же задача как у меня, вы можете теперь не тратить на это целый рабочий день.

ссылка на оригинал статьи https://habr.com/ru/post/513884/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *