Scrittura di uno script canary Node.js utilizzando il runtime Puppeteer
Argomenti
Creazione di un canary CloudWatch Synthetics da zero
Ecco un esempio minimo di script Synthetics canary. Questo script passa come esecuzione riuscita e restituisce una stringa. Per vedere come appare un canary fallito, passare let fail = false; a let fail = true;.
È necessario definire una funzione di punto di ingresso per lo script canary. Per vedere come i file vengono caricati nella posizione Amazon S3 specificata come ArtifactS3Location del canary, crea questi file nella cartella /tmp. Tutti gli artefatti canary devono essere archiviati nella directory /tmp, perché è l'unica scrivibile. Assicurati che il percorso dello screenshot sia impostato su /tmp per tutti gli screenshot o gli altri file creati dallo script. Synthetics carica automaticamente i file nella directory /tmp in un bucket S3.
/tmp/<name>
Dopo l'esecuzione dello script, vengono pubblicati lo stato riuscito/non riuscito e le metriche di durata in CloudWatch, e i file in /tmp vengono caricati su un bucket 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(); };
Successivamente, espanderemo lo script per utilizzare la registrazione Synthetics ed effettuare una chiamata utilizzando l'SDK AWS. A scopo dimostrativo, questo script creerà un client Amazon DynamoDB ed effettuerà una chiamata all'API ListTables DynamoDB. Registra la risposta alla richiesta e i registri passano o falliscono in base all'esito positivo della richiesta.
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 foldersconst 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(); };
Creazione di pacchetti dei file canary
Per syn-nodejs-puppeteer-11.0 e versioni successive
La vecchia struttura di creazione dei pacchetti (per syn-nodejs-puppeteer-10.0 e versioni precedenti) è ancora supportata nelle versioni più recenti.
Crea uno script utilizzando una delle seguenti opzioni:
File .js (sintassi CommonJS)
File .mjs (sintassi dei moduli ES)
Per i moduli ES, utilizza una delle opzioni seguenti:
File .js (sintassi CommonJS)
File .mjs (sintassi dei moduli ES)
La struttura del pacchetto è definita di seguito:
File gestore a livello di root (index.js/index.mjs)
File di configurazione facoltativo (synthetics.json)
Dipendenze aggiuntive in node_modules (se necessario)
Esempio di struttura di impacchettamento:
my_function/ ├── index.mjs ├── synthetics.json ├── helper-utils.mjs └── node_modules/ └── dependencies
Per impacchettare, segui i seguenti passaggi:
Installa le dipendenze (se presenti).
npm installCrea un pacchetto .zip.
zip -r my_deployment_package.zip
Per syn-nodejs-puppeteer-11.0 e versioni precedenti
Quando si utilizza Amazon S3 è richiesta la seguente struttura:
nodejs/ └── node_modules/ └── myCanaryFilename.js
Per aggiungere un supporto facoltativo per le sottocartelle in syn-nodejs-puppeteer-3.4+:
nodejs/ └── node_modules/ └── myFolder/ └── myCanaryFilename.js
Nota
Il percorso del gestore nella configurazione deve corrispondere alla posizione del file.
Nome del gestore
Assicurati di impostare il punto di ingresso dello script del tuo canary (gestore) in modo che myCanaryFilename.functionName corrisponda al nome del file del punto di ingresso dello script. Se utilizzi un runtime precedente a syn-nodejs-puppeteer-3.4, functionName deve corrispondere a handler. Se utilizzi un tempo syn-nodejs-puppeteer-3.4 o successivo, puoi scegliere qualsiasi nome di funzione come gestore. Se utilizzi un tempo syn-nodejs-puppeteer-3.4 o successivo, puoi anche memorizzare il canary in una cartella separata, ad esempio nodejs/node_modules/myFolder/my_canary_filename. Se lo archivi in una cartella separata, definisci il percorso nel punto di ingresso dello script, ad esempio myFolder/my_canary_filename.functionName.
Modifica di uno script Puppeteer esistente da utilizzare come canary di Synthetics
Questa sezione spiega come prendere script Puppeteer e modificarli per essere eseguiti come script canary Synthetics. Per ulteriori informazioni su Puppeteer, consulta Puppeteer API v1.14.0
Inizieremo con questo esempio di script 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(); })();
Le fasi di conversione sono le seguenti:
Creare ed esportare una funzione
handler. Il gestore è la funzione del punto di ingresso per lo script. Se utilizzi un runtime precedente asyn-nodejs-puppeteer-3.4, la funzione del gestore deve essere denominatahandler. Se utilizzi un temposyn-nodejs-puppeteer-3.4o successivo, la funzione può avere un nome qualsiasi, purché corrisponda a quello utilizzato nello script. Inoltre, se utilizzi un temposyn-nodejs-puppeteer-3.4o successivo, puoi archiviare gli script in qualsiasi cartella e definire quest'ultima nel nome del gestore.const basicPuppeteerExample = async function () {}; exports.handler = async () => { return await basicPuppeteerExample(); };Usa la dipendenza
Synthetics.var synthetics = require('Synthetics');Utilizzare la funzione
Synthetics.getPageper ottenere un oggettoPagePuppeteer.const page = await synthetics.getPage();L'oggetto pagina restituito dalla funzione Synthetics.getPage ha gli eventi page.on
request,responseerequestfailedstrumentati per la registrazione. Synthetics imposta anche la generazione di file HAR per le richieste e le risposte nella pagina e aggiunge l'ARN canary alle intestazioni user-agent delle richieste in uscita nella pagina.
Lo script è ora pronto per essere eseguito come Canary di Synthetics. Ecco lo script aggiornato:
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(); };
Variabili di ambiente
Quando crei canary puoi utilizzare le variabili di ambiente. Ciò consente di scrivere un singolo script canary e quindi utilizzare tale script con valori diversi per creare rapidamente più canary che hanno un'attività simile.
Ad esempio, supponiamo che l'organizzazione disponga di endpoint quali prod, dev e pre-release per le diverse fasi dello sviluppo del software ed è necessario creare canary per testare ciascuno di questi endpoint. È possibile scrivere un singolo script canary che testi il software e quindi specificare valori diversi per la variabile di ambiente dell'endpoint quando crei ciascuno dei tre canary. Quindi, quando crei un canary, si specificano lo script e i valori da utilizzare per le variabili di ambiente.
I nomi delle variabili di ambiente possono contenere lettere, numeri e il carattere di sottolineatura. Devono iniziare con una lettera e avere almeno due caratteri. La dimensione totale delle variabili di ambiente non può superare i 4 KB. Non è possibile specificare alcuna variabile di ambiente riservato Lambda come nomi per le variabili di ambiente. Per ulteriori informazioni sulle variabili di ambiente riservate, consulta Variabili di ambiente di runtime.
Importante
Le chiavi e i valori delle variabili di ambiente vengono crittografati quando sono a riposo utilizzando le chiavi AWS KMS proprietarie di AWS. Tuttavia, le variabili di ambiente non vengono crittografate lato client. Non archiviare informazioni sensibili al loro interno.
Lo script di esempio seguente utilizza due variabili di ambiente. Questo script è per un canary che controlla se una pagina Web è disponibile. Utilizza le variabili di ambiente per parametrizzare sia l'URL che controlla che il livello di log di CloudWatch Synthetics utilizzato.
La seguente funzione imposta LogLevel al valore della variabile di ambiente LOG_LEVEL.
synthetics.setLogLevel(process.env.LOG_LEVEL);
Questa funzione imposta URL al valore della variabile di ambiente URL.
const URL = process.env.URL;
Questo è lo script completo. Quando crei un canary utilizzando questo script, si specificano i valori per le variabili di 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(); };
Passare le variabili di ambiente allo script
Per passare le variabili di ambiente allo script quando crei un canary nella console, specifica le chiavi e i valori delle variabili di ambiente nella finestra Environment variables (Variabili di ambiente) della console. Per ulteriori informazioni, consulta Creazione di un Canary.
Per passare variabili di ambiente tramite l'API o AWS CLI, utilizza il parametro EnvironmentVariables nella sezione RunConfig. Di seguito è riportato un comando AWS CLI di esempio che crea un canary che utilizza due variabili di ambiente con chiavi di Environment e Region.
aws synthetics create-canary --cli-input-json '{ "Name":"nameofCanary", "ExecutionRoleArn":"roleArn", "ArtifactS3Location":"s3://amzn-s3-demo-bucket-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" }'
Integrare il tuo Canary con altri servizi AWS
Tutti i canary possono utilizzare la libreria AWS SDK. È possibile utilizzare questa libreria quando si scrive il canary per integrare il canary con altri servizi AWS.
Per fare ciò, è necessario aggiungere il seguente codice al tuo canary. Per questi esempi, Gestione dei segreti AWS viene utilizzato come servizio con cui il canary si sta integrando.
Importa l'SDK AWS.
const AWS = require('aws-sdk');Creare un client per il servizio AWS che si sta integrando.
const secretsManager = new AWS.SecretsManager();Utilizzare il client per effettuare chiamate API a tale servizio.
var params = { SecretId: secretName }; return await secretsManager.getSecretValue(params).promise();
Il seguente frammento di codice di script canary mostra un esempio di integrazione con Secrets Manager in modo più dettagliato.
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(); };
Forzare il canary a utilizzare un indirizzo IP statico
Puoi configurare un canary in modo che utilizzi un indirizzo IP statico.
Per forzare un canary a utilizzare un indirizzo IP statico
Crea un nuovo VPC. Per ulteriori informazioni, vedi Utilizzo del DNS con VPC.
Crea un nuovo gateway Internet. Per ulteriori informazioni, consulta la pagina relativa all'Aggiunta di un gateway Internet al VPC.
Crea una sottorete pubblica all'interno del tuo nuovo VPC.
Aggiungi una nuova tabella di routing al VPC.
Aggiungi un routing nella nuova tabella di routing, che va da
0.0.0.0/0al gateway Internet.Associa la nuova tabella di routing alla sottorete pubblica.
Crea un indirizzo IP elastico. Per ulteriori informazioni, consulta Indirizzi IP elastici.
Crea un nuovo gateway NAT e assegnalo alla sottorete pubblica e all'indirizzo IP elastico.
Per creare una sottorete privata all'interno del VPC.
Aggiungere un routing alla tabella di tabella di routing predefinita del VPC, che va da
0.0.0.0/0al gateway NATCrea il tuo canary.