Gravar um script do canário Node.js - Amazon CloudWatch

Gravar um script do canário Node.js

Criar um canário do CloudWatch Synthetics do zero

Veja a seguir um exemplo de script do canário mínimo do Synthetics. Esse script é executado com êxito e retorna uma string. Para ver como é um canário com falha, altere let fail = false; para let fail = true;.

É necessário definir uma função de ponto de entrada para o script do canário. Para ver como os arquivos são carregados no local do Amazon S3 especificado como ArtifactS3Location do canário, crie esses arquivos na pasta /tmp. Após a execução do script, o status de aprovação/falha e as métricas de duração são publicadas no CloudWatch, e os arquivos em /tmp são carregados no S3.

const basicCustomEntryPoint = async function () { // Insert your code here // Perform multi-step pass/fail check // Log decisions made and results to /tmp // Be sure to wait for all your code paths to complete // before returning control back to Synthetics. // In that way, your canary will not finish and report success // before your code has finished executing // Throw to fail, return to succeed let fail = false; if (fail) { throw "Failed basicCanary check."; } return "Successfully completed basicCanary checks."; }; exports.handler = async () => { return await basicCustomEntryPoint(); };

Depois, expandiremos o script para usar o registro em log do Synthetics e fazer uma chamada usando o AWS SDK. Para fins de demonstração, esse script criará um cliente do Amazon DynamoDB e fará uma chamada para a API listTables do DynamoDB. Ele registra a resposta à solicitação e os logs são aprovados ou falham dependendo se a solicitação foi bem-sucedida.

const log = require('SyntheticsLogger'); const AWS = require('aws-sdk'); // Require any dependencies that your script needs // Bundle additional files and dependencies into a .zip file with folder structure // nodejs/node_modules/additional files and folders const basicCustomEntryPoint = async function () { log.info("Starting DynamoDB:listTables canary."); let dynamodb = new AWS.DynamoDB(); var params = {}; let request = await dynamodb.listTables(params); try { let response = await request.promise(); log.info("listTables response: " + JSON.stringify(response)); } catch (err) { log.error("listTables error: " + JSON.stringify(err), err.stack); throw err; } return "Successfully completed DynamoDB:listTables canary."; }; exports.handler = async () => { return await basicCustomEntryPoint(); };

Empacotamento dos arquivos do canário para Node.js

Se você estiver carregando scripts do canário usando um local do Amazon S3, o arquivo zip deverá incluir seu script sob essa estrutura de pastas: nodejs/node_modules/myCanaryFilename.js file.

Se você tiver mais de um arquivo .js ou se o script estiver condicionado a uma dependência, será possível agrupá-los em um único arquivo ZIP que contenha a estrutura da pasta nodejs/node_modules/myCanaryFilename.js file and other folders and files. Se estiver usando syn-nodejs-puppeteer-3.4 ou posterior, você também poderá colocar os arquivos do canário em outra pasta e criar a estrutura de pastas dessa forma: nodejs/node_modules/myFolder/myCanaryFilename.js file and other folders and files.

Nome do manipulador

Defina o ponto de entrada do script do canário (manipulador) como myCanaryFilename.functionName para corresponder ao nome do arquivo do ponto de entrada do script. Se estiver usando um runtime anterior a syn-nodejs-puppeteer-3.4, então functionNamedeverá ser handler. Se estiver usando syn-nodejs-puppeteer-3.4 ou posterior, você poderá escolher qualquer nome de função como manipulador. Se estiver usando syn-nodejs-puppeteer-3.4 ou posterior, você também poderá armazenar o canário em uma pasta separada, como nodejs/node_modules/myFolder/my_canary_filename. Se você armazenar em uma pasta separada, especifique esse caminho no ponto de entrada do script, como myFolder/my_canary_filename.functionName.

Alterar um script existente do Puppeteer para ser usado como canário do Synthetics

Esta seção explica como modificar scripts do Puppeteer para executá-los como scripts do canário do Synthetics. Para obter mais informações sobre o Puppeteer, consulte API do Puppeteer v1.14.0.

Vamos começar com este exemplo de script do Puppeteer:

const puppeteer = require('puppeteer'); (async () => { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.goto('https://example.com'); await page.screenshot({path: 'example.png'}); await browser.close(); })();

As etapas de conversão são as seguintes:

  • Crie e exporte uma função handler. O manipulador é a função de ponto de entrada para o script. Se estiver usando um runtime anterior a syn-nodejs-puppeteer-3.4, a função do manipulador deverá ser nomeada handler. Se estiver usando syn-nodejs-puppeteer-3.4 ou posterior, a função poderá ter qualquer nome, mas deverá ser o mesmo nome usado no script. Além disso, se você estiver usando syn-nodejs-puppeteer-3.4 ou posterior, poderá armazenar scripts em qualquer pasta e especificar essa pasta como parte do nome do manipulador.

    const basicPuppeteerExample = async function () {}; exports.handler = async () => { return await basicPuppeteerExample(); };
  • Use a dependência Synthetics.

    var synthetics = require('Synthetics');
  • Use a função Synthetics.getPage para obter um objeto Page do Puppeteer.

    const page = await synthetics.getPage();

    O objeto de página retornado pela função Synthetics.getPage tem os eventos page.on request, responsee requestfailed instrumentados para registro em log. O Synthetics também define a geração de arquivos HAR para solicitações e respostas na página e adiciona o ARN do canário aos cabeçalhos do atendente do usuário de solicitações de saída na página.

O script agora está pronto para ser executado como um canário do Synthetics. Veja a seguir o script atualizado:

var synthetics = require('Synthetics'); // Synthetics dependency const basicPuppeteerExample = async function () { const page = await synthetics.getPage(); // Get instrumented page from Synthetics await page.goto('https://example.com'); await page.screenshot({path: '/tmp/example.png'}); // Write screenshot to /tmp folder }; exports.handler = async () => { // Exported handler function return await basicPuppeteerExample(); };

Variáveis de ambiente

É possível usar variáveis de ambiente ao criar canaries. Isso permite escrever um único script o canário e usar esse script com valores diferentes para criar rapidamente vários canários que tenham uma tarefa semelhante.

Por exemplo, suponhamos que sua organização tenha endpoints como prod, dev e pre-release para os diferentes estágios do desenvolvimento de seu software, e você necessite criar canaries para testar cada um desses endpoints. É possível escrever um único script do canário que testa seu software e especificar valores diferentes para a variável de ambiente do endpoint ao criar cada um dos três canários. Em seguida, ao criar um canário, especifique o script e os valores a serem usados para as variáveis de ambiente.

Os nomes das variáveis de ambiente podem conter letras, números e o caractere de sublinhado. Devem começar com uma letra e ter pelo menos dois caracteres. O tamanho total das variáveis de ambiente não pode exceder 4 KB. Você não pode especificar nenhuma variável de ambiente reservada do Lambda como os nomes de suas variáveis de ambiente. Para obter mais informações sobre variáveis de ambiente reservadas, consulte Variáveis de ambiente do runtime.

Importante

As chaves e os valores de variáveis de ambiente não são criptografados. Não armazene informações sigilosas neles.

O exemplo de script a seguir usa duas variáveis de ambiente. Esse script é para um canário que verifica se uma página da Web está disponível. Utiliza variáveis de ambiente para parametrizar tanto a URL que ele verifica como o nível de logs do CloudWatch Synthetics que ele usa.

A função a seguir define LogLevel para o valor da variável de ambiente LOG_LEVEL.

synthetics.setLogLevel(process.env.LOG_LEVEL);

Essa função define URL para o valor da variável de ambiente URL.

const URL = process.env.URL;

Este é o script completo. Ao criar um canário usando esse script, especifique os valores a serem usados para as variáveis de ambiente LOG_LEVEL e URL.

var synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const pageLoadEnvironmentVariable = async function () { // Setting the log level (0-3) synthetics.setLogLevel(process.env.LOG_LEVEL); // INSERT URL here const URL = process.env.URL; let page = await synthetics.getPage(); //You can customize the wait condition here. For instance, //using 'networkidle2' may be less restrictive. const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000}); if (!response) { throw "Failed to load page!"; } //Wait for page to render. //Increase or decrease wait time based on endpoint being monitored. await page.waitFor(15000); await synthetics.takeScreenshot('loaded', 'loaded'); let pageTitle = await page.title(); log.info('Page title: ' + pageTitle); log.debug('Environment variable:' + process.env.URL); //If the response status code is not a 2xx success code if (response.status() < 200 || response.status() > 299) { throw "Failed to load page!"; } }; exports.handler = async () => { return await pageLoadEnvironmentVariable(); };

Aprovar variáveis de ambiente para seu script

Para transmitir variáveis de ambiente para o script ao criar um canário no console, especifique as chaves e os valores das variáveis de ambiente na seção Environment variables (Variáveis de ambiente) no console. Para ter mais informações, consulte Criar um canário.

Para transmitir variáveis de ambiente pela API ou pela AWS CLI, use o parâmetro EnvironmentVariables na seção RunConfig. O exemplo a seguir é um comando AWS CLI que cria um canário que usa duas variáveis de ambiente com chaves de Environment e Region.

aws synthetics create-canary --cli-input-json '{ "Name":"nameofCanary", "ExecutionRoleArn":"roleArn", "ArtifactS3Location":"s3://cw-syn-results-123456789012-us-west-2", "Schedule":{ "Expression":"rate(0 minute)", "DurationInSeconds":604800 }, "Code":{ "S3Bucket": "canarycreation", "S3Key": "cwsyn-mycanaryheartbeat-12345678-d1bd-1234-abcd-123456789012-12345678-6a1f-47c3-b291-123456789012.zip", "Handler":"pageLoadBlueprint.handler" }, "RunConfig": { "TimeoutInSeconds":60, "EnvironmentVariables": { "Environment":"Production", "Region": "us-west-1" } }, "SuccessRetentionPeriodInDays":13, "FailureRetentionPeriodInDays":13, "RuntimeVersion":"syn-nodejs-2.0" }'

Integrar o canário a outros produtos da AWS

Todos os canaries podem usar a biblioteca do AWS SDK. É possível usar essa biblioteca ao escrever o canário de forma a integrá-lo a outros serviços da AWS.

Para fazer isso, é necessário adicionar o código a seguir ao canário. Para estes exemplos, o AWS Secrets Manager é usado como o serviço ao qual o canário está se integrando.

  • Importe o AWS SDK.

    const AWS = require('aws-sdk');
  • Crie um cliente para o serviço da AWS ao qual você está realizando a integração.

    const secretsManager = new AWS.SecretsManager();
  • Use o cliente para fazer chamadas de API para esse serviço.

    var params = { SecretId: secretName }; return await secretsManager.getSecretValue(params).promise();

O trecho de código de script do canário a seguir demonstra um exemplo de integração ao Secrets Manager com mais detalhes.

var synthetics = require('Synthetics'); const log = require('SyntheticsLogger'); const AWS = require('aws-sdk'); const secretsManager = new AWS.SecretsManager(); const getSecrets = async (secretName) => { var params = { SecretId: secretName }; return await secretsManager.getSecretValue(params).promise(); } const secretsExample = async function () { let URL = "<URL>"; let page = await synthetics.getPage(); log.info(`Navigating to URL: ${URL}`); const response = await page.goto(URL, {waitUntil: 'domcontentloaded', timeout: 30000}); // Fetch secrets let secrets = await getSecrets("secretname") /** * Use secrets to login. * * Assuming secrets are stored in a JSON format like: * { * "username": "<USERNAME>", * "password": "<PASSWORD>" * } **/ let secretsObj = JSON.parse(secrets.SecretString); await synthetics.executeStep('login', async function () { await page.type(">USERNAME-INPUT-SELECTOR<", secretsObj.username); await page.type(">PASSWORD-INPUT-SELECTOR<", secretsObj.password); await Promise.all([ page.waitForNavigation({ timeout: 30000 }), await page.click(">SUBMIT-BUTTON-SELECTOR<") ]); }); // Verify login was successful await synthetics.executeStep('verify', async function () { await page.waitForXPath(">SELECTOR<", { timeout: 30000 }); }); }; exports.handler = async () => { return await secretsExample(); };

Forçar seu canário a usar um endereço IP estático

É possível configurar um canário para que ele use um endereço IP estático.

Para forçar um canário a usar um endereço IP estático
  1. Crie uma nova VPC. Para obter mais informações, consulte Using DNS with Your VPC.

  2. Crie um novo gateway da Internet. Para obter mais informações, consulte Adicionar um gateway da Internet à VPC.

  3. Crie uma sub-rede pública dentro de sua nova VPC.

  4. Adicione uma nova tabela de rotas à VPC.

  5. Adicione uma rota na nova tabela de rotas, que vai de 0.0.0.0/0 ao gateway da Internet.

  6. Associe a nova tabela de rotas à sub-rede pública.

  7. Crie um endereço de IP elástico. Para obter mais informações, consulte Endereços de IP elásticos.

  8. Crie um novo gateway NAT e atribua-o à sub-rede pública e ao endereço de IP elástico.

  9. Crie uma sub-rede privada dentro da VPC.

  10. Adiciona uma rota à tabela de rotas padrão da VPC, que vai de 0.0.0.0/0 ao gateway NAT

  11. Crie um canário.