Como criar instantâneos de forma rápida e fácil e removê-los automaticamente

A história é sobre como tive um problema que demorou 2 dias a resolver. Foi encontrada uma discrepância na documentação e o mundo real da nuvem Yandex foi escrito em Yandex, mas não houve resposta.



Yandex.Cloud



Tarefa:



De acordo com a programação, crie discos SNAPSHOT na instância usada. Ao mesmo tempo, deve ser possível marcar os discos que precisam de backup e quais não.



Subtarefas:



  • Snapshots com mais de n dias devem ser excluídos automaticamente do armazenamento. Nesse caso, deve ser possível alterar n.
  • Os instantâneos devem ter um título legível por humanos. E corresponda ao seguinte padrão:



    %  %- %-%  %


Para que, se necessário, fosse óbvio para uma pessoa o que implantar carros novos. (na versão final, é implementado por um script bash separado executado em uma máquina de terceiros).



Progresso:



Y.cloud não tem uma função padrão que execute essa tarefa.



A solução é implementá-lo às custas da função dentro do próprio Y.cloud, para economizar recursos. Para criar instantâneos, uma função foi escrita em 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;


* Ao chamar esta função, você precisa passar FODLER_ID pelo ambiente e especificar a conta de serviço.



Em seguida, uma chamada para esta função é adicionada em uma programação. E a tarefa está resolvida.



Subtarefa 1.



Inicialmente, optou-se por fazê-lo através da mesma função NodeJS 12.

Lógica de trabalho: analisar a data de criação do snapshot, compará-la com a diferença entre a data atual e n, e se o limite for ultrapassado, excluí-lo.



Para fazer isso, consulte a documentação oficial e veja que o parâmetro CreatedAt deve ser do tipo string.



ESTÁ BEM. Estamos escrevendo uma função que removerá os instantâneos com menos de 1 hora do nascimento (para o teste). Nós lançamos. Não ganhamos nada. Nada mesmo. Não é um erro no campo de saída de erro, mas a ação de que precisamos.



Iteração 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;


Iteração 2. Altere a



função para que ela exiba uma mensagem de resposta no corpo do erro.



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\"},…..»


Depois de pentear, vemos o seguinte:



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


A partir daqui, tiramos uma conclusão. CreatedAt não é uma string, mas um objeto.



Iteração 3.



Estamos tentando trabalhar com CreatedAt. Mudamos a função.



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;


Recebemos o erro:



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


O erro nos diz que estamos tentando obter a propriedade seconds de um objeto não existente, embora tenhamos observado anteriormente a saída das propriedades do objeto de resposta "createdAt":{"seconds":{"low":1594137358,"high":0,"unsigned":false}}

Iteração 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;


Recebemos o erro:



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


Reduziu o loop para 5 iterações por conveniência.



Iteração 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;
;


Recebemos o erro:



{
    "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
        }
    ]
}


Essa resposta nos diz que a função Date não conseguiu analisar a string da propriedade supostamente createdAt, que deveria conter a data e hora como string, de acordo com a documentação.



Total - na plataforma Yandex Cloud, foi encontrada outra discrepância entre a documentação e o estado real das coisas. Se você tem a mesma tarefa que a minha, agora você não pode gastar um dia inteiro de trabalho nisso.



All Articles