Escritura de un script de valor controlado Node.js - Amazon CloudWatch

Escritura de un script de valor controlado Node.js

Creación de un valor controlado de CloudWatch Synthetics desde cero

Aquí hay un ejemplo de script mínimo de valor controlado de Synthetics. Este script pasa como una ejecución correcta y devuelve una cadena. Para ver el aspecto de un valor controlado erróneo, cambie let fail = false; a let fail = true;.

Debe definir una función de punto de entrada para el script de valor controlado. Para ver cómo se cargan los archivos en la ubicación especificada de Amazon S3 como la ArtifactS3Location del valor controlado, cree estos archivos en la carpeta /tmp. Después de que el script se ejecuta, el estado superado o no superado y las métricas de duración se ejecutan en CloudWatch y los archivos bajo /tmp se cargan en 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(); };

A continuación, expandiremos el script para usar el registro de Synthetics y realizar una llamada usando el SDK de AWS. A modo de demostración, este script creará un cliente de Amazon DynamoDB y realizará una llamada a las listTables DynamoDB de la API. Registra la respuesta a la solicitud y los registros se superan o no en función de si la solicitud se realizó correctamente.

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(); };

Empaquetado de los archivos de valores controlados de Node.js

Si carga los scripts de valores controlados mediante una ubicación de Amazon S3, el archivo .zip debe incluir el script en esta estructura de carpetas: nodejs/node_modules/myCanaryFilename.js file.

Si tiene más de un solo archivo .js o tiene una dependencia de la que depende su script, puede agruparlos todos en un único archivo ZIP que contenga la estructura de carpetas nodejs/node_modules/myCanaryFilename.js file and other folders and files. Si utiliza syn-nodejs-puppeteer-3.4 o uno posterior, puede optar por colocar los archivos de valores controlados en otra carpeta y crear su estructura de carpetas de la siguiente manera: nodejs/node_modules/myFolder/myCanaryFilename.js file and other folders and files.

Nombre del controlador

Asegúrese de establecer el punto de entrada del script (controlador) del valor controlado como myCanaryFilename.functionName para que coincida con el nombre de archivo del punto de entrada del script. Si utiliza un tiempo de ejecución anterior a syn-nodejs-puppeteer-3.4, el functionName debe ser handler. Si utiliza syn-nodejs-puppeteer-3.4 o uno posterior, puede elegir cualquier nombre de función como el controlador. Si utiliza syn-nodejs-puppeteer-3.4 o uno posterior, también puede almacenar el valor controlado en una carpeta independiente, como nodejs/node_modules/myFolder/my_canary_filename. Si lo almacena en una carpeta independiente, especifique esa ruta en el punto de entrada del script, como myFolder/my_canary_filename.functionName.

Cambio de un script de Puppeteer existente para usarlo como valor controlado de Synthetics

En esta sección se explica cómo tomar scripts de Puppeteer y modificarlos para que se ejecuten como scripts de valor controlado de Synthetics. Para obtener más información acerca de Puppeteer, consulte Puppeteer API v1.14.0.

Comenzaremos con este ejemplo de script de 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(); })();

Los pasos de conversión son los siguientes:

  • Crear y exportar una función de handler. El controlador es la función de punto de entrada para el script. Si utiliza un tiempo de ejecución anterior a syn-nodejs-puppeteer-3.4, la función del controlador debe denominarse handler. Si utiliza syn-nodejs-puppeteer-3.4 o uno posterior, la función puede tener cualquier nombre, pero debe ser el mismo nombre que se usa en el script. Además, si utiliza syn-nodejs-puppeteer-3.4 o uno posterior, puede almacenar los scripts en cualquier carpeta y especificar dicha carpeta como parte del nombre del controlador.

    const basicPuppeteerExample = async function () {}; exports.handler = async () => { return await basicPuppeteerExample(); };
  • Use la dependencia de Synthetics.

    var synthetics = require('Synthetics');
  • Utilice la función de Synthetics.getPage para obtener un objeto Page de Puppeteer.

    const page = await synthetics.getPage();

    El objeto page devuelto por la función Synthetics.getPage tiene los eventos page.on request, response y requestfailed instrumentados para el registro. Synthetics también configura la generación de archivos HAR para las solicitudes y respuestas en la página y agrega el ARN del valor controlado a los encabezados del agente de usuario de las solicitudes salientes en la página.

El script ya está listo para ser ejecutado como un valor controlado de Synthetics. Aquí está el script actualizado:

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(); };

Variables de entorno

Puede utilizar variables de entorno al crear canaries. Esto le permite escribir un único script de valor controlado y luego usar ese script con diferentes valores para crear rápidamente varios valores controlados que tengan una tarea similar.

Suponga, por ejemplo, que su organización tiene puntos de enlaces como prod, dev, y pre-release para las diferentes etapas del desarrollo del software, y que necesita crear canaries para probar cada uno de estos puntos de enlace. Puede escribir un único script de valor controlado que pruebe el software y, a continuación, especificar los valores diferentes para la variable de entorno de punto de conexión cuando cree cada uno de los tres valores controlados. A continuación, cuando se crea un valor controlado, se especifica el script y los valores que se van a utilizar para las variables de entorno.

Los nombres de las variables de entorno pueden contener letras, números y guiones bajos. Deben comenzar con una letra y tener al menos dos caracteres. El tamaño total de las variables de entorno no puede superar los 4 KB. No es posible especificar variables de entorno reservadas de Lambda como claves para sus variables de entorno. Para obtener más información acerca de las variables de entorno reservadas, consulte Runtime environment variables (Variables de entorno en tiempo de ejecución).

importante

Las claves y los valores de las variables de entorno no están cifrados. No guarde información confidencial en ellos.

En el siguiente ejemplo el script utiliza dos variables de entorno. Este script es para un valor controlado que verifica si hay una página web disponible. Utiliza variables de entorno para parametrizar tanto la URL que verifica como el nivel de registro de CloudWatch Synthetics que utiliza.

La siguiente función establece LogLevel al valor de la variable de entorno LOG_LEVEL.

synthetics.setLogLevel(process.env.LOG_LEVEL);

La función establece URL al valor de la variable de entorno URL.

const URL = process.env.URL;

Este es el script completo. Cuando se crea un valor controlado con este script, se especifican los valores para las variables de entorno LOG_LEVEL y 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(); };

Traspaso de las variables de entorno al script

Para pasar variables de entorno al script cuando cree un valor controlado en la consola, especifique las claves y los valores de las variables de entorno en la sección Variables de entorno en la consola. Para obtener más información, consulte Creación de un valor controlado.

Para pasar variables de entorno a través de la API o AWS CLI, utilice el parámetro EnvironmentVariables en la sección RunConfig. A continuación, se observa un ejemplo del comando de AWS CLI que crea un valor controlado que utiliza dos variables de entorno con claves de Environment y 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" }'

Integración del valor controlado con otros servicios de AWS

Todos los canaries pueden utilizar la biblioteca de AWS SDK. Puede utilizar esta biblioteca cuando escriba su valor controlado para integrarlo con otros servicios de AWS.

Para ello, debe agregar el siguiente código al valor controlado. Para estos ejemplos, AWS Secrets Manager se utiliza como servicio para la integración del valor controlado.

  • Importar el SDK de AWS.

    const AWS = require('aws-sdk');
  • Cree un cliente para el servicio de AWS con el que se está integrando.

    const secretsManager = new AWS.SecretsManager();
  • Use el cliente para realizar llamadas a la API a ese servicio.

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

El siguiente fragmento de código de script de valor controlado muestra un ejemplo de integración con Secrets Manager con más detalle.

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(); };

Forzar al valor controlado para que utilice una dirección IP estática

Se puede configurar un valor controlado para que utilice una dirección IP estática.

Para forzar a un valor controlado a utilizar una dirección IP estática
  1. Cree una nueva VPC Para obtener más información, consulte Utilización de DNS con su VPC.

  2. Cree una gateway de Internet. Para obtener más información, consulte Adding an internet gateway to your VPC (Cómo añadir una gateway de Internet a la VPC).

  3. Cree una subred pública en la nueva VPC.

  4. Agregue una nueva tabla de enrutamiento a la VPC.

  5. Agregue una ruta en la nueva tabla de enrutamiento, que va desde 0.0.0.0/0 a la gateway de Internet.

  6. Asocie la nueva tabla de enrutamiento con la subred pública.

  7. Cree una dirección IP elástica Para obtener más información, consulte Elastic IP addresses (Direcciones IP elásticas).

  8. Cree una nueva gateway NAT y asígnela a la subred pública y a la dirección IP elástica.

  9. Cree las subredes privadas en la VPC

  10. Agregue una ruta a la tabla de enrutamiento predeterminada de la VPC, que va desde 0.0.0.0/0 a la gateway NAT

  11. Cree el valor controlado.