From 27d583f9aadb67bb1f65921c9711589074570b3e Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 10 Oct 2023 09:22:06 -0300 Subject: [PATCH 01/30] Updating logic --- src/shared/index.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/shared/index.js b/src/shared/index.js index 6504e71..ebe2d8d 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -283,7 +283,22 @@ const getUnhealthyClusters = async (event) => { try { const response = await axios.get(url) const clusterInfo = response.data - if (!url.includes(ports.metagraph_l0_public_port) && clusterInfo.length < 3) { + const isL0Url = url.includes(ports.metagraph_l0_public_port) + + if (isL0Url) { + const anyNodeReady = clusterInfo.some(node => { + return node.state === 'Ready' + }) + + if (!anyNodeReady) { + console.log("All L0 nodes are not ready") + unhealthyClusters.push(url) + } + + continue + } + + if (clusterInfo.length < 3) { console.log(`Less than 3: ${url}`) unhealthyClusters.push(url) continue From bcd0c9cfa973af8482146b661c1b7c39bf44982e Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 31 Oct 2023 14:01:22 -0300 Subject: [PATCH 02/30] Updating monitor scripts --- .idea/.gitignore | 3 + index.js | 72 +- package-lock.json | 2923 ++++++++++++++++++++++ package.json | 1 + src/external/aws/dynamo.js | 89 + src/metagraph-l0/index.js | 24 +- src/shared/index.js | 21 +- src/utils/scripts/create_dynamo_table.sh | 8 + src/utils/types.js | 16 +- yarn.lock | 982 +++++--- 10 files changed, 3744 insertions(+), 395 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 package-lock.json create mode 100644 src/external/aws/dynamo.js create mode 100755 src/utils/scripts/create_dynamo_table.sh diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/index.js b/index.js index e584152..fca3e01 100644 --- a/index.js +++ b/index.js @@ -8,13 +8,15 @@ import { sleep, getAllEC2NodesInstances, deleteSnapshotNotSyncToGL0, - getUnhealthyClusters + getUnhealthyClusters, + checkIfRollbackFinished } from './src/shared/index.js' import { restartL0Nodes } from './src/metagraph-l0/index.js' import { restartCurrencyL1Nodes } from './src/currency-l1/index.js' import { restartDataL1Nodes } from './src/data-l1/index.js' import { createMetagraphRestartSuccessfullyAlert, createMetagraphRestartFailureAlert } from './src/services/opsgenie_service.js' -import { LAYERS, VALID_NETWORKS, RESTART_REASONS } from './src/utils/types.js' +import { LAYERS, VALID_NETWORKS, RESTART_REASONS, DYNAMO_RESTART_STATUS } from './src/utils/types.js' +import { deleteMetagraphRestart, getMetagraphRestartOrCreateNew, upsertMetagraphRestart } from './src/external/aws/dynamo.js' const getLogsNames = () => { const now = moment.utc().format('YYY-MM-DD_HH-mm-ss') @@ -30,21 +32,28 @@ const getLogsNames = () => { } } -const restartNodes = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogName }) => { +const restartNodes = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogName }, currentMetagraphRestart) => { const allEC2NodesIntances = getAllEC2NodesInstances(event) - printSeparatorWithMessage('Killing current processes on nodes') - await killCurrentProcesses(ssmClient, event, allEC2NodesIntances) - printSeparatorWithMessage('Finished') + if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.NEW) { + printSeparatorWithMessage('Killing current processes on nodes') + await killCurrentProcesses(ssmClient, event, allEC2NodesIntances) + printSeparatorWithMessage('Finished') - printSeparatorWithMessage('Deleting snapshots not sent to GL0 on Metagraph') - await deleteSnapshotNotSyncToGL0(ssmClient, event, allEC2NodesIntances) - printSeparatorWithMessage('Finished') + printSeparatorWithMessage('Deleting snapshots not sent to GL0 on Metagraph') + await deleteSnapshotNotSyncToGL0(ssmClient, event, allEC2NodesIntances) + printSeparatorWithMessage('Finished') + } printSeparatorWithMessage('METAGRAPH L0') - const nodeId = await restartL0Nodes(ssmClient, event, l0LogName) + const nodeId = await restartL0Nodes(ssmClient, event, l0LogName, currentMetagraphRestart) printSeparatorWithMessage('Finished') + if (!nodeId || currentMetagraphRestart.status !== DYNAMO_RESTART_STATUS.READY) { + console.log("Genesis node still not ready, skipping") + return + } + if (event.metagraph.include_currency_l1_layer) { printSeparatorWithMessage('CURRENCY L1') await restartCurrencyL1Nodes(ssmClient, event, nodeId, cl1LogName) @@ -119,6 +128,23 @@ const shouldRestartMetagraph = async (event, lastSnapshotTimestamp) => { } } +const getCurrentMetagraphRestart = async (event) => { + printSeparatorWithMessage('GETTING CURRENT METAGRAPH RESTART') + const rollbackFinished = await checkIfRollbackFinished(event) + + let currentMetagraphRestart + if (rollbackFinished) { + currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATUS.READY) + } else { + currentMetagraphRestart = await getMetagraphRestartOrCreateNew(event.metagraph.id) + } + + console.log("Current Metagraph Restart:", JSON.stringify(currentMetagraphRestart)) + printSeparatorWithMessage('Finished') + + return currentMetagraphRestart +} + export const handler = async (event) => { const ssmClient = new SSMClient({ region: event.aws.region }); @@ -138,17 +164,35 @@ export const handler = async (event) => { }; } + const currentMetagraphRestart = await getCurrentMetagraphRestart(event) + if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.ROLLBACK_IN_PROGRESS) { + const lastRestartTimeDiff = moment.utc().diff(moment.utc(currentMetagraphRestart.updatedAt), 'hours') + + if (lastRestartTimeDiff > 3) { + throw new Error("The last restart of metagraph is taking more than 3 hours, please check the logs") + } + + return { + statusCode: 200, + body: JSON.stringify('There is already one ROLLBACK_IN_PROGRESS for this metagraph, please wait this operation could take hours'), + }; + } + printSeparatorWithMessage('STARTING THE RESTART') const logsNames = getLogsNames(); - await restartNodes(ssmClient, event, logsNames) + await restartNodes(ssmClient, event, logsNames, currentMetagraphRestart) - await validateIfAllNodesAreReady(event) + if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.READY) { + await validateIfAllNodesAreReady(event) - await checkIfNewSnapshotsAreProducedAfterRestart(event) + await checkIfNewSnapshotsAreProducedAfterRestart(event) - await createMetagraphRestartSuccessfullyAlert(ssmClient, event, logsNames, shouldRestart.reason) + await createMetagraphRestartSuccessfullyAlert(ssmClient, event, logsNames, `Metagraph need to be restarted: ${shouldRestart.reason}`) + + await deleteMetagraphRestart(event.metagraph.id) + } printSeparatorWithMessage('FINISHED THE RESTART') diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..576ce84 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2923 @@ +{ + "name": "monitor_lambda", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "monitor_lambda", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@aws-sdk/client-ssm": "^3.419.0", + "aws-sdk": "^2.1484.0", + "axios": "^1.5.0", + "moment": "^2.29.4" + } + }, + "node_modules/@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/crc32/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/ie11-detection/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/sha256-js/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/supports-web-crypto/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + } + }, + "node_modules/@aws-crypto/util/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "license": "0BSD" + }, + "node_modules/@aws-sdk/client-ssm": { + "version": "3.419.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.419.0.tgz", + "integrity": "sha512-lIsh/D/NuakWuJLunL/O+EHWx6yWiVk6gYohQpW0UCVSTFBtmZMMX56nbNrXNafnJYUHrd2OcHt1Rfw9NNpRbw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.418.0", + "@aws-sdk/credential-provider-node": "3.418.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "@smithy/util-waiter": "^2.0.9", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sso": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.418.0.tgz", + "integrity": "sha512-fakz3YeSW/kCAOJ5w4ObrrQBxsYO8sU8i6WHLv6iWAsYZKAws2Mqa8g89P61+GitSH4z9waksdLouS6ep78/5A==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/client-sts": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.418.0.tgz", + "integrity": "sha512-L0n0Hw+Pm+BhXTN1bYZ0y4JAMArYgazdHf1nUSlEHndgZicCCuQtlMLxfo3i/IbtWi0dzfZcZ9d/MdAM8p4Jyw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/credential-provider-node": "3.418.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-sdk-sts": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.418.0.tgz", + "integrity": "sha512-e74sS+x63EZUBO+HaI8zor886YdtmULzwKdctsZp5/37Xho1CVUNtEC+fYa69nigBD9afoiH33I4JggaHgrekQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.418.0.tgz", + "integrity": "sha512-LTAeKKV85unlSqGNIeqEZ4N9gufaSoH+670n5YTUEk564zHCkUQW0PJomzLF5jKBco6Yfzv6rPBTukd+x9XWqw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.418.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.418.0.tgz", + "integrity": "sha512-VveTjtSC6m8YXj3fQDkMKEZuHv+CR2Z4u/NAN51Fi4xOtIWUtOBj5rfZ8HmBYoBjRF0DtRlPXuMiNnXAzTctfQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-ini": "3.418.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.418.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.418.0.tgz", + "integrity": "sha512-xPbdm2WKz1oH6pTkrJoUmr3OLuqvvcPYTQX0IIlc31tmDwDWPQjXGGFD/vwZGIZIkKaFpFxVMgAzfFScxox7dw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.418.0.tgz", + "integrity": "sha512-tUF5Hg/HfaU5t+E7IuvohYlodSIlBXa28xAJPPFxhKrUnvP6AIoW6JLazOtCIQjQgJYEUILV29XX+ojUuITcaw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/client-sso": "3.418.0", + "@aws-sdk/token-providers": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.418.0.tgz", + "integrity": "sha512-do7ang565n9p3dS1JdsQY01rUfRx8vkxQqz5M8OlcEHBNiCdi2PvSjNwcBdrv/FKkyIxZb0TImOfBSt40hVdxQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.418.0.tgz", + "integrity": "sha512-LrMTdzalkPw/1ujLCKPLwCGvPMCmT4P+vOZQRbSEVZPnlZk+Aj++aL/RaHou0jL4kJH3zl8iQepriBt4a7UvXQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.418.0.tgz", + "integrity": "sha512-StKGmyPVfoO/wdNTtKemYwoJsqIl4l7oqarQY7VSf2Mp3mqaa+njLViHsQbirYpyqpgUEusOnuTlH5utxJ1NsQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.418.0.tgz", + "integrity": "sha512-kKFrIQglBLUFPbHSDy1+bbe3Na2Kd70JSUC3QLMbUHmqipXN8KeXRfAj7vTv97zXl0WzG0buV++WcNwOm1rFjg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-sdk-sts": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.418.0.tgz", + "integrity": "sha512-cW8ijrCTP+mgihvcq4+TbhAcE/we5lFl4ydRqvTdtcSnYQAVQADg47rnTScQiFsPFEB3NKq7BGeyTJF9MKolPA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-signing": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.418.0.tgz", + "integrity": "sha512-onvs5KoYQE8OlOE740RxWBGtsUyVIgAo0CzRKOQO63ZEYqpL1Os+MS1CGzdNhvQnJgJruE1WW+Ix8fjN30zKPA==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.418.0.tgz", + "integrity": "sha512-Jdcztg9Tal9SEAL0dKRrnpKrm6LFlWmAhvuwv0dQ7bNTJxIxyEFbpqdgy7mpQHsLVZgq1Aad/7gT/72c9igyZw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.418.0.tgz", + "integrity": "sha512-lJRZ/9TjZU6yLz+mAwxJkcJZ6BmyYoIJVo1p5+BN//EFdEmC8/c0c9gXMRzfISV/mqWSttdtccpAyN4/goHTYA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.418.0.tgz", + "integrity": "sha512-9P7Q0VN0hEzTngy3Sz5eya2qEOEf0Q8qf1vB3um0gE6ID6EVAdz/nc/DztfN32MFxk8FeVBrCP5vWdoOzmd72g==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.418.0.tgz", + "integrity": "sha512-y4PQSH+ulfFLY0+FYkaK4qbIaQI9IJNMO2xsxukW6/aNoApNymN1D2FSi2la8Qbp/iPjNDKsG8suNPm9NtsWXQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.418.0.tgz", + "integrity": "sha512-sYSDwRTl7yE7LhHkPzemGzmIXFVHSsi3AQ1KeNEk84eBqxMHHcCc2kqklaBk2roXWe50QDgRMy1ikZUxvtzNHQ==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.418.0.tgz", + "integrity": "sha512-c4p4mc0VV/jIeNH0lsXzhJ1MpWRLuboGtNEpqE4s1Vl9ck2amv9VdUUZUmHbg+bVxlMgRQ4nmiovA4qIrqGuyg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.418.0.tgz", + "integrity": "sha512-BXMskXFtg+dmzSCgmnWOffokxIbPr1lFqa1D9kvM3l3IFRiFGx2IyDg+8MAhq11aPDLvoa/BDuQ0Yqma5izOhg==", + "license": "Apache-2.0", + "dependencies": { + "@aws-sdk/types": "3.418.0", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } + } + }, + "node_modules/@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@smithy/abort-controller": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.9.tgz", + "integrity": "sha512-8liHOEbx99xcy4VndeQNQhyA0LS+e7UqsuRnDTSIA26IKBv/7vA9w09KOd4fgNULrvX0r3WpA6cwsQTRJpSWkg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/config-resolver": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.10.tgz", + "integrity": "sha512-MwToDsCltHjumkCuRn883qoNeJUawc2b8sX9caSn5vLz6J5crU1IklklNxWCaMO2z2nDL91Po4b/aI1eHv5PfA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.12.tgz", + "integrity": "sha512-S3lUNe+2fEFwKcmiQniXGPXt69vaHvQCw8kYQOBL4OvJsgwfpkIYDZdroHbTshYi0M6WaKL26Mw+hvgma6dZqA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/property-provider": "^2.0.10", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/eventstream-codec": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.9.tgz", + "integrity": "sha512-sy0pcbKnawt1iu+qCoSFbs/h9PAaUgvlJEO3lqkE1HFFj4p5RgL98vH+9CyDoj6YY82cG5XsorFmcLqQJHTOYw==", + "license": "Apache-2.0", + "dependencies": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.1.5.tgz", + "integrity": "sha512-BIeCHGfr5JCGN+EMTwZK74ELvjPXOIrI7OLM5OhZJJ6AmZyRv2S9ANJk18AtLwht0TsSm+8WoXIEp8LuxNgUyA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^3.0.5", + "@smithy/querystring-builder": "^2.0.9", + "@smithy/types": "^2.3.3", + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/hash-node": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.9.tgz", + "integrity": "sha512-XP3yWd5wyCtiVmsY5Nuq/FUwyCEQ6YG7DsvRh7ThldNukGpCzyFdP8eivZJVjn4Fx7oYrrOnVoYZ0WEgpW1AvQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/invalid-dependency": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.9.tgz", + "integrity": "sha512-RuJqhYf8nViK96IIO9JbTtjDUuFItVfuuJhWw2yk7fv67yltQ7fZD6IQ2OsHHluoVmstnQJuCg5raXJR696Ubw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-content-length": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.11.tgz", + "integrity": "sha512-Malj4voNTL4+a5ZL3a6+Ij7JTUMTa2R7c3ZIBzMxN5OUUgAspU7uFi1Q97f4B0afVh2joQBAWH5IQJUG25nl8g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.9.tgz", + "integrity": "sha512-72/o8R6AAO4+nyTI6h4z6PYGTSA4dr1M7tZz29U8DEUHuh1YkhC77js0P6RyF9G0wDLuYqxb+Yh0crI5WG2pJg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-serde": "^2.0.9", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-retry": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.12.tgz", + "integrity": "sha512-YQ/ufXX4/d9/+Jf1QQ4J+CVeupC7BW52qldBTvRV33PDX9vxndlAwkFwzBcmnUFC3Hjf1//HW6I77EItcjNSCA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/protocol-http": "^3.0.5", + "@smithy/service-error-classification": "^2.0.2", + "@smithy/types": "^2.3.3", + "@smithy/util-middleware": "^2.0.2", + "@smithy/util-retry": "^2.0.2", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-serde": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.9.tgz", + "integrity": "sha512-GVbauxrr6WmtCaesakktg3t5LR/yDbajpC7KkWc8rtCpddMI4ShAVO5Q6DqwX8MDFi4CLaY8H7eTGcxhl3jbLg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/middleware-stack": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.3.tgz", + "integrity": "sha512-AlhPmbwpkC4lQBVaVHXczmjFvsAhDHhrakqLt038qFLotnJcvDLhmMzAtu23alBeOSkKxkTQq0LsAt2N0WpAbw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-config-provider": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.12.tgz", + "integrity": "sha512-df9y9ywv+JmS40Y60ZqJ4jfZiTCmyHQffwzIqjBjLJLJl0imf9F6DWBd+jiEWHvlohR+sFhyY+KL/qzKgnAq1A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^2.0.10", + "@smithy/shared-ini-file-loader": "^2.0.11", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.5.tgz", + "integrity": "sha512-52uF+BrZaFiBh+NT/bADiVDCQO91T+OwDRsuaAeWZC1mlCXFjAPPQdxeQohtuYOe9m7mPP/xIMNiqbe8jvndHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^2.0.9", + "@smithy/protocol-http": "^3.0.5", + "@smithy/querystring-builder": "^2.0.9", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/property-provider": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.10.tgz", + "integrity": "sha512-YMBVfh0ZMmJtbsUn+WfSwR32iRljZPdRN0Tn2GAcdJ+ejX8WrBXD7Z0jIkQDrQZr8fEuuv5x8WxMIj+qVbsPQw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/protocol-http": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.5.tgz", + "integrity": "sha512-3t3fxj+ip4EPHRC2fQ0JimMxR/qCQ1LSQJjZZVZFgROnFLYWPDgUZqpoi7chr+EzatxJVXF/Rtoi5yLHOWCoZQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-builder": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.9.tgz", + "integrity": "sha512-Yt6CPF4j3j1cuwod/DRflbuXxBFjJm7gAjy6W1RE21Rz5/kfGFqiZBXWmmXwGtnnhiLThYwoHK4S6/TQtnx0Fg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/querystring-parser": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.9.tgz", + "integrity": "sha512-U6z4N743s4vrcxPW8p8+reLV0PjMCYEyb1/wtMVvv3VnbJ74gshdI8SR1sBnEh95cF8TxonmX5IxY25tS9qGfg==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/service-error-classification": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.2.tgz", + "integrity": "sha512-GTUd2j63gKy7A+ggvSdn2hc4sejG7LWfE+ZMF17vzWoNyqERWbRP7HTPS0d0Lwg1p6OQCAzvNigSrEIWVFt6iA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/shared-ini-file-loader": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.11.tgz", + "integrity": "sha512-Sf0u5C5px6eykXi6jImDTp+edvG3REtPjXnFWU/J+b7S2wkXwUqFXqBL5DdM4zC1F+M8u57ZT7NRqDwMOw7/Tw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.9.tgz", + "integrity": "sha512-RkHP0joSI1j2EI+mU55sOi33/aMMkKdL9ZY+SWrPxsiCe1oyzzuy79Tpn8X7uT+t0ilNmQlwPpkP/jUy940pEA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/eventstream-codec": "^2.0.9", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/smithy-client": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.7.tgz", + "integrity": "sha512-r6T/oiBQ8vCbGqObH4/h0YqD0jFB1hAS9KFRmuTfaNJueu/L2hjmjqFjv3PV5lkbNHTgUYraSv4cFQ1naxiELQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/middleware-stack": "^2.0.3", + "@smithy/types": "^2.3.3", + "@smithy/util-stream": "^2.0.12", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.3.tgz", + "integrity": "sha512-zTdIPR9PvFVNRdIKMQu4M5oyTaycIbUqLheQqaOi9rTWPkgjGO2wDBxMA1rBHQB81aqAEv+DbSS4jfKyQMnXRA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/url-parser": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.9.tgz", + "integrity": "sha512-NBnJ0NiY8z6E82Xd5VYUFQfKwK/wA/+QkKmpYUYP+cpH3aCzE6g2gvixd9vQKYjsIdRfNPCf+SFAozt8ljozOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/querystring-parser": "^2.0.9", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-base64": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", + "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.5.0" + } + }, + "node_modules/@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.11.tgz", + "integrity": "sha512-0syV1Mz/mCQ7CG/MHKQfH+w86xq59jpD0EOXv5oe0WBXLmq2lWPpVHl2Y6+jQ+/9fYzyZ5NF+NC/WEIuiv690A==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/property-provider": "^2.0.10", + "@smithy/smithy-client": "^2.1.7", + "@smithy/types": "^2.3.3", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.13.tgz", + "integrity": "sha512-6BtCHYdw5Z8r6KpW8tRCc3yURgvcQwfIEeHhR70BeSOfx8T/TXPPjb8A+K45+KASspa3fzrsSxeIwB0sAeMoHA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/config-resolver": "^2.0.10", + "@smithy/credential-provider-imds": "^2.0.12", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/property-provider": "^2.0.10", + "@smithy/smithy-client": "^2.1.7", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-middleware": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.2.tgz", + "integrity": "sha512-UGPZM+Ja/vke5pc/S8G0LNiHpVirtjppsXO+GK9m9wbzRGzPJTfnZA/gERUUN/AfxEy/8SL7U1kd7u4t2X8K1w==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-retry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.2.tgz", + "integrity": "sha512-ovWiayUB38moZcLhSFFfUgB2IMb7R1JfojU20qSahjxAgfOZvDWme3eOYUMtAVnouZ9kYJiFgHLy27qRH4NeeA==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/service-error-classification": "^2.0.2", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/@smithy/util-stream": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.12.tgz", + "integrity": "sha512-FOCpRLaj6gvSyUC5mJAACT+sPMPmp9sD1o+hVbUH/QxwZfulypA3ZIFdAg/59/IY0d/1Q4CTztsiHEB5LgjN4g==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/types": "^2.3.3", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-utf8": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", + "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@smithy/util-waiter": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.9.tgz", + "integrity": "sha512-Hy9Cs0FtIacC1aVFk98bm/7CYqim9fnHAPRnV/SB2mj02ExYs/9Dn5SrNQmtTBTLCn65KqYnNVBNS8GuGpZOOw==", + "license": "Apache-2.0", + "dependencies": { + "@smithy/abort-controller": "^2.0.9", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sdk": { + "version": "2.1484.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1484.0.tgz", + "integrity": "sha512-emfCmb5j/UtaB7U8tvLpGdVNAlZMg4xZOhoFvL8jBQwIVJyCRyaqcshe31JXTwJdafThn2pNPtQOeYbZJCE0Ow==", + "dependencies": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/aws-sdk/node_modules/uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==", + "license": "MIT" + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "dependencies": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "dependencies": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "funding": [ + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + }, + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + } + ], + "license": "MIT", + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "dependencies": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "dependencies": { + "which-typed-array": "^1.1.11" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, + "node_modules/set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "dependencies": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==", + "license": "MIT" + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, + "node_modules/url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "license": "MIT", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + } + }, + "dependencies": { + "@aws-crypto/crc32": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz", + "integrity": "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==", + "requires": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@aws-crypto/ie11-detection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz", + "integrity": "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==", + "requires": { + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@aws-crypto/sha256-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz", + "integrity": "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==", + "requires": { + "@aws-crypto/ie11-detection": "^3.0.0", + "@aws-crypto/sha256-js": "^3.0.0", + "@aws-crypto/supports-web-crypto": "^3.0.0", + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@aws-crypto/sha256-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz", + "integrity": "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==", + "requires": { + "@aws-crypto/util": "^3.0.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@aws-crypto/supports-web-crypto": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz", + "integrity": "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==", + "requires": { + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@aws-crypto/util": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz", + "integrity": "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==", + "requires": { + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-utf8-browser": "^3.0.0", + "tslib": "^1.11.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "@aws-sdk/client-ssm": { + "version": "3.419.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.419.0.tgz", + "integrity": "sha512-lIsh/D/NuakWuJLunL/O+EHWx6yWiVk6gYohQpW0UCVSTFBtmZMMX56nbNrXNafnJYUHrd2OcHt1Rfw9NNpRbw==", + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/client-sts": "3.418.0", + "@aws-sdk/credential-provider-node": "3.418.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "@smithy/util-waiter": "^2.0.9", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + } + }, + "@aws-sdk/client-sso": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.418.0.tgz", + "integrity": "sha512-fakz3YeSW/kCAOJ5w4ObrrQBxsYO8sU8i6WHLv6iWAsYZKAws2Mqa8g89P61+GitSH4z9waksdLouS6ep78/5A==", + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/client-sts": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.418.0.tgz", + "integrity": "sha512-L0n0Hw+Pm+BhXTN1bYZ0y4JAMArYgazdHf1nUSlEHndgZicCCuQtlMLxfo3i/IbtWi0dzfZcZ9d/MdAM8p4Jyw==", + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/credential-provider-node": "3.418.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-sdk-sts": "3.418.0", + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/region-config-resolver": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/protocol-http": "^3.0.5", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "fast-xml-parser": "4.2.5", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/credential-provider-env": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.418.0.tgz", + "integrity": "sha512-e74sS+x63EZUBO+HaI8zor886YdtmULzwKdctsZp5/37Xho1CVUNtEC+fYa69nigBD9afoiH33I4JggaHgrekQ==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/credential-provider-ini": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.418.0.tgz", + "integrity": "sha512-LTAeKKV85unlSqGNIeqEZ4N9gufaSoH+670n5YTUEk564zHCkUQW0PJomzLF5jKBco6Yfzv6rPBTukd+x9XWqw==", + "requires": { + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.418.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/credential-provider-node": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.418.0.tgz", + "integrity": "sha512-VveTjtSC6m8YXj3fQDkMKEZuHv+CR2Z4u/NAN51Fi4xOtIWUtOBj5rfZ8HmBYoBjRF0DtRlPXuMiNnXAzTctfQ==", + "requires": { + "@aws-sdk/credential-provider-env": "3.418.0", + "@aws-sdk/credential-provider-ini": "3.418.0", + "@aws-sdk/credential-provider-process": "3.418.0", + "@aws-sdk/credential-provider-sso": "3.418.0", + "@aws-sdk/credential-provider-web-identity": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/credential-provider-imds": "^2.0.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/credential-provider-process": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.418.0.tgz", + "integrity": "sha512-xPbdm2WKz1oH6pTkrJoUmr3OLuqvvcPYTQX0IIlc31tmDwDWPQjXGGFD/vwZGIZIkKaFpFxVMgAzfFScxox7dw==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/credential-provider-sso": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.418.0.tgz", + "integrity": "sha512-tUF5Hg/HfaU5t+E7IuvohYlodSIlBXa28xAJPPFxhKrUnvP6AIoW6JLazOtCIQjQgJYEUILV29XX+ojUuITcaw==", + "requires": { + "@aws-sdk/client-sso": "3.418.0", + "@aws-sdk/token-providers": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/credential-provider-web-identity": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.418.0.tgz", + "integrity": "sha512-do7ang565n9p3dS1JdsQY01rUfRx8vkxQqz5M8OlcEHBNiCdi2PvSjNwcBdrv/FKkyIxZb0TImOfBSt40hVdxQ==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/middleware-host-header": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.418.0.tgz", + "integrity": "sha512-LrMTdzalkPw/1ujLCKPLwCGvPMCmT4P+vOZQRbSEVZPnlZk+Aj++aL/RaHou0jL4kJH3zl8iQepriBt4a7UvXQ==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/middleware-logger": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.418.0.tgz", + "integrity": "sha512-StKGmyPVfoO/wdNTtKemYwoJsqIl4l7oqarQY7VSf2Mp3mqaa+njLViHsQbirYpyqpgUEusOnuTlH5utxJ1NsQ==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/middleware-recursion-detection": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.418.0.tgz", + "integrity": "sha512-kKFrIQglBLUFPbHSDy1+bbe3Na2Kd70JSUC3QLMbUHmqipXN8KeXRfAj7vTv97zXl0WzG0buV++WcNwOm1rFjg==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/middleware-sdk-sts": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.418.0.tgz", + "integrity": "sha512-cW8ijrCTP+mgihvcq4+TbhAcE/we5lFl4ydRqvTdtcSnYQAVQADg47rnTScQiFsPFEB3NKq7BGeyTJF9MKolPA==", + "requires": { + "@aws-sdk/middleware-signing": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/middleware-signing": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.418.0.tgz", + "integrity": "sha512-onvs5KoYQE8OlOE740RxWBGtsUyVIgAo0CzRKOQO63ZEYqpL1Os+MS1CGzdNhvQnJgJruE1WW+Ix8fjN30zKPA==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/signature-v4": "^2.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/middleware-user-agent": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.418.0.tgz", + "integrity": "sha512-Jdcztg9Tal9SEAL0dKRrnpKrm6LFlWmAhvuwv0dQ7bNTJxIxyEFbpqdgy7mpQHsLVZgq1Aad/7gT/72c9igyZw==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/region-config-resolver": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.418.0.tgz", + "integrity": "sha512-lJRZ/9TjZU6yLz+mAwxJkcJZ6BmyYoIJVo1p5+BN//EFdEmC8/c0c9gXMRzfISV/mqWSttdtccpAyN4/goHTYA==", + "requires": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/token-providers": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.418.0.tgz", + "integrity": "sha512-9P7Q0VN0hEzTngy3Sz5eya2qEOEf0Q8qf1vB3um0gE6ID6EVAdz/nc/DztfN32MFxk8FeVBrCP5vWdoOzmd72g==", + "requires": { + "@aws-crypto/sha256-browser": "3.0.0", + "@aws-crypto/sha256-js": "3.0.0", + "@aws-sdk/middleware-host-header": "3.418.0", + "@aws-sdk/middleware-logger": "3.418.0", + "@aws-sdk/middleware-recursion-detection": "3.418.0", + "@aws-sdk/middleware-user-agent": "3.418.0", + "@aws-sdk/types": "3.418.0", + "@aws-sdk/util-endpoints": "3.418.0", + "@aws-sdk/util-user-agent-browser": "3.418.0", + "@aws-sdk/util-user-agent-node": "3.418.0", + "@smithy/config-resolver": "^2.0.10", + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/hash-node": "^2.0.9", + "@smithy/invalid-dependency": "^2.0.9", + "@smithy/middleware-content-length": "^2.0.11", + "@smithy/middleware-endpoint": "^2.0.9", + "@smithy/middleware-retry": "^2.0.12", + "@smithy/middleware-serde": "^2.0.9", + "@smithy/middleware-stack": "^2.0.2", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/property-provider": "^2.0.0", + "@smithy/protocol-http": "^3.0.5", + "@smithy/shared-ini-file-loader": "^2.0.6", + "@smithy/smithy-client": "^2.1.6", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-body-length-browser": "^2.0.0", + "@smithy/util-body-length-node": "^2.1.0", + "@smithy/util-defaults-mode-browser": "^2.0.10", + "@smithy/util-defaults-mode-node": "^2.0.12", + "@smithy/util-retry": "^2.0.2", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/types": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.418.0.tgz", + "integrity": "sha512-y4PQSH+ulfFLY0+FYkaK4qbIaQI9IJNMO2xsxukW6/aNoApNymN1D2FSi2la8Qbp/iPjNDKsG8suNPm9NtsWXQ==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/util-endpoints": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.418.0.tgz", + "integrity": "sha512-sYSDwRTl7yE7LhHkPzemGzmIXFVHSsi3AQ1KeNEk84eBqxMHHcCc2kqklaBk2roXWe50QDgRMy1ikZUxvtzNHQ==", + "requires": { + "@aws-sdk/types": "3.418.0", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/util-locate-window": { + "version": "3.310.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz", + "integrity": "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@aws-sdk/util-user-agent-browser": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.418.0.tgz", + "integrity": "sha512-c4p4mc0VV/jIeNH0lsXzhJ1MpWRLuboGtNEpqE4s1Vl9ck2amv9VdUUZUmHbg+bVxlMgRQ4nmiovA4qIrqGuyg==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/types": "^2.3.3", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/util-user-agent-node": { + "version": "3.418.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.418.0.tgz", + "integrity": "sha512-BXMskXFtg+dmzSCgmnWOffokxIbPr1lFqa1D9kvM3l3IFRiFGx2IyDg+8MAhq11aPDLvoa/BDuQ0Yqma5izOhg==", + "requires": { + "@aws-sdk/types": "3.418.0", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@aws-sdk/util-utf8-browser": { + "version": "3.259.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz", + "integrity": "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==", + "requires": { + "tslib": "^2.3.1" + } + }, + "@smithy/abort-controller": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.9.tgz", + "integrity": "sha512-8liHOEbx99xcy4VndeQNQhyA0LS+e7UqsuRnDTSIA26IKBv/7vA9w09KOd4fgNULrvX0r3WpA6cwsQTRJpSWkg==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/config-resolver": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.10.tgz", + "integrity": "sha512-MwToDsCltHjumkCuRn883qoNeJUawc2b8sX9caSn5vLz6J5crU1IklklNxWCaMO2z2nDL91Po4b/aI1eHv5PfA==", + "requires": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/types": "^2.3.3", + "@smithy/util-config-provider": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "@smithy/credential-provider-imds": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.12.tgz", + "integrity": "sha512-S3lUNe+2fEFwKcmiQniXGPXt69vaHvQCw8kYQOBL4OvJsgwfpkIYDZdroHbTshYi0M6WaKL26Mw+hvgma6dZqA==", + "requires": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/property-provider": "^2.0.10", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "tslib": "^2.5.0" + } + }, + "@smithy/eventstream-codec": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.9.tgz", + "integrity": "sha512-sy0pcbKnawt1iu+qCoSFbs/h9PAaUgvlJEO3lqkE1HFFj4p5RgL98vH+9CyDoj6YY82cG5XsorFmcLqQJHTOYw==", + "requires": { + "@aws-crypto/crc32": "3.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-hex-encoding": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/fetch-http-handler": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.1.5.tgz", + "integrity": "sha512-BIeCHGfr5JCGN+EMTwZK74ELvjPXOIrI7OLM5OhZJJ6AmZyRv2S9ANJk18AtLwht0TsSm+8WoXIEp8LuxNgUyA==", + "requires": { + "@smithy/protocol-http": "^3.0.5", + "@smithy/querystring-builder": "^2.0.9", + "@smithy/types": "^2.3.3", + "@smithy/util-base64": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/hash-node": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.9.tgz", + "integrity": "sha512-XP3yWd5wyCtiVmsY5Nuq/FUwyCEQ6YG7DsvRh7ThldNukGpCzyFdP8eivZJVjn4Fx7oYrrOnVoYZ0WEgpW1AvQ==", + "requires": { + "@smithy/types": "^2.3.3", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/invalid-dependency": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.9.tgz", + "integrity": "sha512-RuJqhYf8nViK96IIO9JbTtjDUuFItVfuuJhWw2yk7fv67yltQ7fZD6IQ2OsHHluoVmstnQJuCg5raXJR696Ubw==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/is-array-buffer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz", + "integrity": "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-content-length": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.11.tgz", + "integrity": "sha512-Malj4voNTL4+a5ZL3a6+Ij7JTUMTa2R7c3ZIBzMxN5OUUgAspU7uFi1Q97f4B0afVh2joQBAWH5IQJUG25nl8g==", + "requires": { + "@smithy/protocol-http": "^3.0.5", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-endpoint": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.9.tgz", + "integrity": "sha512-72/o8R6AAO4+nyTI6h4z6PYGTSA4dr1M7tZz29U8DEUHuh1YkhC77js0P6RyF9G0wDLuYqxb+Yh0crI5WG2pJg==", + "requires": { + "@smithy/middleware-serde": "^2.0.9", + "@smithy/types": "^2.3.3", + "@smithy/url-parser": "^2.0.9", + "@smithy/util-middleware": "^2.0.2", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-retry": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.12.tgz", + "integrity": "sha512-YQ/ufXX4/d9/+Jf1QQ4J+CVeupC7BW52qldBTvRV33PDX9vxndlAwkFwzBcmnUFC3Hjf1//HW6I77EItcjNSCA==", + "requires": { + "@smithy/node-config-provider": "^2.0.12", + "@smithy/protocol-http": "^3.0.5", + "@smithy/service-error-classification": "^2.0.2", + "@smithy/types": "^2.3.3", + "@smithy/util-middleware": "^2.0.2", + "@smithy/util-retry": "^2.0.2", + "tslib": "^2.5.0", + "uuid": "^8.3.2" + } + }, + "@smithy/middleware-serde": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.9.tgz", + "integrity": "sha512-GVbauxrr6WmtCaesakktg3t5LR/yDbajpC7KkWc8rtCpddMI4ShAVO5Q6DqwX8MDFi4CLaY8H7eTGcxhl3jbLg==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/middleware-stack": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.3.tgz", + "integrity": "sha512-AlhPmbwpkC4lQBVaVHXczmjFvsAhDHhrakqLt038qFLotnJcvDLhmMzAtu23alBeOSkKxkTQq0LsAt2N0WpAbw==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/node-config-provider": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.12.tgz", + "integrity": "sha512-df9y9ywv+JmS40Y60ZqJ4jfZiTCmyHQffwzIqjBjLJLJl0imf9F6DWBd+jiEWHvlohR+sFhyY+KL/qzKgnAq1A==", + "requires": { + "@smithy/property-provider": "^2.0.10", + "@smithy/shared-ini-file-loader": "^2.0.11", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/node-http-handler": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.5.tgz", + "integrity": "sha512-52uF+BrZaFiBh+NT/bADiVDCQO91T+OwDRsuaAeWZC1mlCXFjAPPQdxeQohtuYOe9m7mPP/xIMNiqbe8jvndHA==", + "requires": { + "@smithy/abort-controller": "^2.0.9", + "@smithy/protocol-http": "^3.0.5", + "@smithy/querystring-builder": "^2.0.9", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/property-provider": { + "version": "2.0.10", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.10.tgz", + "integrity": "sha512-YMBVfh0ZMmJtbsUn+WfSwR32iRljZPdRN0Tn2GAcdJ+ejX8WrBXD7Z0jIkQDrQZr8fEuuv5x8WxMIj+qVbsPQw==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/protocol-http": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.5.tgz", + "integrity": "sha512-3t3fxj+ip4EPHRC2fQ0JimMxR/qCQ1LSQJjZZVZFgROnFLYWPDgUZqpoi7chr+EzatxJVXF/Rtoi5yLHOWCoZQ==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/querystring-builder": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.9.tgz", + "integrity": "sha512-Yt6CPF4j3j1cuwod/DRflbuXxBFjJm7gAjy6W1RE21Rz5/kfGFqiZBXWmmXwGtnnhiLThYwoHK4S6/TQtnx0Fg==", + "requires": { + "@smithy/types": "^2.3.3", + "@smithy/util-uri-escape": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/querystring-parser": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.9.tgz", + "integrity": "sha512-U6z4N743s4vrcxPW8p8+reLV0PjMCYEyb1/wtMVvv3VnbJ74gshdI8SR1sBnEh95cF8TxonmX5IxY25tS9qGfg==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/service-error-classification": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.2.tgz", + "integrity": "sha512-GTUd2j63gKy7A+ggvSdn2hc4sejG7LWfE+ZMF17vzWoNyqERWbRP7HTPS0d0Lwg1p6OQCAzvNigSrEIWVFt6iA==", + "requires": { + "@smithy/types": "^2.3.3" + } + }, + "@smithy/shared-ini-file-loader": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.11.tgz", + "integrity": "sha512-Sf0u5C5px6eykXi6jImDTp+edvG3REtPjXnFWU/J+b7S2wkXwUqFXqBL5DdM4zC1F+M8u57ZT7NRqDwMOw7/Tw==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/signature-v4": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.9.tgz", + "integrity": "sha512-RkHP0joSI1j2EI+mU55sOi33/aMMkKdL9ZY+SWrPxsiCe1oyzzuy79Tpn8X7uT+t0ilNmQlwPpkP/jUy940pEA==", + "requires": { + "@smithy/eventstream-codec": "^2.0.9", + "@smithy/is-array-buffer": "^2.0.0", + "@smithy/types": "^2.3.3", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-middleware": "^2.0.2", + "@smithy/util-uri-escape": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/smithy-client": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.7.tgz", + "integrity": "sha512-r6T/oiBQ8vCbGqObH4/h0YqD0jFB1hAS9KFRmuTfaNJueu/L2hjmjqFjv3PV5lkbNHTgUYraSv4cFQ1naxiELQ==", + "requires": { + "@smithy/middleware-stack": "^2.0.3", + "@smithy/types": "^2.3.3", + "@smithy/util-stream": "^2.0.12", + "tslib": "^2.5.0" + } + }, + "@smithy/types": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.3.3.tgz", + "integrity": "sha512-zTdIPR9PvFVNRdIKMQu4M5oyTaycIbUqLheQqaOi9rTWPkgjGO2wDBxMA1rBHQB81aqAEv+DbSS4jfKyQMnXRA==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/url-parser": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.9.tgz", + "integrity": "sha512-NBnJ0NiY8z6E82Xd5VYUFQfKwK/wA/+QkKmpYUYP+cpH3aCzE6g2gvixd9vQKYjsIdRfNPCf+SFAozt8ljozOw==", + "requires": { + "@smithy/querystring-parser": "^2.0.9", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/util-base64": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz", + "integrity": "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==", + "requires": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-body-length-browser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz", + "integrity": "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-body-length-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz", + "integrity": "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-buffer-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz", + "integrity": "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==", + "requires": { + "@smithy/is-array-buffer": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-config-provider": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz", + "integrity": "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-defaults-mode-browser": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.11.tgz", + "integrity": "sha512-0syV1Mz/mCQ7CG/MHKQfH+w86xq59jpD0EOXv5oe0WBXLmq2lWPpVHl2Y6+jQ+/9fYzyZ5NF+NC/WEIuiv690A==", + "requires": { + "@smithy/property-provider": "^2.0.10", + "@smithy/smithy-client": "^2.1.7", + "@smithy/types": "^2.3.3", + "bowser": "^2.11.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-defaults-mode-node": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.13.tgz", + "integrity": "sha512-6BtCHYdw5Z8r6KpW8tRCc3yURgvcQwfIEeHhR70BeSOfx8T/TXPPjb8A+K45+KASspa3fzrsSxeIwB0sAeMoHA==", + "requires": { + "@smithy/config-resolver": "^2.0.10", + "@smithy/credential-provider-imds": "^2.0.12", + "@smithy/node-config-provider": "^2.0.12", + "@smithy/property-provider": "^2.0.10", + "@smithy/smithy-client": "^2.1.7", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/util-hex-encoding": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz", + "integrity": "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-middleware": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.2.tgz", + "integrity": "sha512-UGPZM+Ja/vke5pc/S8G0LNiHpVirtjppsXO+GK9m9wbzRGzPJTfnZA/gERUUN/AfxEy/8SL7U1kd7u4t2X8K1w==", + "requires": { + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/util-retry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.2.tgz", + "integrity": "sha512-ovWiayUB38moZcLhSFFfUgB2IMb7R1JfojU20qSahjxAgfOZvDWme3eOYUMtAVnouZ9kYJiFgHLy27qRH4NeeA==", + "requires": { + "@smithy/service-error-classification": "^2.0.2", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "@smithy/util-stream": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.12.tgz", + "integrity": "sha512-FOCpRLaj6gvSyUC5mJAACT+sPMPmp9sD1o+hVbUH/QxwZfulypA3ZIFdAg/59/IY0d/1Q4CTztsiHEB5LgjN4g==", + "requires": { + "@smithy/fetch-http-handler": "^2.1.5", + "@smithy/node-http-handler": "^2.1.5", + "@smithy/types": "^2.3.3", + "@smithy/util-base64": "^2.0.0", + "@smithy/util-buffer-from": "^2.0.0", + "@smithy/util-hex-encoding": "^2.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-uri-escape": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz", + "integrity": "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==", + "requires": { + "tslib": "^2.5.0" + } + }, + "@smithy/util-utf8": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz", + "integrity": "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==", + "requires": { + "@smithy/util-buffer-from": "^2.0.0", + "tslib": "^2.5.0" + } + }, + "@smithy/util-waiter": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.9.tgz", + "integrity": "sha512-Hy9Cs0FtIacC1aVFk98bm/7CYqim9fnHAPRnV/SB2mj02ExYs/9Dn5SrNQmtTBTLCn65KqYnNVBNS8GuGpZOOw==", + "requires": { + "@smithy/abort-controller": "^2.0.9", + "@smithy/types": "^2.3.3", + "tslib": "^2.5.0" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "available-typed-arrays": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", + "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + }, + "aws-sdk": { + "version": "2.1484.0", + "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1484.0.tgz", + "integrity": "sha512-emfCmb5j/UtaB7U8tvLpGdVNAlZMg4xZOhoFvL8jBQwIVJyCRyaqcshe31JXTwJdafThn2pNPtQOeYbZJCE0Ow==", + "requires": { + "buffer": "4.9.2", + "events": "1.1.1", + "ieee754": "1.1.13", + "jmespath": "0.16.0", + "querystring": "0.2.0", + "sax": "1.2.1", + "url": "0.10.3", + "util": "^0.12.4", + "uuid": "8.0.0", + "xml2js": "0.5.0" + }, + "dependencies": { + "uuid": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz", + "integrity": "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==" + } + } + }, + "axios": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", + "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "call-bind": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz", + "integrity": "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==", + "requires": { + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.1", + "set-function-length": "^1.1.1" + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "define-data-property": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz", + "integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==", + "requires": { + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "events": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", + "integrity": "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" + }, + "fast-xml-parser": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz", + "integrity": "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==", + "requires": { + "strnum": "^1.0.5" + } + }, + "follow-redirects": { + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + }, + "for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "requires": { + "is-callable": "^1.1.3" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "get-intrinsic": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz", + "integrity": "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==", + "requires": { + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "requires": { + "get-intrinsic": "^1.2.2" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + }, + "is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-typed-array": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz", + "integrity": "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==", + "requires": { + "which-typed-array": "^1.1.11" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "jmespath": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz", + "integrity": "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + }, + "sax": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", + "integrity": "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + }, + "set-function-length": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz", + "integrity": "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==", + "requires": { + "define-data-property": "^1.1.1", + "get-intrinsic": "^1.2.1", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0" + } + }, + "strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "url": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", + "integrity": "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "which-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz", + "integrity": "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==", + "requires": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.4", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" + } + }, + "xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "requires": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + } + } +} diff --git a/package.json b/package.json index 64251dd..da5f71c 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "description": "", "dependencies": { "@aws-sdk/client-ssm": "^3.419.0", + "aws-sdk": "^2.1484.0", "axios": "^1.5.0", "moment": "^2.29.4" } diff --git a/src/external/aws/dynamo.js b/src/external/aws/dynamo.js new file mode 100644 index 0000000..df53ce7 --- /dev/null +++ b/src/external/aws/dynamo.js @@ -0,0 +1,89 @@ +import AWS from 'aws-sdk'; +import moment from 'moment'; +import { + DATE_FORMAT, + DYNAMO_RESTART_STATUS, + DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART +} from '../../utils/types.js' + +const dynamodb = new AWS.DynamoDB(); + +const upsertMetagraphRestart = async (metagraphId, status, updatedAt) => { + const item = { + TableName: DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART, + Item: { + id: { S: metagraphId }, + status: { S: status }, + updated_at: { S: updatedAt || moment.utc().format(DATE_FORMAT) }, + }, + }; + + const metagraphRestart = await dynamodb.putItem(item).promise(); + const { error } = metagraphRestart.$response + if (error) { + throw error + } + + return await getMetagraphRestartOrCreateNew(metagraphId) +} + +const getMetagraphRestartOrCreateNew = async (metagraphId) => { + const params = { + TableName: DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART, + Key: { + id: { S: `${metagraphId}` }, + }, + }; + + + const metagraphRestart = await dynamodb.getItem(params).promise(); + const { error, data } = metagraphRestart.$response; + + if (error) { + console.error(`Error when trying to get information from dynamo: ${err}`) + throw error + } + + const { Item } = data + if (!Item) { + console.log("Could not get status, creating new restart of metagraph...") + const updatedAt = moment.utc().format(DATE_FORMAT) + + return upsertMetagraphRestart(metagraphId, DYNAMO_RESTART_STATUS.NEW, updatedAt) + } + + const status = Item.status.S + const updatedAt = Item.updated_at.S + return { + status, + updatedAt + } + +} + +const deleteMetagraphRestart = async (metagraphId) => { + const params = { + TableName: DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART, + Key: { + id: { S: `${metagraphId}` }, + }, + }; + + + const response = await dynamodb.deleteItem(params).promise(); + const { error, data } = response.$response + + if (error) { + console.error('Error deleting item: ', error); + throw err + } else { + console.log('Item deleted successfully: ', data); + } + +} + +export { + getMetagraphRestartOrCreateNew, + upsertMetagraphRestart, + deleteMetagraphRestart +} \ No newline at end of file diff --git a/src/metagraph-l0/index.js b/src/metagraph-l0/index.js index 29fad51..ed30f96 100644 --- a/src/metagraph-l0/index.js +++ b/src/metagraph-l0/index.js @@ -1,3 +1,4 @@ +import { upsertMetagraphRestart } from '../external/aws/dynamo.js' import { sendCommand, getInformationToJoinNode, @@ -8,7 +9,7 @@ import { saveLogs, getAllEC2NodesInstances } from '../shared/index.js' -import { LAYERS } from '../utils/types.js' +import { DYNAMO_RESTART_STATUS, LAYERS } from '../utils/types.js' const startRollbackFirstNodeL0 = async (ssmClient, event, ec2InstancesIds) => { const l0Keys = await getKeys(ssmClient, event.aws.ec2.instances.genesis.id, LAYERS.L0) @@ -88,13 +89,22 @@ const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2Insta await sendCommand(ssmClient, [...keys, ...commands], ec2InstancesIds) } -const restartL0Nodes = async (ssmClient, event, logName) => { - const allEC2NodesIntances = getAllEC2NodesInstances(event) - await saveLogs(ssmClient, event, logName, LAYERS.L0, allEC2NodesIntances) +const restartL0Nodes = async (ssmClient, event, logName, currentMetagraphRestart) => { + if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.NEW) { + const allEC2NodesIntances = getAllEC2NodesInstances(event) + await saveLogs(ssmClient, event, logName, LAYERS.L0, allEC2NodesIntances) + + printSeparatorWithMessage('Starting rollback genesis l0 node') + await startRollbackFirstNodeL0(ssmClient, event, [event.aws.ec2.instances.genesis.id]) + + console.log("Updating status to ROLLBACK_IN_PROGRESS") + currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATUS.ROLLBACK_IN_PROGRESS) + printSeparatorWithMessage('Finished') + } - printSeparatorWithMessage('Starting rollback genesis l0 node') - await startRollbackFirstNodeL0(ssmClient, event, [event.aws.ec2.instances.genesis.id]) - printSeparatorWithMessage('Finished') + if (currentMetagraphRestart.status !== DYNAMO_RESTART_STATUS.READY) { + return null + } printSeparatorWithMessage('Starting validators L0 nodes') for (const validator of event.aws.ec2.instances.validators) { diff --git a/src/shared/index.js b/src/shared/index.js index ebe2d8d..8077e56 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -324,6 +324,24 @@ const printSeparatorWithMessage = (message) => { console.log(`\n########################## ${message} ###############################\n`) } +const checkIfRollbackFinished = async (event) => { + try { + const { metagraph_l0_public_port } = event.metagraph.ports + const url = `http://${event.aws.ec2.instances.genesis.ip}:${metagraph_l0_public_port}/node/info` + + const response = await axios.get(url) + const nodeState = response.data.state + console.log(`Current state of genesis node: ${nodeState}`) + if (nodeState === 'Ready') { + return true + } + return false + } catch (e) { + console.log("Error when checking node url", e) + return false + } +} + export { sleep, getLastMetagraphInfo, @@ -339,5 +357,6 @@ export { checkIfAllNodesAreReady, getAllEC2NodesInstances, deleteSnapshotNotSyncToGL0, - getUnhealthyClusters + getUnhealthyClusters, + checkIfRollbackFinished } \ No newline at end of file diff --git a/src/utils/scripts/create_dynamo_table.sh b/src/utils/scripts/create_dynamo_table.sh new file mode 100755 index 0000000..a662c15 --- /dev/null +++ b/src/utils/scripts/create_dynamo_table.sh @@ -0,0 +1,8 @@ +aws dynamodb create-table \ + --table-name metagraph_auto_restart \ + --attribute-definitions \ + AttributeName=id,AttributeType=S \ + --key-schema \ + AttributeName=id,KeyType=HASH \ + --provisioned-throughput \ + ReadCapacityUnits=5,WriteCapacityUnits=5 \ No newline at end of file diff --git a/src/utils/types.js b/src/utils/types.js index 57bf66d..7f226b6 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -6,13 +6,27 @@ const LAYERS = { const VALID_NETWORKS = ['mainnet', 'integrationnet', 'testnet'] +const DATE_FORMAT = "YYYY-MM-DDTHH:mm:ssZ" + const RESTART_REASONS = { STOP_PRODUCING_SNAPSHOTS: "Metagraph stop producing snapshots", FORCE_METAGRAPH_RESTART: "Force metagraph restart provided", UNHEALTHY_CLUSTER: "One of the clusters are unhealthy (less than 3 nodes or nodes with not Ready status)" } + +const DYNAMO_RESTART_STATUS = { + NEW: 'NEW', + ROLLBACK_IN_PROGRESS: "ROLLBACK IN PROGRESS", + READY: 'READY' +} + +const DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART = 'metagraph_auto_restart' + export { LAYERS, VALID_NETWORKS, - RESTART_REASONS + DATE_FORMAT, + RESTART_REASONS, + DYNAMO_RESTART_STATUS, + DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index d61fc83..438ce99 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3,25 +3,25 @@ "@aws-crypto/crc32@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@aws-crypto/crc32/-/crc32-3.0.0.tgz#07300eca214409c33e3ff769cd5697b57fdd38fa" - integrity sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA== + "integrity" "sha512-IzSgsrxUcsrejQbPVilIKy16kAT52EwB6zSaI+M3xxIhKh5+aldEyvI+z6erM7TCLB2BJsFrtHjp6/4/sr+3dA==" + "resolved" "https://registry.npmjs.org/@aws-crypto/crc32/-/crc32-3.0.0.tgz" + "version" "3.0.0" dependencies: "@aws-crypto/util" "^3.0.0" "@aws-sdk/types" "^3.222.0" - tslib "^1.11.1" + "tslib" "^1.11.1" "@aws-crypto/ie11-detection@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz#640ae66b4ec3395cee6a8e94ebcd9f80c24cd688" - integrity sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q== + "integrity" "sha512-341lBBkiY1DfDNKai/wXM3aujNBkXR7tq1URPQDL9wi3AUbI80NR74uF1TXHMm7po1AcnFk8iu2S2IeU/+/A+Q==" + "resolved" "https://registry.npmjs.org/@aws-crypto/ie11-detection/-/ie11-detection-3.0.0.tgz" + "version" "3.0.0" dependencies: - tslib "^1.11.1" + "tslib" "^1.11.1" "@aws-crypto/sha256-browser@3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz#05f160138ab893f1c6ba5be57cfd108f05827766" - integrity sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ== + "integrity" "sha512-8VLmW2B+gjFbU5uMeqtQM6Nj0/F1bro80xQXCW6CQBWgosFWXTx77aeOF5CAIAmbOK64SdMBJdNr6J41yP5mvQ==" + "resolved" "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-3.0.0.tgz" + "version" "3.0.0" dependencies: "@aws-crypto/ie11-detection" "^3.0.0" "@aws-crypto/sha256-js" "^3.0.0" @@ -30,37 +30,37 @@ "@aws-sdk/types" "^3.222.0" "@aws-sdk/util-locate-window" "^3.0.0" "@aws-sdk/util-utf8-browser" "^3.0.0" - tslib "^1.11.1" + "tslib" "^1.11.1" -"@aws-crypto/sha256-js@3.0.0", "@aws-crypto/sha256-js@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz#f06b84d550d25521e60d2a0e2a90139341e007c2" - integrity sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ== +"@aws-crypto/sha256-js@^3.0.0", "@aws-crypto/sha256-js@3.0.0": + "integrity" "sha512-PnNN7os0+yd1XvXAy23CFOmTbMaDxgxXtTKHybrJ39Y8kGzBATgBFibWJKH6BhytLI/Zyszs87xCOBNyBig6vQ==" + "resolved" "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-3.0.0.tgz" + "version" "3.0.0" dependencies: "@aws-crypto/util" "^3.0.0" "@aws-sdk/types" "^3.222.0" - tslib "^1.11.1" + "tslib" "^1.11.1" "@aws-crypto/supports-web-crypto@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz#5d1bf825afa8072af2717c3e455f35cda0103ec2" - integrity sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg== + "integrity" "sha512-06hBdMwUAb2WFTuGG73LSC0wfPu93xWwo5vL2et9eymgmu3Id5vFAHBbajVWiGhPO37qcsdCap/FqXvJGJWPIg==" + "resolved" "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-3.0.0.tgz" + "version" "3.0.0" dependencies: - tslib "^1.11.1" + "tslib" "^1.11.1" "@aws-crypto/util@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@aws-crypto/util/-/util-3.0.0.tgz#1c7ca90c29293f0883468ad48117937f0fe5bfb0" - integrity sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w== + "integrity" "sha512-2OJlpeJpCR48CC8r+uKVChzs9Iungj9wkZrl8Z041DWEWvyIHILYKCPNzJghKsivj+S3mLo6BVc7mBNzdxA46w==" + "resolved" "https://registry.npmjs.org/@aws-crypto/util/-/util-3.0.0.tgz" + "version" "3.0.0" dependencies: "@aws-sdk/types" "^3.222.0" "@aws-sdk/util-utf8-browser" "^3.0.0" - tslib "^1.11.1" + "tslib" "^1.11.1" "@aws-sdk/client-ssm@^3.419.0": - version "3.419.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-ssm/-/client-ssm-3.419.0.tgz#49d8f1d7687cc278c0b3d772f4ed26cc1fd2160a" - integrity sha512-lIsh/D/NuakWuJLunL/O+EHWx6yWiVk6gYohQpW0UCVSTFBtmZMMX56nbNrXNafnJYUHrd2OcHt1Rfw9NNpRbw== + "integrity" "sha512-lIsh/D/NuakWuJLunL/O+EHWx6yWiVk6gYohQpW0UCVSTFBtmZMMX56nbNrXNafnJYUHrd2OcHt1Rfw9NNpRbw==" + "resolved" "https://registry.npmjs.org/@aws-sdk/client-ssm/-/client-ssm-3.419.0.tgz" + "version" "3.419.0" dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" @@ -99,13 +99,13 @@ "@smithy/util-retry" "^2.0.2" "@smithy/util-utf8" "^2.0.0" "@smithy/util-waiter" "^2.0.9" - tslib "^2.5.0" - uuid "^8.3.2" + "tslib" "^2.5.0" + "uuid" "^8.3.2" "@aws-sdk/client-sso@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sso/-/client-sso-3.418.0.tgz#c303ef8d3721b78a186f1079029c800b923a8db7" - integrity sha512-fakz3YeSW/kCAOJ5w4ObrrQBxsYO8sU8i6WHLv6iWAsYZKAws2Mqa8g89P61+GitSH4z9waksdLouS6ep78/5A== + "integrity" "sha512-fakz3YeSW/kCAOJ5w4ObrrQBxsYO8sU8i6WHLv6iWAsYZKAws2Mqa8g89P61+GitSH4z9waksdLouS6ep78/5A==" + "resolved" "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" @@ -140,12 +140,12 @@ "@smithy/util-defaults-mode-node" "^2.0.12" "@smithy/util-retry" "^2.0.2" "@smithy/util-utf8" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/client-sts@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/client-sts/-/client-sts-3.418.0.tgz#20cb08ea7e50e466cfa6559528fc20c95cfe0e51" - integrity sha512-L0n0Hw+Pm+BhXTN1bYZ0y4JAMArYgazdHf1nUSlEHndgZicCCuQtlMLxfo3i/IbtWi0dzfZcZ9d/MdAM8p4Jyw== + "integrity" "sha512-L0n0Hw+Pm+BhXTN1bYZ0y4JAMArYgazdHf1nUSlEHndgZicCCuQtlMLxfo3i/IbtWi0dzfZcZ9d/MdAM8p4Jyw==" + "resolved" "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" @@ -183,23 +183,23 @@ "@smithy/util-defaults-mode-node" "^2.0.12" "@smithy/util-retry" "^2.0.2" "@smithy/util-utf8" "^2.0.0" - fast-xml-parser "4.2.5" - tslib "^2.5.0" + "fast-xml-parser" "4.2.5" + "tslib" "^2.5.0" "@aws-sdk/credential-provider-env@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-env/-/credential-provider-env-3.418.0.tgz#7b14169350d9c14c9f656da06edf46f40a224ed2" - integrity sha512-e74sS+x63EZUBO+HaI8zor886YdtmULzwKdctsZp5/37Xho1CVUNtEC+fYa69nigBD9afoiH33I4JggaHgrekQ== + "integrity" "sha512-e74sS+x63EZUBO+HaI8zor886YdtmULzwKdctsZp5/37Xho1CVUNtEC+fYa69nigBD9afoiH33I4JggaHgrekQ==" + "resolved" "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/credential-provider-ini@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.418.0.tgz#93d431eef20af22294321351ed7bc0d2c272f25a" - integrity sha512-LTAeKKV85unlSqGNIeqEZ4N9gufaSoH+670n5YTUEk564zHCkUQW0PJomzLF5jKBco6Yfzv6rPBTukd+x9XWqw== + "integrity" "sha512-LTAeKKV85unlSqGNIeqEZ4N9gufaSoH+670n5YTUEk564zHCkUQW0PJomzLF5jKBco6Yfzv6rPBTukd+x9XWqw==" + "resolved" "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/credential-provider-env" "3.418.0" "@aws-sdk/credential-provider-process" "3.418.0" @@ -210,12 +210,12 @@ "@smithy/property-provider" "^2.0.0" "@smithy/shared-ini-file-loader" "^2.0.6" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/credential-provider-node@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-node/-/credential-provider-node-3.418.0.tgz#8cc6d1a65a9564d924258bccbac51d23d3384610" - integrity sha512-VveTjtSC6m8YXj3fQDkMKEZuHv+CR2Z4u/NAN51Fi4xOtIWUtOBj5rfZ8HmBYoBjRF0DtRlPXuMiNnXAzTctfQ== + "integrity" "sha512-VveTjtSC6m8YXj3fQDkMKEZuHv+CR2Z4u/NAN51Fi4xOtIWUtOBj5rfZ8HmBYoBjRF0DtRlPXuMiNnXAzTctfQ==" + "resolved" "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/credential-provider-env" "3.418.0" "@aws-sdk/credential-provider-ini" "3.418.0" @@ -227,23 +227,23 @@ "@smithy/property-provider" "^2.0.0" "@smithy/shared-ini-file-loader" "^2.0.6" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/credential-provider-process@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-process/-/credential-provider-process-3.418.0.tgz#1cb6d816bd471db3f9724715b007035ef18b5b2b" - integrity sha512-xPbdm2WKz1oH6pTkrJoUmr3OLuqvvcPYTQX0IIlc31tmDwDWPQjXGGFD/vwZGIZIkKaFpFxVMgAzfFScxox7dw== + "integrity" "sha512-xPbdm2WKz1oH6pTkrJoUmr3OLuqvvcPYTQX0IIlc31tmDwDWPQjXGGFD/vwZGIZIkKaFpFxVMgAzfFScxox7dw==" + "resolved" "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" "@smithy/shared-ini-file-loader" "^2.0.6" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/credential-provider-sso@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.418.0.tgz#7c43430663ded333e063e64f616bdff9a9fa0e7e" - integrity sha512-tUF5Hg/HfaU5t+E7IuvohYlodSIlBXa28xAJPPFxhKrUnvP6AIoW6JLazOtCIQjQgJYEUILV29XX+ojUuITcaw== + "integrity" "sha512-tUF5Hg/HfaU5t+E7IuvohYlodSIlBXa28xAJPPFxhKrUnvP6AIoW6JLazOtCIQjQgJYEUILV29XX+ojUuITcaw==" + "resolved" "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/client-sso" "3.418.0" "@aws-sdk/token-providers" "3.418.0" @@ -251,61 +251,61 @@ "@smithy/property-provider" "^2.0.0" "@smithy/shared-ini-file-loader" "^2.0.6" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/credential-provider-web-identity@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.418.0.tgz#c2aed2a79bf193c1fef2b98391aaa9de7336aaaf" - integrity sha512-do7ang565n9p3dS1JdsQY01rUfRx8vkxQqz5M8OlcEHBNiCdi2PvSjNwcBdrv/FKkyIxZb0TImOfBSt40hVdxQ== + "integrity" "sha512-do7ang565n9p3dS1JdsQY01rUfRx8vkxQqz5M8OlcEHBNiCdi2PvSjNwcBdrv/FKkyIxZb0TImOfBSt40hVdxQ==" + "resolved" "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/middleware-host-header@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-host-header/-/middleware-host-header-3.418.0.tgz#35d682e14f36c9d9d7464c7c1dd582bf6611436d" - integrity sha512-LrMTdzalkPw/1ujLCKPLwCGvPMCmT4P+vOZQRbSEVZPnlZk+Aj++aL/RaHou0jL4kJH3zl8iQepriBt4a7UvXQ== + "integrity" "sha512-LrMTdzalkPw/1ujLCKPLwCGvPMCmT4P+vOZQRbSEVZPnlZk+Aj++aL/RaHou0jL4kJH3zl8iQepriBt4a7UvXQ==" + "resolved" "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/protocol-http" "^3.0.5" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/middleware-logger@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-logger/-/middleware-logger-3.418.0.tgz#08d7419f4220c36032a070a7dbb8bbf7e744a9ce" - integrity sha512-StKGmyPVfoO/wdNTtKemYwoJsqIl4l7oqarQY7VSf2Mp3mqaa+njLViHsQbirYpyqpgUEusOnuTlH5utxJ1NsQ== + "integrity" "sha512-StKGmyPVfoO/wdNTtKemYwoJsqIl4l7oqarQY7VSf2Mp3mqaa+njLViHsQbirYpyqpgUEusOnuTlH5utxJ1NsQ==" + "resolved" "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/middleware-recursion-detection@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.418.0.tgz#2bb80d084f946846ad4907f3d6e0b451787d62b1" - integrity sha512-kKFrIQglBLUFPbHSDy1+bbe3Na2Kd70JSUC3QLMbUHmqipXN8KeXRfAj7vTv97zXl0WzG0buV++WcNwOm1rFjg== + "integrity" "sha512-kKFrIQglBLUFPbHSDy1+bbe3Na2Kd70JSUC3QLMbUHmqipXN8KeXRfAj7vTv97zXl0WzG0buV++WcNwOm1rFjg==" + "resolved" "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/protocol-http" "^3.0.5" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/middleware-sdk-sts@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.418.0.tgz#f167f16050e055282ddd60226a2216c84873d464" - integrity sha512-cW8ijrCTP+mgihvcq4+TbhAcE/we5lFl4ydRqvTdtcSnYQAVQADg47rnTScQiFsPFEB3NKq7BGeyTJF9MKolPA== + "integrity" "sha512-cW8ijrCTP+mgihvcq4+TbhAcE/we5lFl4ydRqvTdtcSnYQAVQADg47rnTScQiFsPFEB3NKq7BGeyTJF9MKolPA==" + "resolved" "https://registry.npmjs.org/@aws-sdk/middleware-sdk-sts/-/middleware-sdk-sts-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/middleware-signing" "3.418.0" "@aws-sdk/types" "3.418.0" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/middleware-signing@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-signing/-/middleware-signing-3.418.0.tgz#c7242b84069067bb671cb4191d412b59713a375e" - integrity sha512-onvs5KoYQE8OlOE740RxWBGtsUyVIgAo0CzRKOQO63ZEYqpL1Os+MS1CGzdNhvQnJgJruE1WW+Ix8fjN30zKPA== + "integrity" "sha512-onvs5KoYQE8OlOE740RxWBGtsUyVIgAo0CzRKOQO63ZEYqpL1Os+MS1CGzdNhvQnJgJruE1WW+Ix8fjN30zKPA==" + "resolved" "https://registry.npmjs.org/@aws-sdk/middleware-signing/-/middleware-signing-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/property-provider" "^2.0.0" @@ -313,34 +313,34 @@ "@smithy/signature-v4" "^2.0.0" "@smithy/types" "^2.3.3" "@smithy/util-middleware" "^2.0.2" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/middleware-user-agent@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.418.0.tgz#37426cf801332165fb170b1fd62dea8bb967a1ef" - integrity sha512-Jdcztg9Tal9SEAL0dKRrnpKrm6LFlWmAhvuwv0dQ7bNTJxIxyEFbpqdgy7mpQHsLVZgq1Aad/7gT/72c9igyZw== + "integrity" "sha512-Jdcztg9Tal9SEAL0dKRrnpKrm6LFlWmAhvuwv0dQ7bNTJxIxyEFbpqdgy7mpQHsLVZgq1Aad/7gT/72c9igyZw==" + "resolved" "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@aws-sdk/util-endpoints" "3.418.0" "@smithy/protocol-http" "^3.0.5" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/region-config-resolver@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/region-config-resolver/-/region-config-resolver-3.418.0.tgz#53b99e4bd92f3369f51e9a76534b7d884db67526" - integrity sha512-lJRZ/9TjZU6yLz+mAwxJkcJZ6BmyYoIJVo1p5+BN//EFdEmC8/c0c9gXMRzfISV/mqWSttdtccpAyN4/goHTYA== + "integrity" "sha512-lJRZ/9TjZU6yLz+mAwxJkcJZ6BmyYoIJVo1p5+BN//EFdEmC8/c0c9gXMRzfISV/mqWSttdtccpAyN4/goHTYA==" + "resolved" "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.418.0.tgz" + "version" "3.418.0" dependencies: "@smithy/node-config-provider" "^2.0.12" "@smithy/types" "^2.3.3" "@smithy/util-config-provider" "^2.0.0" "@smithy/util-middleware" "^2.0.2" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/token-providers@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/token-providers/-/token-providers-3.418.0.tgz#cbfac922df397e72daf6dbdd8c1e9a140df0aa0e" - integrity sha512-9P7Q0VN0hEzTngy3Sz5eya2qEOEf0Q8qf1vB3um0gE6ID6EVAdz/nc/DztfN32MFxk8FeVBrCP5vWdoOzmd72g== + "integrity" "sha512-9P7Q0VN0hEzTngy3Sz5eya2qEOEf0Q8qf1vB3um0gE6ID6EVAdz/nc/DztfN32MFxk8FeVBrCP5vWdoOzmd72g==" + "resolved" "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-crypto/sha256-browser" "3.0.0" "@aws-crypto/sha256-js" "3.0.0" @@ -376,158 +376,158 @@ "@smithy/util-defaults-mode-node" "^2.0.12" "@smithy/util-retry" "^2.0.2" "@smithy/util-utf8" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" -"@aws-sdk/types@3.418.0", "@aws-sdk/types@^3.222.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/types/-/types-3.418.0.tgz#c23213110b0c313d5546c810da032a441682f49a" - integrity sha512-y4PQSH+ulfFLY0+FYkaK4qbIaQI9IJNMO2xsxukW6/aNoApNymN1D2FSi2la8Qbp/iPjNDKsG8suNPm9NtsWXQ== +"@aws-sdk/types@^3.222.0", "@aws-sdk/types@3.418.0": + "integrity" "sha512-y4PQSH+ulfFLY0+FYkaK4qbIaQI9IJNMO2xsxukW6/aNoApNymN1D2FSi2la8Qbp/iPjNDKsG8suNPm9NtsWXQ==" + "resolved" "https://registry.npmjs.org/@aws-sdk/types/-/types-3.418.0.tgz" + "version" "3.418.0" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/util-endpoints@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-endpoints/-/util-endpoints-3.418.0.tgz#462c976f054fe260562d4d2844152a04dd883fd7" - integrity sha512-sYSDwRTl7yE7LhHkPzemGzmIXFVHSsi3AQ1KeNEk84eBqxMHHcCc2kqklaBk2roXWe50QDgRMy1ikZUxvtzNHQ== + "integrity" "sha512-sYSDwRTl7yE7LhHkPzemGzmIXFVHSsi3AQ1KeNEk84eBqxMHHcCc2kqklaBk2roXWe50QDgRMy1ikZUxvtzNHQ==" + "resolved" "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/util-locate-window@^3.0.0": - version "3.310.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz#b071baf050301adee89051032bd4139bba32cc40" - integrity sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w== + "integrity" "sha512-qo2t/vBTnoXpjKxlsC2e1gBrRm80M3bId27r0BRB2VniSSe7bL1mmzM+/HFtujm0iAxtPM+aLEflLJlJeDPg0w==" + "resolved" "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.310.0.tgz" + "version" "3.310.0" dependencies: - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/util-user-agent-browser@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.418.0.tgz#dc76b8e7e5cae3f827d68cd4a3ee30c0d475a39c" - integrity sha512-c4p4mc0VV/jIeNH0lsXzhJ1MpWRLuboGtNEpqE4s1Vl9ck2amv9VdUUZUmHbg+bVxlMgRQ4nmiovA4qIrqGuyg== + "integrity" "sha512-c4p4mc0VV/jIeNH0lsXzhJ1MpWRLuboGtNEpqE4s1Vl9ck2amv9VdUUZUmHbg+bVxlMgRQ4nmiovA4qIrqGuyg==" + "resolved" "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/types" "^2.3.3" - bowser "^2.11.0" - tslib "^2.5.0" + "bowser" "^2.11.0" + "tslib" "^2.5.0" "@aws-sdk/util-user-agent-node@3.418.0": - version "3.418.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.418.0.tgz#7d5a1c82ce3265ff0f70b13d58d08593113ab99a" - integrity sha512-BXMskXFtg+dmzSCgmnWOffokxIbPr1lFqa1D9kvM3l3IFRiFGx2IyDg+8MAhq11aPDLvoa/BDuQ0Yqma5izOhg== + "integrity" "sha512-BXMskXFtg+dmzSCgmnWOffokxIbPr1lFqa1D9kvM3l3IFRiFGx2IyDg+8MAhq11aPDLvoa/BDuQ0Yqma5izOhg==" + "resolved" "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.418.0.tgz" + "version" "3.418.0" dependencies: "@aws-sdk/types" "3.418.0" "@smithy/node-config-provider" "^2.0.12" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@aws-sdk/util-utf8-browser@^3.0.0": - version "3.259.0" - resolved "https://registry.yarnpkg.com/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz#3275a6f5eb334f96ca76635b961d3c50259fd9ff" - integrity sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw== + "integrity" "sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==" + "resolved" "https://registry.npmjs.org/@aws-sdk/util-utf8-browser/-/util-utf8-browser-3.259.0.tgz" + "version" "3.259.0" dependencies: - tslib "^2.3.1" + "tslib" "^2.3.1" "@smithy/abort-controller@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/abort-controller/-/abort-controller-2.0.9.tgz#f4b9ce1a9a09d446cf24d8bc1abc2b3b524cd7cd" - integrity sha512-8liHOEbx99xcy4VndeQNQhyA0LS+e7UqsuRnDTSIA26IKBv/7vA9w09KOd4fgNULrvX0r3WpA6cwsQTRJpSWkg== + "integrity" "sha512-8liHOEbx99xcy4VndeQNQhyA0LS+e7UqsuRnDTSIA26IKBv/7vA9w09KOd4fgNULrvX0r3WpA6cwsQTRJpSWkg==" + "resolved" "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/config-resolver@^2.0.10": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@smithy/config-resolver/-/config-resolver-2.0.10.tgz#974de532e6048d86b8b7aa1fed17a75c558c41c8" - integrity sha512-MwToDsCltHjumkCuRn883qoNeJUawc2b8sX9caSn5vLz6J5crU1IklklNxWCaMO2z2nDL91Po4b/aI1eHv5PfA== + "integrity" "sha512-MwToDsCltHjumkCuRn883qoNeJUawc2b8sX9caSn5vLz6J5crU1IklklNxWCaMO2z2nDL91Po4b/aI1eHv5PfA==" + "resolved" "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-2.0.10.tgz" + "version" "2.0.10" dependencies: "@smithy/node-config-provider" "^2.0.12" "@smithy/types" "^2.3.3" "@smithy/util-config-provider" "^2.0.0" "@smithy/util-middleware" "^2.0.2" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/credential-provider-imds@^2.0.0", "@smithy/credential-provider-imds@^2.0.12": - version "2.0.12" - resolved "https://registry.yarnpkg.com/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.12.tgz#787dc731903dd1b07f5e35e6c1d63ca74d1d3356" - integrity sha512-S3lUNe+2fEFwKcmiQniXGPXt69vaHvQCw8kYQOBL4OvJsgwfpkIYDZdroHbTshYi0M6WaKL26Mw+hvgma6dZqA== + "integrity" "sha512-S3lUNe+2fEFwKcmiQniXGPXt69vaHvQCw8kYQOBL4OvJsgwfpkIYDZdroHbTshYi0M6WaKL26Mw+hvgma6dZqA==" + "resolved" "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-2.0.12.tgz" + "version" "2.0.12" dependencies: "@smithy/node-config-provider" "^2.0.12" "@smithy/property-provider" "^2.0.10" "@smithy/types" "^2.3.3" "@smithy/url-parser" "^2.0.9" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/eventstream-codec@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/eventstream-codec/-/eventstream-codec-2.0.9.tgz#aa588d4083c9a16f14896d780e2fff0b34ef2c35" - integrity sha512-sy0pcbKnawt1iu+qCoSFbs/h9PAaUgvlJEO3lqkE1HFFj4p5RgL98vH+9CyDoj6YY82cG5XsorFmcLqQJHTOYw== + "integrity" "sha512-sy0pcbKnawt1iu+qCoSFbs/h9PAaUgvlJEO3lqkE1HFFj4p5RgL98vH+9CyDoj6YY82cG5XsorFmcLqQJHTOYw==" + "resolved" "https://registry.npmjs.org/@smithy/eventstream-codec/-/eventstream-codec-2.0.9.tgz" + "version" "2.0.9" dependencies: "@aws-crypto/crc32" "3.0.0" "@smithy/types" "^2.3.3" "@smithy/util-hex-encoding" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/fetch-http-handler@^2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@smithy/fetch-http-handler/-/fetch-http-handler-2.1.5.tgz#0764e232482320b9f2f8ec9c79ebdfa214a761fb" - integrity sha512-BIeCHGfr5JCGN+EMTwZK74ELvjPXOIrI7OLM5OhZJJ6AmZyRv2S9ANJk18AtLwht0TsSm+8WoXIEp8LuxNgUyA== + "integrity" "sha512-BIeCHGfr5JCGN+EMTwZK74ELvjPXOIrI7OLM5OhZJJ6AmZyRv2S9ANJk18AtLwht0TsSm+8WoXIEp8LuxNgUyA==" + "resolved" "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-2.1.5.tgz" + "version" "2.1.5" dependencies: "@smithy/protocol-http" "^3.0.5" "@smithy/querystring-builder" "^2.0.9" "@smithy/types" "^2.3.3" "@smithy/util-base64" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/hash-node@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/hash-node/-/hash-node-2.0.9.tgz#51811dabd2990eec1fc003dd6aaa8b8db95cc1eb" - integrity sha512-XP3yWd5wyCtiVmsY5Nuq/FUwyCEQ6YG7DsvRh7ThldNukGpCzyFdP8eivZJVjn4Fx7oYrrOnVoYZ0WEgpW1AvQ== + "integrity" "sha512-XP3yWd5wyCtiVmsY5Nuq/FUwyCEQ6YG7DsvRh7ThldNukGpCzyFdP8eivZJVjn4Fx7oYrrOnVoYZ0WEgpW1AvQ==" + "resolved" "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/types" "^2.3.3" "@smithy/util-buffer-from" "^2.0.0" "@smithy/util-utf8" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/invalid-dependency@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/invalid-dependency/-/invalid-dependency-2.0.9.tgz#9c8ebb70f0d1670490ae51c078d7240ac7cb9ddb" - integrity sha512-RuJqhYf8nViK96IIO9JbTtjDUuFItVfuuJhWw2yk7fv67yltQ7fZD6IQ2OsHHluoVmstnQJuCg5raXJR696Ubw== + "integrity" "sha512-RuJqhYf8nViK96IIO9JbTtjDUuFItVfuuJhWw2yk7fv67yltQ7fZD6IQ2OsHHluoVmstnQJuCg5raXJR696Ubw==" + "resolved" "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/is-array-buffer@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz#8fa9b8040651e7ba0b2f6106e636a91354ff7d34" - integrity sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug== + "integrity" "sha512-z3PjFjMyZNI98JFRJi/U0nGoLWMSJlDjAW4QUX2WNZLas5C0CmVV6LJ01JI0k90l7FvpmixjWxPFmENSClQ7ug==" + "resolved" "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.0.0.tgz" + "version" "2.0.0" dependencies: - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/middleware-content-length@^2.0.11": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@smithy/middleware-content-length/-/middleware-content-length-2.0.11.tgz#3d046f917cb0975caf6af2de96c9622cfa3c33ca" - integrity sha512-Malj4voNTL4+a5ZL3a6+Ij7JTUMTa2R7c3ZIBzMxN5OUUgAspU7uFi1Q97f4B0afVh2joQBAWH5IQJUG25nl8g== + "integrity" "sha512-Malj4voNTL4+a5ZL3a6+Ij7JTUMTa2R7c3ZIBzMxN5OUUgAspU7uFi1Q97f4B0afVh2joQBAWH5IQJUG25nl8g==" + "resolved" "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-2.0.11.tgz" + "version" "2.0.11" dependencies: "@smithy/protocol-http" "^3.0.5" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/middleware-endpoint@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.9.tgz#2a8b5098cc124923a7104db7578314b4193a62f6" - integrity sha512-72/o8R6AAO4+nyTI6h4z6PYGTSA4dr1M7tZz29U8DEUHuh1YkhC77js0P6RyF9G0wDLuYqxb+Yh0crI5WG2pJg== + "integrity" "sha512-72/o8R6AAO4+nyTI6h4z6PYGTSA4dr1M7tZz29U8DEUHuh1YkhC77js0P6RyF9G0wDLuYqxb+Yh0crI5WG2pJg==" + "resolved" "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/middleware-serde" "^2.0.9" "@smithy/types" "^2.3.3" "@smithy/url-parser" "^2.0.9" "@smithy/util-middleware" "^2.0.2" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/middleware-retry@^2.0.12": - version "2.0.12" - resolved "https://registry.yarnpkg.com/@smithy/middleware-retry/-/middleware-retry-2.0.12.tgz#d297d7cc5f40e8908aa1495060155b40e24f1ce7" - integrity sha512-YQ/ufXX4/d9/+Jf1QQ4J+CVeupC7BW52qldBTvRV33PDX9vxndlAwkFwzBcmnUFC3Hjf1//HW6I77EItcjNSCA== + "integrity" "sha512-YQ/ufXX4/d9/+Jf1QQ4J+CVeupC7BW52qldBTvRV33PDX9vxndlAwkFwzBcmnUFC3Hjf1//HW6I77EItcjNSCA==" + "resolved" "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-2.0.12.tgz" + "version" "2.0.12" dependencies: "@smithy/node-config-provider" "^2.0.12" "@smithy/protocol-http" "^3.0.5" @@ -535,98 +535,98 @@ "@smithy/types" "^2.3.3" "@smithy/util-middleware" "^2.0.2" "@smithy/util-retry" "^2.0.2" - tslib "^2.5.0" - uuid "^8.3.2" + "tslib" "^2.5.0" + "uuid" "^8.3.2" "@smithy/middleware-serde@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/middleware-serde/-/middleware-serde-2.0.9.tgz#cf0028f18dc96648de212870c9726844084dd89a" - integrity sha512-GVbauxrr6WmtCaesakktg3t5LR/yDbajpC7KkWc8rtCpddMI4ShAVO5Q6DqwX8MDFi4CLaY8H7eTGcxhl3jbLg== + "integrity" "sha512-GVbauxrr6WmtCaesakktg3t5LR/yDbajpC7KkWc8rtCpddMI4ShAVO5Q6DqwX8MDFi4CLaY8H7eTGcxhl3jbLg==" + "resolved" "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/middleware-stack@^2.0.2", "@smithy/middleware-stack@^2.0.3": - version "2.0.3" - resolved "https://registry.yarnpkg.com/@smithy/middleware-stack/-/middleware-stack-2.0.3.tgz#86b9d13d7b01208b59f9510eb6b08f8556ef6915" - integrity sha512-AlhPmbwpkC4lQBVaVHXczmjFvsAhDHhrakqLt038qFLotnJcvDLhmMzAtu23alBeOSkKxkTQq0LsAt2N0WpAbw== + "integrity" "sha512-AlhPmbwpkC4lQBVaVHXczmjFvsAhDHhrakqLt038qFLotnJcvDLhmMzAtu23alBeOSkKxkTQq0LsAt2N0WpAbw==" + "resolved" "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-2.0.3.tgz" + "version" "2.0.3" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/node-config-provider@^2.0.12": - version "2.0.12" - resolved "https://registry.yarnpkg.com/@smithy/node-config-provider/-/node-config-provider-2.0.12.tgz#59ef195dab5f00ea15abeb356e1fc2f41e4d54f2" - integrity sha512-df9y9ywv+JmS40Y60ZqJ4jfZiTCmyHQffwzIqjBjLJLJl0imf9F6DWBd+jiEWHvlohR+sFhyY+KL/qzKgnAq1A== + "integrity" "sha512-df9y9ywv+JmS40Y60ZqJ4jfZiTCmyHQffwzIqjBjLJLJl0imf9F6DWBd+jiEWHvlohR+sFhyY+KL/qzKgnAq1A==" + "resolved" "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-2.0.12.tgz" + "version" "2.0.12" dependencies: "@smithy/property-provider" "^2.0.10" "@smithy/shared-ini-file-loader" "^2.0.11" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/node-http-handler@^2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@smithy/node-http-handler/-/node-http-handler-2.1.5.tgz#b1ad4c4b7cdbb5774aeeaaf0bd14b78c6c267460" - integrity sha512-52uF+BrZaFiBh+NT/bADiVDCQO91T+OwDRsuaAeWZC1mlCXFjAPPQdxeQohtuYOe9m7mPP/xIMNiqbe8jvndHA== + "integrity" "sha512-52uF+BrZaFiBh+NT/bADiVDCQO91T+OwDRsuaAeWZC1mlCXFjAPPQdxeQohtuYOe9m7mPP/xIMNiqbe8jvndHA==" + "resolved" "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.1.5.tgz" + "version" "2.1.5" dependencies: "@smithy/abort-controller" "^2.0.9" "@smithy/protocol-http" "^3.0.5" "@smithy/querystring-builder" "^2.0.9" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/property-provider@^2.0.0", "@smithy/property-provider@^2.0.10": - version "2.0.10" - resolved "https://registry.yarnpkg.com/@smithy/property-provider/-/property-provider-2.0.10.tgz#6ed80935deff770459717c402af26e925076f32b" - integrity sha512-YMBVfh0ZMmJtbsUn+WfSwR32iRljZPdRN0Tn2GAcdJ+ejX8WrBXD7Z0jIkQDrQZr8fEuuv5x8WxMIj+qVbsPQw== + "integrity" "sha512-YMBVfh0ZMmJtbsUn+WfSwR32iRljZPdRN0Tn2GAcdJ+ejX8WrBXD7Z0jIkQDrQZr8fEuuv5x8WxMIj+qVbsPQw==" + "resolved" "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-2.0.10.tgz" + "version" "2.0.10" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/protocol-http@^3.0.5": - version "3.0.5" - resolved "https://registry.yarnpkg.com/@smithy/protocol-http/-/protocol-http-3.0.5.tgz#a143bf54382c6f7c8cdf2c67d3be101a9b7b486c" - integrity sha512-3t3fxj+ip4EPHRC2fQ0JimMxR/qCQ1LSQJjZZVZFgROnFLYWPDgUZqpoi7chr+EzatxJVXF/Rtoi5yLHOWCoZQ== + "integrity" "sha512-3t3fxj+ip4EPHRC2fQ0JimMxR/qCQ1LSQJjZZVZFgROnFLYWPDgUZqpoi7chr+EzatxJVXF/Rtoi5yLHOWCoZQ==" + "resolved" "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.0.5.tgz" + "version" "3.0.5" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/querystring-builder@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/querystring-builder/-/querystring-builder-2.0.9.tgz#97e3731b6e6fef533ab0b063b0007f6a545c0291" - integrity sha512-Yt6CPF4j3j1cuwod/DRflbuXxBFjJm7gAjy6W1RE21Rz5/kfGFqiZBXWmmXwGtnnhiLThYwoHK4S6/TQtnx0Fg== + "integrity" "sha512-Yt6CPF4j3j1cuwod/DRflbuXxBFjJm7gAjy6W1RE21Rz5/kfGFqiZBXWmmXwGtnnhiLThYwoHK4S6/TQtnx0Fg==" + "resolved" "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/types" "^2.3.3" "@smithy/util-uri-escape" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/querystring-parser@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/querystring-parser/-/querystring-parser-2.0.9.tgz#a372fcb652df0c8110aa3ffbf6bc6b512e11a78c" - integrity sha512-U6z4N743s4vrcxPW8p8+reLV0PjMCYEyb1/wtMVvv3VnbJ74gshdI8SR1sBnEh95cF8TxonmX5IxY25tS9qGfg== + "integrity" "sha512-U6z4N743s4vrcxPW8p8+reLV0PjMCYEyb1/wtMVvv3VnbJ74gshdI8SR1sBnEh95cF8TxonmX5IxY25tS9qGfg==" + "resolved" "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/service-error-classification@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@smithy/service-error-classification/-/service-error-classification-2.0.2.tgz#2fcc703ecb2c0f2880a53427a1ecd8530fcccc34" - integrity sha512-GTUd2j63gKy7A+ggvSdn2hc4sejG7LWfE+ZMF17vzWoNyqERWbRP7HTPS0d0Lwg1p6OQCAzvNigSrEIWVFt6iA== + "integrity" "sha512-GTUd2j63gKy7A+ggvSdn2hc4sejG7LWfE+ZMF17vzWoNyqERWbRP7HTPS0d0Lwg1p6OQCAzvNigSrEIWVFt6iA==" + "resolved" "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-2.0.2.tgz" + "version" "2.0.2" dependencies: "@smithy/types" "^2.3.3" "@smithy/shared-ini-file-loader@^2.0.11", "@smithy/shared-ini-file-loader@^2.0.6": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.11.tgz#33dcad2941884e0f9423b0cfc0f2d2bcc74425d3" - integrity sha512-Sf0u5C5px6eykXi6jImDTp+edvG3REtPjXnFWU/J+b7S2wkXwUqFXqBL5DdM4zC1F+M8u57ZT7NRqDwMOw7/Tw== + "integrity" "sha512-Sf0u5C5px6eykXi6jImDTp+edvG3REtPjXnFWU/J+b7S2wkXwUqFXqBL5DdM4zC1F+M8u57ZT7NRqDwMOw7/Tw==" + "resolved" "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-2.0.11.tgz" + "version" "2.0.11" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/signature-v4@^2.0.0": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/signature-v4/-/signature-v4-2.0.9.tgz#d971fed260107a815fb26f1746a1b496f654dd39" - integrity sha512-RkHP0joSI1j2EI+mU55sOi33/aMMkKdL9ZY+SWrPxsiCe1oyzzuy79Tpn8X7uT+t0ilNmQlwPpkP/jUy940pEA== + "integrity" "sha512-RkHP0joSI1j2EI+mU55sOi33/aMMkKdL9ZY+SWrPxsiCe1oyzzuy79Tpn8X7uT+t0ilNmQlwPpkP/jUy940pEA==" + "resolved" "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/eventstream-codec" "^2.0.9" "@smithy/is-array-buffer" "^2.0.0" @@ -635,86 +635,86 @@ "@smithy/util-middleware" "^2.0.2" "@smithy/util-uri-escape" "^2.0.0" "@smithy/util-utf8" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/smithy-client@^2.1.6", "@smithy/smithy-client@^2.1.7": - version "2.1.7" - resolved "https://registry.yarnpkg.com/@smithy/smithy-client/-/smithy-client-2.1.7.tgz#76b1f3ad9d95bd32afea3113132549be66c5eb12" - integrity sha512-r6T/oiBQ8vCbGqObH4/h0YqD0jFB1hAS9KFRmuTfaNJueu/L2hjmjqFjv3PV5lkbNHTgUYraSv4cFQ1naxiELQ== + "integrity" "sha512-r6T/oiBQ8vCbGqObH4/h0YqD0jFB1hAS9KFRmuTfaNJueu/L2hjmjqFjv3PV5lkbNHTgUYraSv4cFQ1naxiELQ==" + "resolved" "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-2.1.7.tgz" + "version" "2.1.7" dependencies: "@smithy/middleware-stack" "^2.0.3" "@smithy/types" "^2.3.3" "@smithy/util-stream" "^2.0.12" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/types@^2.3.3": - version "2.3.3" - resolved "https://registry.yarnpkg.com/@smithy/types/-/types-2.3.3.tgz#8770dea9b0e36c404d99a867d50b2fa6454f28aa" - integrity sha512-zTdIPR9PvFVNRdIKMQu4M5oyTaycIbUqLheQqaOi9rTWPkgjGO2wDBxMA1rBHQB81aqAEv+DbSS4jfKyQMnXRA== + "integrity" "sha512-zTdIPR9PvFVNRdIKMQu4M5oyTaycIbUqLheQqaOi9rTWPkgjGO2wDBxMA1rBHQB81aqAEv+DbSS4jfKyQMnXRA==" + "resolved" "https://registry.npmjs.org/@smithy/types/-/types-2.3.3.tgz" + "version" "2.3.3" dependencies: - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/url-parser@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/url-parser/-/url-parser-2.0.9.tgz#0ea656c5e9b167082861ff1ff82ebb7459b09ab3" - integrity sha512-NBnJ0NiY8z6E82Xd5VYUFQfKwK/wA/+QkKmpYUYP+cpH3aCzE6g2gvixd9vQKYjsIdRfNPCf+SFAozt8ljozOw== + "integrity" "sha512-NBnJ0NiY8z6E82Xd5VYUFQfKwK/wA/+QkKmpYUYP+cpH3aCzE6g2gvixd9vQKYjsIdRfNPCf+SFAozt8ljozOw==" + "resolved" "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/querystring-parser" "^2.0.9" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-base64@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-base64/-/util-base64-2.0.0.tgz#1beeabfb155471d1d41c8d0603be1351f883c444" - integrity sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA== + "integrity" "sha512-Zb1E4xx+m5Lud8bbeYi5FkcMJMnn+1WUnJF3qD7rAdXpaL7UjkFQLdmW5fHadoKbdHpwH9vSR8EyTJFHJs++tA==" + "resolved" "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-2.0.0.tgz" + "version" "2.0.0" dependencies: "@smithy/util-buffer-from" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-body-length-browser@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz#5447853003b4c73da3bc5f3c5e82c21d592d1650" - integrity sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg== + "integrity" "sha512-JdDuS4ircJt+FDnaQj88TzZY3+njZ6O+D3uakS32f2VNnDo3vyEuNdBOh/oFd8Df1zSZOuH1HEChk2AOYDezZg==" + "resolved" "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-2.0.0.tgz" + "version" "2.0.0" dependencies: - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-body-length-node@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz#313a5f7c5017947baf5fa018bfc22628904bbcfa" - integrity sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw== + "integrity" "sha512-/li0/kj/y3fQ3vyzn36NTLGmUwAICb7Jbe/CsWCktW363gh1MOcpEcSO3mJ344Gv2dqz8YJCLQpb6hju/0qOWw==" + "resolved" "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-2.1.0.tgz" + "version" "2.1.0" dependencies: - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-buffer-from@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz#7eb75d72288b6b3001bc5f75b48b711513091deb" - integrity sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw== + "integrity" "sha512-/YNnLoHsR+4W4Vf2wL5lGv0ksg8Bmk3GEGxn2vEQt52AQaPSCuaO5PM5VM7lP1K9qHRKHwrPGktqVoAHKWHxzw==" + "resolved" "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.0.0.tgz" + "version" "2.0.0" dependencies: "@smithy/is-array-buffer" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-config-provider@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz#4dd6a793605559d94267312fd06d0f58784b4c38" - integrity sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg== + "integrity" "sha512-xCQ6UapcIWKxXHEU4Mcs2s7LcFQRiU3XEluM2WcCjjBtQkUN71Tb+ydGmJFPxMUrW/GWMgQEEGipLym4XG0jZg==" + "resolved" "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-2.0.0.tgz" + "version" "2.0.0" dependencies: - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-defaults-mode-browser@^2.0.10": - version "2.0.11" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.11.tgz#46807747f3ca21a13770fc49e4bfb2bbc61a59c8" - integrity sha512-0syV1Mz/mCQ7CG/MHKQfH+w86xq59jpD0EOXv5oe0WBXLmq2lWPpVHl2Y6+jQ+/9fYzyZ5NF+NC/WEIuiv690A== + "integrity" "sha512-0syV1Mz/mCQ7CG/MHKQfH+w86xq59jpD0EOXv5oe0WBXLmq2lWPpVHl2Y6+jQ+/9fYzyZ5NF+NC/WEIuiv690A==" + "resolved" "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-2.0.11.tgz" + "version" "2.0.11" dependencies: "@smithy/property-provider" "^2.0.10" "@smithy/smithy-client" "^2.1.7" "@smithy/types" "^2.3.3" - bowser "^2.11.0" - tslib "^2.5.0" + "bowser" "^2.11.0" + "tslib" "^2.5.0" "@smithy/util-defaults-mode-node@^2.0.12": - version "2.0.13" - resolved "https://registry.yarnpkg.com/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.13.tgz#aebdc44696f9713d0e9e65ca140b45122710c1df" - integrity sha512-6BtCHYdw5Z8r6KpW8tRCc3yURgvcQwfIEeHhR70BeSOfx8T/TXPPjb8A+K45+KASspa3fzrsSxeIwB0sAeMoHA== + "integrity" "sha512-6BtCHYdw5Z8r6KpW8tRCc3yURgvcQwfIEeHhR70BeSOfx8T/TXPPjb8A+K45+KASspa3fzrsSxeIwB0sAeMoHA==" + "resolved" "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-2.0.13.tgz" + "version" "2.0.13" dependencies: "@smithy/config-resolver" "^2.0.10" "@smithy/credential-provider-imds" "^2.0.12" @@ -722,36 +722,36 @@ "@smithy/property-provider" "^2.0.10" "@smithy/smithy-client" "^2.1.7" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-hex-encoding@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz#0aa3515acd2b005c6d55675e377080a7c513b59e" - integrity sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA== + "integrity" "sha512-c5xY+NUnFqG6d7HFh1IFfrm3mGl29lC+vF+geHv4ToiuJCBmIfzx6IeHLg+OgRdPFKDXIw6pvi+p3CsscaMcMA==" + "resolved" "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-2.0.0.tgz" + "version" "2.0.0" dependencies: - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-middleware@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@smithy/util-middleware/-/util-middleware-2.0.2.tgz#9529ba2c57c26a57e4a59af88ac7c36c69cffb7d" - integrity sha512-UGPZM+Ja/vke5pc/S8G0LNiHpVirtjppsXO+GK9m9wbzRGzPJTfnZA/gERUUN/AfxEy/8SL7U1kd7u4t2X8K1w== + "integrity" "sha512-UGPZM+Ja/vke5pc/S8G0LNiHpVirtjppsXO+GK9m9wbzRGzPJTfnZA/gERUUN/AfxEy/8SL7U1kd7u4t2X8K1w==" + "resolved" "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-2.0.2.tgz" + "version" "2.0.2" dependencies: "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-retry@^2.0.2": - version "2.0.2" - resolved "https://registry.yarnpkg.com/@smithy/util-retry/-/util-retry-2.0.2.tgz#a328ec9580a160faa2a25247543fa4bd036a7426" - integrity sha512-ovWiayUB38moZcLhSFFfUgB2IMb7R1JfojU20qSahjxAgfOZvDWme3eOYUMtAVnouZ9kYJiFgHLy27qRH4NeeA== + "integrity" "sha512-ovWiayUB38moZcLhSFFfUgB2IMb7R1JfojU20qSahjxAgfOZvDWme3eOYUMtAVnouZ9kYJiFgHLy27qRH4NeeA==" + "resolved" "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-2.0.2.tgz" + "version" "2.0.2" dependencies: "@smithy/service-error-classification" "^2.0.2" "@smithy/types" "^2.3.3" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-stream@^2.0.12": - version "2.0.12" - resolved "https://registry.yarnpkg.com/@smithy/util-stream/-/util-stream-2.0.12.tgz#12682792e368794c4b890a14db4ce85272e3259d" - integrity sha512-FOCpRLaj6gvSyUC5mJAACT+sPMPmp9sD1o+hVbUH/QxwZfulypA3ZIFdAg/59/IY0d/1Q4CTztsiHEB5LgjN4g== + "integrity" "sha512-FOCpRLaj6gvSyUC5mJAACT+sPMPmp9sD1o+hVbUH/QxwZfulypA3ZIFdAg/59/IY0d/1Q4CTztsiHEB5LgjN4g==" + "resolved" "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-2.0.12.tgz" + "version" "2.0.12" dependencies: "@smithy/fetch-http-handler" "^2.1.5" "@smithy/node-http-handler" "^2.1.5" @@ -760,122 +760,360 @@ "@smithy/util-buffer-from" "^2.0.0" "@smithy/util-hex-encoding" "^2.0.0" "@smithy/util-utf8" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-uri-escape@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz#19955b1a0f517a87ae77ac729e0e411963dfda95" - integrity sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw== + "integrity" "sha512-ebkxsqinSdEooQduuk9CbKcI+wheijxEb3utGXkCoYQkJnwTnLbH1JXGimJtUkQwNQbsbuYwG2+aFVyZf5TLaw==" + "resolved" "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-2.0.0.tgz" + "version" "2.0.0" dependencies: - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-utf8@^2.0.0": - version "2.0.0" - resolved "https://registry.yarnpkg.com/@smithy/util-utf8/-/util-utf8-2.0.0.tgz#b4da87566ea7757435e153799df9da717262ad42" - integrity sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ== + "integrity" "sha512-rctU1VkziY84n5OXe3bPNpKR001ZCME2JCaBBFgtiM2hfKbHFudc/BkMuPab8hRbLd0j3vbnBTTZ1igBf0wgiQ==" + "resolved" "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.0.0.tgz" + "version" "2.0.0" dependencies: "@smithy/util-buffer-from" "^2.0.0" - tslib "^2.5.0" + "tslib" "^2.5.0" "@smithy/util-waiter@^2.0.9": - version "2.0.9" - resolved "https://registry.yarnpkg.com/@smithy/util-waiter/-/util-waiter-2.0.9.tgz#c9f1967f8313f194cb00a7d5c3f279643d4960d1" - integrity sha512-Hy9Cs0FtIacC1aVFk98bm/7CYqim9fnHAPRnV/SB2mj02ExYs/9Dn5SrNQmtTBTLCn65KqYnNVBNS8GuGpZOOw== + "integrity" "sha512-Hy9Cs0FtIacC1aVFk98bm/7CYqim9fnHAPRnV/SB2mj02ExYs/9Dn5SrNQmtTBTLCn65KqYnNVBNS8GuGpZOOw==" + "resolved" "https://registry.npmjs.org/@smithy/util-waiter/-/util-waiter-2.0.9.tgz" + "version" "2.0.9" dependencies: "@smithy/abort-controller" "^2.0.9" "@smithy/types" "^2.3.3" - tslib "^2.5.0" - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -axios@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.5.0.tgz#f02e4af823e2e46a9768cfc74691fdd0517ea267" - integrity sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ== - dependencies: - follow-redirects "^1.15.0" - form-data "^4.0.0" - proxy-from-env "^1.1.0" - -bowser@^2.11.0: - version "2.11.0" - resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" - integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -fast-xml-parser@4.2.5: - version "4.2.5" - resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz#a6747a09296a6cb34f2ae634019bf1738f3b421f" - integrity sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g== - dependencies: - strnum "^1.0.5" - -follow-redirects@^1.15.0: - version "1.15.3" - resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" - integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== - -form-data@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -moment@^2.29.4: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - -proxy-from-env@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" - integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== - -strnum@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" - integrity sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA== - -tslib@^1.11.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - -tslib@^2.3.1, tslib@^2.5.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + "tslib" "^2.5.0" + +"asynckit@^0.4.0": + "integrity" "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + "resolved" "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + "version" "0.4.0" + +"available-typed-arrays@^1.0.5": + "integrity" "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==" + "resolved" "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" + "version" "1.0.5" + +"aws-sdk@^2.1484.0": + "integrity" "sha512-emfCmb5j/UtaB7U8tvLpGdVNAlZMg4xZOhoFvL8jBQwIVJyCRyaqcshe31JXTwJdafThn2pNPtQOeYbZJCE0Ow==" + "resolved" "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.1484.0.tgz" + "version" "2.1484.0" + dependencies: + "buffer" "4.9.2" + "events" "1.1.1" + "ieee754" "1.1.13" + "jmespath" "0.16.0" + "querystring" "0.2.0" + "sax" "1.2.1" + "url" "0.10.3" + "util" "^0.12.4" + "uuid" "8.0.0" + "xml2js" "0.5.0" + +"axios@^1.5.0": + "integrity" "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==" + "resolved" "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz" + "version" "1.5.0" + dependencies: + "follow-redirects" "^1.15.0" + "form-data" "^4.0.0" + "proxy-from-env" "^1.1.0" + +"base64-js@^1.0.2": + "integrity" "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + "resolved" "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" + "version" "1.5.1" + +"bowser@^2.11.0": + "integrity" "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + "resolved" "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz" + "version" "2.11.0" + +"buffer@4.9.2": + "integrity" "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==" + "resolved" "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz" + "version" "4.9.2" + dependencies: + "base64-js" "^1.0.2" + "ieee754" "^1.1.4" + "isarray" "^1.0.0" + +"call-bind@^1.0.2", "call-bind@^1.0.4": + "integrity" "sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==" + "resolved" "https://registry.npmjs.org/call-bind/-/call-bind-1.0.5.tgz" + "version" "1.0.5" + dependencies: + "function-bind" "^1.1.2" + "get-intrinsic" "^1.2.1" + "set-function-length" "^1.1.1" + +"combined-stream@^1.0.8": + "integrity" "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==" + "resolved" "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + "version" "1.0.8" + dependencies: + "delayed-stream" "~1.0.0" + +"define-data-property@^1.1.1": + "integrity" "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==" + "resolved" "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "get-intrinsic" "^1.2.1" + "gopd" "^1.0.1" + "has-property-descriptors" "^1.0.0" + +"delayed-stream@~1.0.0": + "integrity" "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + "resolved" "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + "version" "1.0.0" + +"events@1.1.1": + "integrity" "sha512-kEcvvCBByWXGnZy6JUlgAp2gBIUjfCAV6P6TgT1/aaQKcmuAEC4OZTV1I4EWQLz2gxZw76atuVyvHhTxvi0Flw==" + "resolved" "https://registry.npmjs.org/events/-/events-1.1.1.tgz" + "version" "1.1.1" + +"fast-xml-parser@4.2.5": + "integrity" "sha512-B9/wizE4WngqQftFPmdaMYlXoJlJOYxGQOanC77fq9k8+Z0v5dDSVh+3glErdIROP//s/jgb7ZuxKfB8nVyo0g==" + "resolved" "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz" + "version" "4.2.5" + dependencies: + "strnum" "^1.0.5" + +"follow-redirects@^1.15.0": + "integrity" "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==" + "resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz" + "version" "1.15.3" + +"for-each@^0.3.3": + "integrity" "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==" + "resolved" "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + "version" "0.3.3" + dependencies: + "is-callable" "^1.1.3" + +"form-data@^4.0.0": + "integrity" "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==" + "resolved" "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + "version" "4.0.0" + dependencies: + "asynckit" "^0.4.0" + "combined-stream" "^1.0.8" + "mime-types" "^2.1.12" + +"function-bind@^1.1.2": + "integrity" "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + "version" "1.1.2" + +"get-intrinsic@^1.1.3", "get-intrinsic@^1.2.1", "get-intrinsic@^1.2.2": + "integrity" "sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==" + "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.2.tgz" + "version" "1.2.2" + dependencies: + "function-bind" "^1.1.2" + "has-proto" "^1.0.1" + "has-symbols" "^1.0.3" + "hasown" "^2.0.0" + +"gopd@^1.0.1": + "integrity" "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==" + "resolved" "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "get-intrinsic" "^1.1.3" + +"has-property-descriptors@^1.0.0": + "integrity" "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==" + "resolved" "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz" + "version" "1.0.1" + dependencies: + "get-intrinsic" "^1.2.2" + +"has-proto@^1.0.1": + "integrity" "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + "resolved" "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" + "version" "1.0.1" + +"has-symbols@^1.0.2", "has-symbols@^1.0.3": + "integrity" "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + "version" "1.0.3" + +"has-tostringtag@^1.0.0": + "integrity" "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==" + "resolved" "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz" + "version" "1.0.0" + dependencies: + "has-symbols" "^1.0.2" + +"hasown@^2.0.0": + "integrity" "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==" + "resolved" "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" + "version" "2.0.0" + dependencies: + "function-bind" "^1.1.2" + +"ieee754@^1.1.4", "ieee754@1.1.13": + "integrity" "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + "resolved" "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz" + "version" "1.1.13" + +"inherits@^2.0.3": + "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + "version" "2.0.4" + +"is-arguments@^1.0.4": + "integrity" "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==" + "resolved" "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "call-bind" "^1.0.2" + "has-tostringtag" "^1.0.0" + +"is-callable@^1.1.3": + "integrity" "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==" + "resolved" "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + "version" "1.2.7" + +"is-generator-function@^1.0.7": + "integrity" "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==" + "resolved" "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz" + "version" "1.0.10" + dependencies: + "has-tostringtag" "^1.0.0" + +"is-typed-array@^1.1.3": + "integrity" "sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg==" + "resolved" "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.12.tgz" + "version" "1.1.12" + dependencies: + "which-typed-array" "^1.1.11" + +"isarray@^1.0.0": + "integrity" "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "resolved" "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + "version" "1.0.0" + +"jmespath@0.16.0": + "integrity" "sha512-9FzQjJ7MATs1tSpnco1K6ayiYE3figslrXA72G2HQ/n76RzvYlofyi5QM+iX4YRs/pu3yzxlVQSST23+dMDknw==" + "resolved" "https://registry.npmjs.org/jmespath/-/jmespath-0.16.0.tgz" + "version" "0.16.0" + +"mime-db@1.52.0": + "integrity" "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + "resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + "version" "1.52.0" + +"mime-types@^2.1.12": + "integrity" "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==" + "resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + "version" "2.1.35" + dependencies: + "mime-db" "1.52.0" + +"moment@^2.29.4": + "integrity" "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==" + "resolved" "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz" + "version" "2.29.4" + +"proxy-from-env@^1.1.0": + "integrity" "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + "resolved" "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" + "version" "1.1.0" + +"punycode@1.3.2": + "integrity" "sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw==" + "resolved" "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" + "version" "1.3.2" + +"querystring@0.2.0": + "integrity" "sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g==" + "resolved" "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" + "version" "0.2.0" + +"sax@>=0.6.0", "sax@1.2.1": + "integrity" "sha512-8I2a3LovHTOpm7NV5yOyO8IHqgVsfK4+UuySrXU8YXkSRX7k6hCV9b3HrkKCr3nMpgj+0bmocaJJWpvp1oc7ZA==" + "resolved" "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz" + "version" "1.2.1" + +"set-function-length@^1.1.1": + "integrity" "sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==" + "resolved" "https://registry.npmjs.org/set-function-length/-/set-function-length-1.1.1.tgz" + "version" "1.1.1" + dependencies: + "define-data-property" "^1.1.1" + "get-intrinsic" "^1.2.1" + "gopd" "^1.0.1" + "has-property-descriptors" "^1.0.0" + +"strnum@^1.0.5": + "integrity" "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + "resolved" "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz" + "version" "1.0.5" + +"tslib@^1.11.1": + "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" + "version" "1.14.1" + +"tslib@^2.3.1", "tslib@^2.5.0": + "integrity" "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" + "version" "2.6.2" + +"url@0.10.3": + "integrity" "sha512-hzSUW2q06EqL1gKM/a+obYHLIO6ct2hwPuviqTTOcfFVc61UbfJ2Q32+uGL/HCPxKqrdGB5QUwIe7UqlDgwsOQ==" + "resolved" "https://registry.npmjs.org/url/-/url-0.10.3.tgz" + "version" "0.10.3" + dependencies: + "punycode" "1.3.2" + "querystring" "0.2.0" + +"util@^0.12.4": + "integrity" "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==" + "resolved" "https://registry.npmjs.org/util/-/util-0.12.5.tgz" + "version" "0.12.5" + dependencies: + "inherits" "^2.0.3" + "is-arguments" "^1.0.4" + "is-generator-function" "^1.0.7" + "is-typed-array" "^1.1.3" + "which-typed-array" "^1.1.2" + +"uuid@^8.3.2": + "integrity" "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + "resolved" "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" + "version" "8.3.2" + +"uuid@8.0.0": + "integrity" "sha512-jOXGuXZAWdsTH7eZLtyXMqUb9EcWMGZNbL9YcGBJl4MH4nrxHmZJhEHvyLFrkxo+28uLb/NYRcStH48fnD0Vzw==" + "resolved" "https://registry.npmjs.org/uuid/-/uuid-8.0.0.tgz" + "version" "8.0.0" + +"which-typed-array@^1.1.11", "which-typed-array@^1.1.2": + "integrity" "sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow==" + "resolved" "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.13.tgz" + "version" "1.1.13" + dependencies: + "available-typed-arrays" "^1.0.5" + "call-bind" "^1.0.4" + "for-each" "^0.3.3" + "gopd" "^1.0.1" + "has-tostringtag" "^1.0.0" + +"xml2js@0.5.0": + "integrity" "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==" + "resolved" "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz" + "version" "0.5.0" + dependencies: + "sax" ">=0.6.0" + "xmlbuilder" "~11.0.0" + +"xmlbuilder@~11.0.0": + "integrity" "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + "resolved" "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz" + "version" "11.0.1" From 67ab122d4bd755e3b6fde1bf887c361538a68475 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 31 Oct 2023 15:48:54 -0300 Subject: [PATCH 03/30] Updating table name --- src/external/aws/dynamo.js | 9 +++++---- src/utils/scripts/create_dynamo_table.sh | 2 +- src/utils/types.js | 4 ++-- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/external/aws/dynamo.js b/src/external/aws/dynamo.js index df53ce7..6a3000f 100644 --- a/src/external/aws/dynamo.js +++ b/src/external/aws/dynamo.js @@ -3,17 +3,18 @@ import moment from 'moment'; import { DATE_FORMAT, DYNAMO_RESTART_STATUS, - DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART + DYNAMO_DB_TABLE_AUTO_RESTART } from '../../utils/types.js' const dynamodb = new AWS.DynamoDB(); const upsertMetagraphRestart = async (metagraphId, status, updatedAt) => { const item = { - TableName: DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART, + TableName: DYNAMO_DB_TABLE_AUTO_RESTART, Item: { id: { S: metagraphId }, status: { S: status }, + type: { S: 'metagraph' }, updated_at: { S: updatedAt || moment.utc().format(DATE_FORMAT) }, }, }; @@ -29,7 +30,7 @@ const upsertMetagraphRestart = async (metagraphId, status, updatedAt) => { const getMetagraphRestartOrCreateNew = async (metagraphId) => { const params = { - TableName: DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART, + TableName: DYNAMO_DB_TABLE_AUTO_RESTART, Key: { id: { S: `${metagraphId}` }, }, @@ -63,7 +64,7 @@ const getMetagraphRestartOrCreateNew = async (metagraphId) => { const deleteMetagraphRestart = async (metagraphId) => { const params = { - TableName: DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART, + TableName: DYNAMO_DB_TABLE_AUTO_RESTART, Key: { id: { S: `${metagraphId}` }, }, diff --git a/src/utils/scripts/create_dynamo_table.sh b/src/utils/scripts/create_dynamo_table.sh index a662c15..13a61ce 100755 --- a/src/utils/scripts/create_dynamo_table.sh +++ b/src/utils/scripts/create_dynamo_table.sh @@ -1,5 +1,5 @@ aws dynamodb create-table \ - --table-name metagraph_auto_restart \ + --table-name auto_restart \ --attribute-definitions \ AttributeName=id,AttributeType=S \ --key-schema \ diff --git a/src/utils/types.js b/src/utils/types.js index 7f226b6..31f961d 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -20,7 +20,7 @@ const DYNAMO_RESTART_STATUS = { READY: 'READY' } -const DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART = 'metagraph_auto_restart' +const DYNAMO_DB_TABLE_AUTO_RESTART = 'auto_restart' export { LAYERS, @@ -28,5 +28,5 @@ export { DATE_FORMAT, RESTART_REASONS, DYNAMO_RESTART_STATUS, - DYNAMO_DB_TABLE_METAGRAPH_AUTO_RESTART + DYNAMO_DB_TABLE_AUTO_RESTART } \ No newline at end of file From 840bc8fb43417aded0876bd0aaa75624c7f27cb5 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 31 Oct 2023 16:04:51 -0300 Subject: [PATCH 04/30] Fixing CR comments --- index.js | 48 +++++++++++++++++++++----------- src/external/aws/dynamo.js | 24 ++++++++-------- src/services/opsgenie_service.js | 2 +- src/shared/index.js | 20 ++++++------- 4 files changed, 54 insertions(+), 40 deletions(-) diff --git a/index.js b/index.js index fca3e01..861ea88 100644 --- a/index.js +++ b/index.js @@ -15,9 +15,11 @@ import { restartL0Nodes } from './src/metagraph-l0/index.js' import { restartCurrencyL1Nodes } from './src/currency-l1/index.js' import { restartDataL1Nodes } from './src/data-l1/index.js' import { createMetagraphRestartSuccessfullyAlert, createMetagraphRestartFailureAlert } from './src/services/opsgenie_service.js' -import { LAYERS, VALID_NETWORKS, RESTART_REASONS, DYNAMO_RESTART_STATUS } from './src/utils/types.js' +import { LAYERS, VALID_NETWORKS, RESTART_REASONS, DYNAMO_RESTART_STATUS, DATE_FORMAT } from './src/utils/types.js' import { deleteMetagraphRestart, getMetagraphRestartOrCreateNew, upsertMetagraphRestart } from './src/external/aws/dynamo.js' +const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 240 + const getLogsNames = () => { const now = moment.utc().format('YYY-MM-DD_HH-mm-ss') @@ -110,7 +112,7 @@ const shouldRestartMetagraph = async (event, lastSnapshotTimestamp) => { return { should_restart: true, reason: RESTART_REASONS.STOP_PRODUCING_SNAPSHOTS - }; + } } const unhealthyClusters = await getUnhealthyClusters(event) @@ -146,7 +148,7 @@ const getCurrentMetagraphRestart = async (event) => { } export const handler = async (event) => { - const ssmClient = new SSMClient({ region: event.aws.region }); + const ssmClient = new SSMClient({ region: event.aws.region }) if (!VALID_NETWORKS.includes(event.network.name)) { throw Error(`Network should be one of the following: ${JSON.stringify(VALID_NETWORKS)}`) @@ -161,26 +163,38 @@ export const handler = async (event) => { return { statusCode: 200, body: JSON.stringify('Metagraph healthy, ignoring restart!'), - }; + } } - const currentMetagraphRestart = await getCurrentMetagraphRestart(event) + let currentMetagraphRestart = await getCurrentMetagraphRestart(event) if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.ROLLBACK_IN_PROGRESS) { - const lastRestartTimeDiff = moment.utc().diff(moment.utc(currentMetagraphRestart.updatedAt), 'hours') - - if (lastRestartTimeDiff > 3) { - throw new Error("The last restart of metagraph is taking more than 3 hours, please check the logs") - } + const lastRestartTimeDiff = moment.utc().diff(moment.utc(currentMetagraphRestart.updatedAt), 'minutes') - return { - statusCode: 200, - body: JSON.stringify('There is already one ROLLBACK_IN_PROGRESS for this metagraph, please wait this operation could take hours'), - }; + if (lastRestartTimeDiff <= ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES) { + const timeoutTime = moment.utc(currentMetagraphRestart.updatedAt).add(ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES, 'minutes') + + console.log(`Operation running since: ${currentMetagraphRestart.updatedAt} will timeout at ${timeoutTime.format(DATE_FORMAT)}`) + + return { + statusCode: 200, + body: JSON.stringify('There is already one ROLLBACK_IN_PROGRESS for this metagraph, please wait this operation could take hours'), + } + } + + await deleteMetagraphRestart(event.metagraph.id) + await createMetagraphRestartFailureAlert( + ssmClient, + event, + `The last restart of metagraph is taking more than ${ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES} minutes, please check the logs. Triggering a new restart...`, + shouldRestart ? shouldRestart.reason : 'Unknow reason' + ) + + currentMetagraphRestart = await getCurrentMetagraphRestart(event) } printSeparatorWithMessage('STARTING THE RESTART') - const logsNames = getLogsNames(); + const logsNames = getLogsNames() await restartNodes(ssmClient, event, logsNames, currentMetagraphRestart) @@ -199,10 +213,10 @@ export const handler = async (event) => { return { statusCode: 200, body: JSON.stringify('Finished cluster restart'), - }; + } } catch (e) { await createMetagraphRestartFailureAlert(ssmClient, event, e.message, shouldRestart ? shouldRestart.reason : 'Unknow reason') throw e } -}; \ No newline at end of file +} \ No newline at end of file diff --git a/src/external/aws/dynamo.js b/src/external/aws/dynamo.js index 6a3000f..674dbeb 100644 --- a/src/external/aws/dynamo.js +++ b/src/external/aws/dynamo.js @@ -1,12 +1,12 @@ -import AWS from 'aws-sdk'; -import moment from 'moment'; +import AWS from 'aws-sdk' +import moment from 'moment' import { DATE_FORMAT, DYNAMO_RESTART_STATUS, DYNAMO_DB_TABLE_AUTO_RESTART } from '../../utils/types.js' -const dynamodb = new AWS.DynamoDB(); +const dynamodb = new AWS.DynamoDB() const upsertMetagraphRestart = async (metagraphId, status, updatedAt) => { const item = { @@ -17,9 +17,9 @@ const upsertMetagraphRestart = async (metagraphId, status, updatedAt) => { type: { S: 'metagraph' }, updated_at: { S: updatedAt || moment.utc().format(DATE_FORMAT) }, }, - }; + } - const metagraphRestart = await dynamodb.putItem(item).promise(); + const metagraphRestart = await dynamodb.putItem(item).promise() const { error } = metagraphRestart.$response if (error) { throw error @@ -34,11 +34,11 @@ const getMetagraphRestartOrCreateNew = async (metagraphId) => { Key: { id: { S: `${metagraphId}` }, }, - }; + } - const metagraphRestart = await dynamodb.getItem(params).promise(); - const { error, data } = metagraphRestart.$response; + const metagraphRestart = await dynamodb.getItem(params).promise() + const { error, data } = metagraphRestart.$response if (error) { console.error(`Error when trying to get information from dynamo: ${err}`) @@ -68,17 +68,17 @@ const deleteMetagraphRestart = async (metagraphId) => { Key: { id: { S: `${metagraphId}` }, }, - }; + } - const response = await dynamodb.deleteItem(params).promise(); + const response = await dynamodb.deleteItem(params).promise() const { error, data } = response.$response if (error) { - console.error('Error deleting item: ', error); + console.error('Error deleting item: ', error) throw err } else { - console.log('Item deleted successfully: ', data); + console.log('Item deleted successfully: ', data) } } diff --git a/src/services/opsgenie_service.js b/src/services/opsgenie_service.js index 86f1ed5..58b339c 100644 --- a/src/services/opsgenie_service.js +++ b/src/services/opsgenie_service.js @@ -1,4 +1,4 @@ -import axios from 'axios'; +import axios from 'axios' import { getSSMParameter, printSeparatorWithMessage } from '../shared/index.js' const OPSGENIE_ALERT_URL = "https://api.opsgenie.com/v2/alerts" diff --git a/src/shared/index.js b/src/shared/index.js index 8077e56..9059c78 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -1,14 +1,14 @@ -import moment from 'moment'; -import axios from 'axios'; +import moment from 'moment' +import axios from 'axios' import { SendCommandCommand, GetParameterCommand } from '@aws-sdk/client-ssm' import { LAYERS } from '../utils/types.js' const sleep = (ms) => { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise(resolve => setTimeout(resolve, ms)) } const getLastMetagraphInfo = async (event) => { - const { network, metagraph } = event; + const { network, metagraph } = event const beUrl = `https://be-${network.name}.constellationnetwork.io/currency/${metagraph.id}/snapshots/latest` try { const response = await axios.get(beUrl) @@ -36,20 +36,20 @@ const sendCommand = async (ssmClient, commands, ec2InstancesIds) => { Parameters: { commands }, - }; + } try { - const commandResponse = await ssmClient.send(new SendCommandCommand(params)); - console.log("Command sent successfully. Command ID:", commandResponse.Command.CommandId); + const commandResponse = await ssmClient.send(new SendCommandCommand(params)) + console.log("Command sent successfully. Command ID:", commandResponse.Command.CommandId) } catch (error) { - console.error("Error sending command:", error); + console.error("Error sending command:", error) } } const getSSMParameter = async (ssmClient, parameterName) => { const getParameterCommand = new GetParameterCommand({ Name: parameterName, - }); + }) const parameter = await ssmClient.send(getParameterCommand) return parameter.Parameter.Value @@ -107,7 +107,7 @@ const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => } const deletingCommands = await Promise.all(promises) - const allDeletingCommands = deletingCommands.reduce((acc, curr) => [...acc, ...curr], []); + const allDeletingCommands = deletingCommands.reduce((acc, curr) => [...acc, ...curr], []) const commands = [ `cd ${file_system.base_metagraph_l0_directory}`, From 8b068da8499a364ad3141c8d3a4231f61d6af5fe Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 31 Oct 2023 16:25:03 -0300 Subject: [PATCH 05/30] Updating --- index.js | 26 ++++++++++++++------------ src/external/aws/dynamo.js | 14 +++++++------- src/metagraph-l0/index.js | 10 +++++----- src/shared/index.js | 10 +++++----- src/utils/types.js | 6 +++--- 5 files changed, 34 insertions(+), 32 deletions(-) diff --git a/index.js b/index.js index 861ea88..9b53660 100644 --- a/index.js +++ b/index.js @@ -15,7 +15,7 @@ import { restartL0Nodes } from './src/metagraph-l0/index.js' import { restartCurrencyL1Nodes } from './src/currency-l1/index.js' import { restartDataL1Nodes } from './src/data-l1/index.js' import { createMetagraphRestartSuccessfullyAlert, createMetagraphRestartFailureAlert } from './src/services/opsgenie_service.js' -import { LAYERS, VALID_NETWORKS, RESTART_REASONS, DYNAMO_RESTART_STATUS, DATE_FORMAT } from './src/utils/types.js' +import { LAYERS, VALID_NETWORKS, RESTART_REASONS, DYNAMO_RESTART_STATE, DATE_FORMAT } from './src/utils/types.js' import { deleteMetagraphRestart, getMetagraphRestartOrCreateNew, upsertMetagraphRestart } from './src/external/aws/dynamo.js' const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 240 @@ -37,7 +37,7 @@ const getLogsNames = () => { const restartNodes = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogName }, currentMetagraphRestart) => { const allEC2NodesIntances = getAllEC2NodesInstances(event) - if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.NEW) { + if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { printSeparatorWithMessage('Killing current processes on nodes') await killCurrentProcesses(ssmClient, event, allEC2NodesIntances) printSeparatorWithMessage('Finished') @@ -51,7 +51,7 @@ const restartNodes = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogNam const nodeId = await restartL0Nodes(ssmClient, event, l0LogName, currentMetagraphRestart) printSeparatorWithMessage('Finished') - if (!nodeId || currentMetagraphRestart.status !== DYNAMO_RESTART_STATUS.READY) { + if (!nodeId || currentMetagraphRestart.state !== DYNAMO_RESTART_STATE.READY) { console.log("Genesis node still not ready, skipping") return } @@ -132,13 +132,15 @@ const shouldRestartMetagraph = async (event, lastSnapshotTimestamp) => { const getCurrentMetagraphRestart = async (event) => { printSeparatorWithMessage('GETTING CURRENT METAGRAPH RESTART') - const rollbackFinished = await checkIfRollbackFinished(event) - let currentMetagraphRestart + let currentMetagraphRestart = await getMetagraphRestartOrCreateNew(event.metagraph.id) + if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { + return currentMetagraphRestart + } + + const rollbackFinished = await checkIfRollbackFinished(event) if (rollbackFinished) { - currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATUS.READY) - } else { - currentMetagraphRestart = await getMetagraphRestartOrCreateNew(event.metagraph.id) + currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATE.READY) } console.log("Current Metagraph Restart:", JSON.stringify(currentMetagraphRestart)) @@ -167,20 +169,20 @@ export const handler = async (event) => { } let currentMetagraphRestart = await getCurrentMetagraphRestart(event) - if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.ROLLBACK_IN_PROGRESS) { + if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS) { const lastRestartTimeDiff = moment.utc().diff(moment.utc(currentMetagraphRestart.updatedAt), 'minutes') if (lastRestartTimeDiff <= ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES) { const timeoutTime = moment.utc(currentMetagraphRestart.updatedAt).add(ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES, 'minutes') console.log(`Operation running since: ${currentMetagraphRestart.updatedAt} will timeout at ${timeoutTime.format(DATE_FORMAT)}`) - + return { statusCode: 200, body: JSON.stringify('There is already one ROLLBACK_IN_PROGRESS for this metagraph, please wait this operation could take hours'), } } - + await deleteMetagraphRestart(event.metagraph.id) await createMetagraphRestartFailureAlert( ssmClient, @@ -198,7 +200,7 @@ export const handler = async (event) => { await restartNodes(ssmClient, event, logsNames, currentMetagraphRestart) - if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.READY) { + if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.READY) { await validateIfAllNodesAreReady(event) await checkIfNewSnapshotsAreProducedAfterRestart(event) diff --git a/src/external/aws/dynamo.js b/src/external/aws/dynamo.js index 674dbeb..31358a5 100644 --- a/src/external/aws/dynamo.js +++ b/src/external/aws/dynamo.js @@ -2,18 +2,18 @@ import AWS from 'aws-sdk' import moment from 'moment' import { DATE_FORMAT, - DYNAMO_RESTART_STATUS, + DYNAMO_RESTART_STATE, DYNAMO_DB_TABLE_AUTO_RESTART } from '../../utils/types.js' const dynamodb = new AWS.DynamoDB() -const upsertMetagraphRestart = async (metagraphId, status, updatedAt) => { +const upsertMetagraphRestart = async (metagraphId, state, updatedAt) => { const item = { TableName: DYNAMO_DB_TABLE_AUTO_RESTART, Item: { id: { S: metagraphId }, - status: { S: status }, + state: { S: state }, type: { S: 'metagraph' }, updated_at: { S: updatedAt || moment.utc().format(DATE_FORMAT) }, }, @@ -47,16 +47,16 @@ const getMetagraphRestartOrCreateNew = async (metagraphId) => { const { Item } = data if (!Item) { - console.log("Could not get status, creating new restart of metagraph...") + console.log("Could not get metagraph restart, creating new restart of metagraph...") const updatedAt = moment.utc().format(DATE_FORMAT) - return upsertMetagraphRestart(metagraphId, DYNAMO_RESTART_STATUS.NEW, updatedAt) + return upsertMetagraphRestart(metagraphId, DYNAMO_RESTART_STATE.NEW, updatedAt) } - const status = Item.status.S + const state = Item.state.S const updatedAt = Item.updated_at.S return { - status, + state, updatedAt } diff --git a/src/metagraph-l0/index.js b/src/metagraph-l0/index.js index ed30f96..06b1904 100644 --- a/src/metagraph-l0/index.js +++ b/src/metagraph-l0/index.js @@ -9,7 +9,7 @@ import { saveLogs, getAllEC2NodesInstances } from '../shared/index.js' -import { DYNAMO_RESTART_STATUS, LAYERS } from '../utils/types.js' +import { DYNAMO_RESTART_STATE, LAYERS } from '../utils/types.js' const startRollbackFirstNodeL0 = async (ssmClient, event, ec2InstancesIds) => { const l0Keys = await getKeys(ssmClient, event.aws.ec2.instances.genesis.id, LAYERS.L0) @@ -90,19 +90,19 @@ const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2Insta } const restartL0Nodes = async (ssmClient, event, logName, currentMetagraphRestart) => { - if (currentMetagraphRestart.status === DYNAMO_RESTART_STATUS.NEW) { + if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { const allEC2NodesIntances = getAllEC2NodesInstances(event) await saveLogs(ssmClient, event, logName, LAYERS.L0, allEC2NodesIntances) printSeparatorWithMessage('Starting rollback genesis l0 node') await startRollbackFirstNodeL0(ssmClient, event, [event.aws.ec2.instances.genesis.id]) - console.log("Updating status to ROLLBACK_IN_PROGRESS") - currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATUS.ROLLBACK_IN_PROGRESS) + console.log("Updating state to ROLLBACK_IN_PROGRESS") + currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS) printSeparatorWithMessage('Finished') } - if (currentMetagraphRestart.status !== DYNAMO_RESTART_STATUS.READY) { + if (currentMetagraphRestart.state !== DYNAMO_RESTART_STATE.READY) { return null } diff --git a/src/shared/index.js b/src/shared/index.js index 9059c78..b72fff9 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -210,7 +210,7 @@ const saveLogs = async (ssmClient, event, logName, layer, ec2InstancesIds) => { } const checkIfAllNodesAreReady = async (event, layer) => { - printSeparatorWithMessage(`[${layer}] Checking nodes statuses`) + printSeparatorWithMessage(`[${layer}] Checking nodes states`) const { ports } = event.metagraph var layerPorts = { [LAYERS.L0]: ports.metagraph_l0_public_port, @@ -239,20 +239,20 @@ const checkIfAllNodesAreReady = async (event, layer) => { } if (urls.length === 0) { - console.log(`[${layer}] All nodes are on ready status`) + console.log(`[${layer}] All nodes are on ready state`) printSeparatorWithMessage(`[${layer}] Finished`) return } else { console.log(`[${layer}] The following nodes are not ready yet: ${JSON.stringify(urls)}`) - console.log(`[${layer}] Not all nodes are on Ready status, trying again in 10s (${idx + 1}/20)`) + console.log(`[${layer}] Not all nodes are on Ready state, trying again in 10s (${idx + 1}/20)`) await sleep(10000) } } catch (e) { if (idx === 19) { - throw new Error(`[${layer}] Failing when restarting nodes. All nodes should be on READY status`) + throw new Error(`[${layer}] Failing when restarting nodes. All nodes should be on READY state`) } - console.log(`[${layer}] Not all nodes are on Ready status, trying again in 10s (${idx + 1}/20)`) + console.log(`[${layer}] Not all nodes are on Ready state, trying again in 10s (${idx + 1}/20)`) await sleep(10000) } } diff --git a/src/utils/types.js b/src/utils/types.js index 31f961d..377c175 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -11,10 +11,10 @@ const DATE_FORMAT = "YYYY-MM-DDTHH:mm:ssZ" const RESTART_REASONS = { STOP_PRODUCING_SNAPSHOTS: "Metagraph stop producing snapshots", FORCE_METAGRAPH_RESTART: "Force metagraph restart provided", - UNHEALTHY_CLUSTER: "One of the clusters are unhealthy (less than 3 nodes or nodes with not Ready status)" + UNHEALTHY_CLUSTER: "One of the clusters are unhealthy (less than 3 nodes or nodes with not Ready state)" } -const DYNAMO_RESTART_STATUS = { +const DYNAMO_RESTART_STATE = { NEW: 'NEW', ROLLBACK_IN_PROGRESS: "ROLLBACK IN PROGRESS", READY: 'READY' @@ -27,6 +27,6 @@ export { VALID_NETWORKS, DATE_FORMAT, RESTART_REASONS, - DYNAMO_RESTART_STATUS, + DYNAMO_RESTART_STATE, DYNAMO_DB_TABLE_AUTO_RESTART } \ No newline at end of file From b2cb469a73520862c67f0d891e7f411934ffd5cf Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Wed, 8 Nov 2023 11:54:12 -0300 Subject: [PATCH 06/30] Fixing force_restart --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 9b53660..c28cd2f 100644 --- a/index.js +++ b/index.js @@ -100,7 +100,8 @@ const checkIfNewSnapshotsAreProducedAfterRestart = async (event) => { const shouldRestartMetagraph = async (event, lastSnapshotTimestamp) => { if (event.force_metagraph_restart) { - console.log('Force metagraph restart provided, restarting') + console.log('Force metagraph restart provided. Deleting dynamo row and restarting') + await deleteMetagraphRestart(event.metagraph.id) return { should_restart: true, reason: RESTART_REASONS.FORCE_METAGRAPH_RESTART From ddf25496fa18a118ae26c9ff5e2d134b86f43913 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Wed, 8 Nov 2023 11:55:40 -0300 Subject: [PATCH 07/30] Fixing force_restart --- index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 9b53660..c28cd2f 100644 --- a/index.js +++ b/index.js @@ -100,7 +100,8 @@ const checkIfNewSnapshotsAreProducedAfterRestart = async (event) => { const shouldRestartMetagraph = async (event, lastSnapshotTimestamp) => { if (event.force_metagraph_restart) { - console.log('Force metagraph restart provided, restarting') + console.log('Force metagraph restart provided. Deleting dynamo row and restarting') + await deleteMetagraphRestart(event.metagraph.id) return { should_restart: true, reason: RESTART_REASONS.FORCE_METAGRAPH_RESTART From ac9bf42ea3a021fa245406531bd8e9858d9b12ad Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Wed, 8 Nov 2023 14:00:53 -0300 Subject: [PATCH 08/30] Updating logical to get source node --- event.json | 5 +-- index.js | 15 ++++++--- src/currency-l1/index.js | 25 +++++++------- src/data-l1/index.js | 25 +++++++------- src/metagraph-l0/index.js | 25 +++++++------- src/shared/index.js | 70 +++++++++++++++++++++++++++++++++++++-- src/utils/types.js | 57 ++++++++++++++++++++++++++++++- 7 files changed, 171 insertions(+), 51 deletions(-) diff --git a/event.json b/event.json index 5a8215f..8661517 100644 --- a/event.json +++ b/event.json @@ -32,10 +32,7 @@ "additional_data_l1_env_variables": [] }, "network": { - "name": "integrationnet", - "gl0_node_ip": "52.53.216.201", - "gl0_node_id": "3458a688925a4bd89f2ac2c695362e44d2e0c2903bdbb41b341a4d39283b22d8c85b487bd33cc5d36dbe5e31b5b00a10a6eab802718ead4ed7192ade5a5d1941", - "gl0_node_port": "9000" + "name": "integrationnet" }, "aws": { "region": "us-west-2", diff --git a/index.js b/index.js index c28cd2f..c80ceed 100644 --- a/index.js +++ b/index.js @@ -9,7 +9,8 @@ import { getAllEC2NodesInstances, deleteSnapshotNotSyncToGL0, getUnhealthyClusters, - checkIfRollbackFinished + checkIfRollbackFinished, + getReferenceSourceNode } from './src/shared/index.js' import { restartL0Nodes } from './src/metagraph-l0/index.js' import { restartCurrencyL1Nodes } from './src/currency-l1/index.js' @@ -37,6 +38,12 @@ const getLogsNames = () => { const restartNodes = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogName }, currentMetagraphRestart) => { const allEC2NodesIntances = getAllEC2NodesInstances(event) + const referenceSourceNode = await getReferenceSourceNode(event) + if(!referenceSourceNode) { + throw Error(`Could not get reference node to network ${event.network.name}`) + } + console.log(`RefrenceSourceNode found: ${JSON.stringify(referenceSourceNode)}`) + if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { printSeparatorWithMessage('Killing current processes on nodes') await killCurrentProcesses(ssmClient, event, allEC2NodesIntances) @@ -48,7 +55,7 @@ const restartNodes = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogNam } printSeparatorWithMessage('METAGRAPH L0') - const nodeId = await restartL0Nodes(ssmClient, event, l0LogName, currentMetagraphRestart) + const nodeId = await restartL0Nodes(ssmClient, event, l0LogName, currentMetagraphRestart, referenceSourceNode) printSeparatorWithMessage('Finished') if (!nodeId || currentMetagraphRestart.state !== DYNAMO_RESTART_STATE.READY) { @@ -58,13 +65,13 @@ const restartNodes = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogNam if (event.metagraph.include_currency_l1_layer) { printSeparatorWithMessage('CURRENCY L1') - await restartCurrencyL1Nodes(ssmClient, event, nodeId, cl1LogName) + await restartCurrencyL1Nodes(ssmClient, event, nodeId, cl1LogName, referenceSourceNode) printSeparatorWithMessage('Finished') } if (event.metagraph.include_data_l1_layer) { printSeparatorWithMessage('DATA L1') - await restartDataL1Nodes(ssmClient, event, nodeId, dl1LogName) + await restartDataL1Nodes(ssmClient, event, nodeId, dl1LogName, referenceSourceNode) printSeparatorWithMessage('Finished') } } diff --git a/src/currency-l1/index.js b/src/currency-l1/index.js index c82ea70..fb849f4 100644 --- a/src/currency-l1/index.js +++ b/src/currency-l1/index.js @@ -10,11 +10,10 @@ import { } from '../shared/index.js' import { LAYERS } from '../utils/types.js' -const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2InstancesIds) => { +const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2InstancesIds, referenceSourceNode) => { const cl1Keys = await getKeys(ssmClient, event.aws.ec2.instances.genesis.id, 'cl1') const { ports } = event.metagraph - const { gl0_node_ip, gl0_node_id, gl0_node_port } = event.network const { id, required_env_variables, @@ -31,9 +30,9 @@ const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2Insta `export CL_P2P_HTTP_PORT=${ports.currency_l1_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.currency_l1_cli_port}`, - `export CL_GLOBAL_L0_PEER_HTTP_HOST=${gl0_node_ip}`, - `export CL_GLOBAL_L0_PEER_HTTP_PORT=${gl0_node_port}`, - `export CL_GLOBAL_L0_PEER_ID=${gl0_node_id}`, + `export CL_GLOBAL_L0_PEER_HTTP_HOST=${referenceSourceNode.ip}`, + `export CL_GLOBAL_L0_PEER_HTTP_PORT=${referenceSourceNode.port}`, + `export CL_GLOBAL_L0_PEER_ID=${referenceSourceNode.id}`, `export CL_L0_PEER_HTTP_HOST=${event.aws.ec2.instances.genesis.ip}`, `export CL_L0_PEER_HTTP_PORT=${ports.metagraph_l0_public_port}`, @@ -57,9 +56,8 @@ const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2Insta await sendCommand(ssmClient, commands, ec2InstancesIds) } -const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceIp, ec2InstancesIds) => { +const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceIp, ec2InstancesIds, referenceSourceNode) => { const { ports } = event.metagraph - const { gl0_node_ip, gl0_node_id, gl0_node_port } = event.network const { id, required_env_variables, @@ -72,9 +70,9 @@ const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceI `export CL_P2P_HTTP_PORT=${ports.currency_l1_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.currency_l1_cli_port}`, - `export CL_GLOBAL_L0_PEER_HTTP_HOST=${gl0_node_ip}`, - `export CL_GLOBAL_L0_PEER_HTTP_PORT=${gl0_node_port}`, - `export CL_GLOBAL_L0_PEER_ID=${gl0_node_id}`, + `export CL_GLOBAL_L0_PEER_HTTP_HOST=${referenceSourceNode.ip}`, + `export CL_GLOBAL_L0_PEER_HTTP_PORT=${referenceSourceNode.port}`, + `export CL_GLOBAL_L0_PEER_ID=${referenceSourceNode.id}`, `export CL_L0_PEER_HTTP_HOST=${event.aws.ec2.instances.genesis.ip}`, `export CL_L0_PEER_HTTP_PORT=${ports.metagraph_l0_public_port}`, @@ -98,12 +96,12 @@ const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceI await sendCommand(ssmClient, [...keys, ...commands], ec2InstancesIds) } -const restartCurrencyL1Nodes = async (ssmClient, event, metagraphL0NodeId, logName) => { +const restartCurrencyL1Nodes = async (ssmClient, event, metagraphL0NodeId, logName, referenceSourceNode) => { const allEC2NodesIntances = getAllEC2NodesInstances(event) await saveLogs(ssmClient, event, logName, LAYERS.CURRENCY_L1, allEC2NodesIntances) printSeparatorWithMessage('Starting initial validator currency l1 node') - await startInitialValidatorNodeL1(ssmClient, event, metagraphL0NodeId, [event.aws.ec2.instances.genesis.id]) + await startInitialValidatorNodeL1(ssmClient, event, metagraphL0NodeId, [event.aws.ec2.instances.genesis.id], referenceSourceNode) printSeparatorWithMessage('Finished') printSeparatorWithMessage('Starting validators currency l1 node') @@ -120,7 +118,8 @@ const restartCurrencyL1Nodes = async (ssmClient, event, metagraphL0NodeId, logNa `export CL_PASSWORD="${validator1Keys.password}"` ], validator.ip, - [validator.id] + [validator.id], + referenceSourceNode ) } printSeparatorWithMessage('Finished') diff --git a/src/data-l1/index.js b/src/data-l1/index.js index 4fdeff2..5cfac98 100644 --- a/src/data-l1/index.js +++ b/src/data-l1/index.js @@ -10,11 +10,10 @@ import { } from '../shared/index.js' import { LAYERS } from '../utils/types.js' -const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2InstancesIds) => { +const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2InstancesIds, referenceSourceNode) => { const dl1Keys = await getKeys(ssmClient, event.aws.ec2.instances.genesis.id, 'dl1') const { ports } = event.metagraph - const { gl0_node_ip, gl0_node_id, gl0_node_port } = event.network const { id, required_env_variables, @@ -31,9 +30,9 @@ const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2Insta `export CL_P2P_HTTP_PORT=${ports.data_l1_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.data_l1_cli_port}`, - `export CL_GLOBAL_L0_PEER_HTTP_HOST=${gl0_node_ip}`, - `export CL_GLOBAL_L0_PEER_HTTP_PORT=${gl0_node_port}`, - `export CL_GLOBAL_L0_PEER_ID=${gl0_node_id}`, + `export CL_GLOBAL_L0_PEER_HTTP_HOST=${referenceSourceNode.ip}`, + `export CL_GLOBAL_L0_PEER_HTTP_PORT=${referenceSourceNode.port}`, + `export CL_GLOBAL_L0_PEER_ID=${referenceSourceNode.id}`, `export CL_L0_PEER_HTTP_HOST=${event.aws.ec2.instances.genesis.ip}`, `export CL_L0_PEER_HTTP_PORT=${ports.metagraph_l0_public_port}`, @@ -57,9 +56,8 @@ const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2Insta await sendCommand(ssmClient, commands, ec2InstancesIds) } -const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceIp, ec2InstancesIds) => { +const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceIp, ec2InstancesIds, referenceSourceNode) => { const { ports } = event.metagraph - const { gl0_node_ip, gl0_node_id, gl0_node_port } = event.network const { id, required_env_variables, @@ -72,9 +70,9 @@ const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceI `export CL_P2P_HTTP_PORT=${ports.data_l1_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.data_l1_cli_port}`, - `export CL_GLOBAL_L0_PEER_HTTP_HOST=${gl0_node_ip}`, - `export CL_GLOBAL_L0_PEER_HTTP_PORT=${gl0_node_port}`, - `export CL_GLOBAL_L0_PEER_ID=${gl0_node_id}`, + `export CL_GLOBAL_L0_PEER_HTTP_HOST=${referenceSourceNode.ip}`, + `export CL_GLOBAL_L0_PEER_HTTP_PORT=${referenceSourceNode.port}`, + `export CL_GLOBAL_L0_PEER_ID=${referenceSourceNode.id}`, `export CL_L0_PEER_HTTP_HOST=${event.aws.ec2.instances.genesis.ip}`, `export CL_L0_PEER_HTTP_PORT=${ports.metagraph_l0_public_port}`, @@ -98,12 +96,12 @@ const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceI await sendCommand(ssmClient, [...keys, ...commands], ec2InstancesIds) } -const restartDataL1Nodes = async (ssmClient, event, metagraphL0NodeId, logName) => { +const restartDataL1Nodes = async (ssmClient, event, metagraphL0NodeId, logName, referenceSourceNode) => { const allEC2NodesIntances = getAllEC2NodesInstances(event) await saveLogs(ssmClient, event, logName, LAYERS.DATA_L1, allEC2NodesIntances) printSeparatorWithMessage('Starting initial validator data l1 node') - await startInitialValidatorNodeL1(ssmClient, event, metagraphL0NodeId, [event.aws.ec2.instances.genesis.id]) + await startInitialValidatorNodeL1(ssmClient, event, metagraphL0NodeId, [event.aws.ec2.instances.genesis.id], referenceSourceNode) printSeparatorWithMessage('Finished') printSeparatorWithMessage('Starting validators data L1 nodes') @@ -120,7 +118,8 @@ const restartDataL1Nodes = async (ssmClient, event, metagraphL0NodeId, logName) `export CL_PASSWORD="${validator1Keys.password}"` ], validator.ip, - [validator.id] + [validator.id], + referenceSourceNode ) } printSeparatorWithMessage('Finished') diff --git a/src/metagraph-l0/index.js b/src/metagraph-l0/index.js index 06b1904..1b5b3e8 100644 --- a/src/metagraph-l0/index.js +++ b/src/metagraph-l0/index.js @@ -11,11 +11,10 @@ import { } from '../shared/index.js' import { DYNAMO_RESTART_STATE, LAYERS } from '../utils/types.js' -const startRollbackFirstNodeL0 = async (ssmClient, event, ec2InstancesIds) => { +const startRollbackFirstNodeL0 = async (ssmClient, event, ec2InstancesIds, referenceSourceNode) => { const l0Keys = await getKeys(ssmClient, event.aws.ec2.instances.genesis.id, LAYERS.L0) const { ports } = event.metagraph - const { gl0_node_ip, gl0_node_id, gl0_node_port } = event.network const { id, required_env_variables, @@ -32,9 +31,9 @@ const startRollbackFirstNodeL0 = async (ssmClient, event, ec2InstancesIds) => { `export CL_P2P_HTTP_PORT=${ports.metagraph_l0_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.metagraph_l0_cli_port}`, - `export CL_GLOBAL_L0_PEER_HTTP_HOST=${gl0_node_ip}`, - `export CL_GLOBAL_L0_PEER_HTTP_PORT=${gl0_node_port}`, - `export CL_GLOBAL_L0_PEER_ID=${gl0_node_id}`, + `export CL_GLOBAL_L0_PEER_HTTP_HOST=${referenceSourceNode.ip}`, + `export CL_GLOBAL_L0_PEER_HTTP_PORT=${referenceSourceNode.port}`, + `export CL_GLOBAL_L0_PEER_ID=${referenceSourceNode.id}`, `export CL_L0_TOKEN_IDENTIFIER=${id}`, `export CL_APP_ENV=${required_env_variables.cl_app_env}`, @@ -54,9 +53,8 @@ const startRollbackFirstNodeL0 = async (ssmClient, event, ec2InstancesIds) => { await sendCommand(ssmClient, commands, ec2InstancesIds) } -const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2InstancesIds) => { +const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2InstancesIds, referenceSourceNode) => { const { ports } = event.metagraph - const { gl0_node_ip, gl0_node_id, gl0_node_port } = event.network const { id, required_env_variables, @@ -68,9 +66,9 @@ const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2Insta `export CL_PUBLIC_HTTP_PORT=${ports.metagraph_l0_public_port}`, `export CL_P2P_HTTP_PORT=${ports.metagraph_l0_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.metagraph_l0_cli_port}`, - `export CL_GLOBAL_L0_PEER_HTTP_HOST=${gl0_node_ip}`, - `export CL_GLOBAL_L0_PEER_HTTP_PORT=${gl0_node_port}`, - `export CL_GLOBAL_L0_PEER_ID=${gl0_node_id}`, + `export CL_GLOBAL_L0_PEER_HTTP_HOST=${referenceSourceNode.ip}`, + `export CL_GLOBAL_L0_PEER_HTTP_PORT=${referenceSourceNode.port}`, + `export CL_GLOBAL_L0_PEER_ID=${referenceSourceNode.id}`, `export CL_L0_TOKEN_IDENTIFIER=${id}`, `export CL_APP_ENV=${required_env_variables.cl_app_env}`, `export CL_COLLATERAL=${required_env_variables.cl_collateral}`, @@ -89,13 +87,13 @@ const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2Insta await sendCommand(ssmClient, [...keys, ...commands], ec2InstancesIds) } -const restartL0Nodes = async (ssmClient, event, logName, currentMetagraphRestart) => { +const restartL0Nodes = async (ssmClient, event, logName, currentMetagraphRestart, referenceSourceNode) => { if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { const allEC2NodesIntances = getAllEC2NodesInstances(event) await saveLogs(ssmClient, event, logName, LAYERS.L0, allEC2NodesIntances) printSeparatorWithMessage('Starting rollback genesis l0 node') - await startRollbackFirstNodeL0(ssmClient, event, [event.aws.ec2.instances.genesis.id]) + await startRollbackFirstNodeL0(ssmClient, event, [event.aws.ec2.instances.genesis.id], referenceSourceNode) console.log("Updating state to ROLLBACK_IN_PROGRESS") currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS) @@ -119,7 +117,8 @@ const restartL0Nodes = async (ssmClient, event, logName, currentMetagraphRestart `export CL_PASSWORD="${validator1Keys.password}"` ], validator.ip, - [validator.id] + [validator.id], + referenceSourceNode ) } printSeparatorWithMessage('Finished') diff --git a/src/shared/index.js b/src/shared/index.js index 5dab8d6..726910b 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -1,6 +1,6 @@ import axios from 'axios' import { SendCommandCommand, GetParameterCommand } from '@aws-sdk/client-ssm' -import { LAYERS } from '../utils/types.js' +import { LAYERS, NETWORK_NODES } from '../utils/types.js' const sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)) @@ -28,6 +28,69 @@ const getLastMetagraphInfo = async (event) => { } } +const getLatestMetagraphOfNetwork = async (networkName) => { + const beUrl = `https://be-${networkName}.constellationnetwork.io/global-snapshots/latest` + try { + const response = await axios.get(beUrl) + const lastSnapshotOrdinal = response.data.data.ordinal + const lastSnapshotHash = response.data.data.hash + + console.log(`LAST SNAPSHOT OF NETWORK: ${networkName}. Ordinal: ${lastSnapshotOrdinal}. Hash: ${lastSnapshotHash}`) + + return { + lastSnapshotOrdinal, + lastSnapshotHash + } + } catch (e) { + console.log(e) + throw Error(`Error when searching for snapshot on: ${beUrl}`, e) + } +} + +const checkIfSnapshotExistsOnNode = async (nodeIp, nodePort, snapshotHash) => { + const nodeUrl = `http://${nodeIp}:${nodePort}/global-snapshots/${snapshotHash}` + try { + await axios.get(nodeUrl) + console.log(`Snapshot exists on node: ${nodeIp}`) + return true + } catch (e) { + console.log(`Snapshot does not exists on node: ${nodeIp}`) + return false + } +} + +const getReferenceSourceNode = async (event) => { + const { network } = event + const networkName = network.name + + console.log(`Starting to get reference source node for network: ${networkName}`) + + const networkNodes = NETWORK_NODES[networkName] + if (!networkNodes || Object.keys(networkNodes).length === 0) { + throw Error(`Could not find nodes of network: ${networkName}`) + } + + const { node_1, node_2, node_3 } = networkNodes + const { lastSnapshotHash } = await getLatestMetagraphOfNetwork(networkName) + + const snapshotExistsOnNode1 = await checkIfSnapshotExistsOnNode(node_1.ip, node_1.port, lastSnapshotHash) + if(snapshotExistsOnNode1){ + return node_1 + } + + const snapshotExistsOnNode2 = await checkIfSnapshotExistsOnNode(node_2.ip, node_2.port, lastSnapshotHash) + if(snapshotExistsOnNode2){ + return node_2 + } + + const snapshotExistsOnNode3 = await checkIfSnapshotExistsOnNode(node_3.ip, node_3.port, lastSnapshotHash) + if(snapshotExistsOnNode3){ + return node_3 + } + + return null +} + const sendCommand = async (ssmClient, commands, ec2InstancesIds) => { const params = { DocumentName: "AWS-RunShellScript", @@ -287,7 +350,7 @@ const getUnhealthyClusters = async (event) => { const response = await axios.get(url) const clusterInfo = response.data const isL0Url = url.includes(ports.metagraph_l0_public_port) - + if (isL0Url) { const anyNodeReady = clusterInfo.some(node => { return node.state === 'Ready' @@ -361,5 +424,6 @@ export { getAllEC2NodesInstances, deleteSnapshotNotSyncToGL0, getUnhealthyClusters, - checkIfRollbackFinished + checkIfRollbackFinished, + getReferenceSourceNode } \ No newline at end of file diff --git a/src/utils/types.js b/src/utils/types.js index 696835f..2454972 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -27,6 +27,60 @@ const DYNAMO_RESTART_STATE = { const DYNAMO_DB_TABLE_AUTO_RESTART = 'auto_restart' +const NETWORK_NODES = { + testnet: { + node_1: { + ip: "13.57.186.140", + port: 9000, + id: "e2f4496e5872682d7a55aa06e507a58e96b5d48a5286bfdff7ed780fa464d9e789b2760ecd840f4cb3ee6e1c1d81b2ee844c88dbebf149b1084b7313eb680714" + }, + node_2: { + ip: "54.193.165.70", + port: 9000, + id: "3458a688925a4bd89f2ac2c695362e44d2e0c2903bdbb41b341a4d39283b22d8c85b487bd33cc5d36dbe5e31b5b00a10a6eab802718ead4ed7192ade5a5d1941" + }, + node_3: { + ip: "54.177.255.227", + port: 9000, + id: "46daea11ca239cb8c0c8cdeb27db9dbe9c03744908a8a389a60d14df2ddde409260a93334d74957331eec1af323f458b12b3a6c3b8e05885608aae7e3a77eac7" + }, + }, + integrationnet: { + node_1: { + ip: "3.101.147.116", + port: 9000, + id: "e2f4496e5872682d7a55aa06e507a58e96b5d48a5286bfdff7ed780fa464d9e789b2760ecd840f4cb3ee6e1c1d81b2ee844c88dbebf149b1084b7313eb680714" + }, + node_2: { + ip: "52.53.216.201", + port: 9000, + id: "3458a688925a4bd89f2ac2c695362e44d2e0c2903bdbb41b341a4d39283b22d8c85b487bd33cc5d36dbe5e31b5b00a10a6eab802718ead4ed7192ade5a5d1941" + }, + node_3: { + ip: "54.67.6.165", + port: 9000, + id: "46daea11ca239cb8c0c8cdeb27db9dbe9c03744908a8a389a60d14df2ddde409260a93334d74957331eec1af323f458b12b3a6c3b8e05885608aae7e3a77eac7" + }, + }, + mainnet: { + node_1: { + ip: "52.53.46.33", + port: 9000, + id: "e0c1ee6ec43510f0e16d2969a7a7c074a5c8cdb477c074fe9c32a9aad8cbc8ff1dff60bb81923e0db437d2686a9b65b86c403e6a21fa32b6acc4e61be4d70925" + }, + node_2: { + ip: "54.215.18.98", + port: 9000, + id: "629880a5b8d4cc6d12aec26f24230a463825c429723153aeaff29475b29e39d2406af0f8b034ba7798ae598dbd5f513d642bcbbeef088290abeadac61a0445d6" + }, + node_3: { + ip: "54.151.19.111", + port: 9000, + id: "710b3dc521b805aea7a798d61f5d4dae39601124f1f34fac9738a78047adeff60931ba522250226b87a2194d3b7d39da8d2cbffa35d6502c70f1a7e97132a4b0" + }, + } +} + export { LAYERS, VALID_NETWORKS, @@ -34,5 +88,6 @@ export { DATE_FORMAT, RESTART_REASONS, DYNAMO_RESTART_STATE, - DYNAMO_DB_TABLE_AUTO_RESTART + DYNAMO_DB_TABLE_AUTO_RESTART, + NETWORK_NODES } \ No newline at end of file From dbb4239e0824c8a14eab236e1bb7d6c33d1a7089 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Mon, 13 Nov 2023 08:53:31 -0300 Subject: [PATCH 09/30] Adding metagraph monitor to mainnet --- .../deploy-dor-metagraph-mainnet.yml | 19 ++++++++++++++++ event.json | 22 +++++++++---------- 2 files changed, 30 insertions(+), 11 deletions(-) create mode 100644 .github/workflows/deploy-dor-metagraph-mainnet.yml diff --git a/.github/workflows/deploy-dor-metagraph-mainnet.yml b/.github/workflows/deploy-dor-metagraph-mainnet.yml new file mode 100644 index 0000000..330ed82 --- /dev/null +++ b/.github/workflows/deploy-dor-metagraph-mainnet.yml @@ -0,0 +1,19 @@ +name: Deploy DOR Metagraph Monitor - Mainnet + +on: + push: + branches: + - "deploy/dor-metagraph-mainnet" +jobs: + deploy-mainnet-dor-metagraph: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Deploy DOR Metagraph Monitor - Mainnet + uses: "./.github/templates/deploy" + with: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID_DOR }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY_DOR }} + AWS_REGION: ${{ secrets.AWS_REGION_DOR}} + AWS_LAMBDA_FUNCTION_NAME: MainnetMetagraphMonitor \ No newline at end of file diff --git a/event.json b/event.json index 8661517..a1a5cab 100644 --- a/event.json +++ b/event.json @@ -1,6 +1,6 @@ { "metagraph": { - "id": "DAG5kfY9GoHF1CYaY8tuRJxmB3JSzAEARJEAkA2C", + "id": "DAG0CyySf35ftDQDQBnd1bdQ9aPyUdacMghpnCuM", "name": "DOR", "include_currency_l1_layer": true, "include_data_l1_layer": true, @@ -21,35 +21,35 @@ "data_l1_cli_port": 9002 }, "required_env_variables": { - "cl_app_env": "integrationnet", + "cl_app_env": "mainnet", "cl_collateral": 0 }, "additional_metagraph_l0_env_variables": [ - "METAGRAPH_L0_NODE_URL=http://54.218.46.24:7000/cluster/info", - "DATA_L1_NODE_URL=http://54.218.46.24:9000/cluster/info" + "METAGRAPH_L0_NODE_URL=http://54.191.143.191:7000/cluster/info", + "DATA_L1_NODE_URL=http://54.191.143.191:9000/cluster/info" ], "additional_currency_l1_env_variables": [], "additional_data_l1_env_variables": [] }, "network": { - "name": "integrationnet" + "name": "mainnet" }, "aws": { "region": "us-west-2", "ec2": { "instances": { "genesis": { - "id": "i-03b3276264675e661", - "ip": "54.218.46.24" + "id": "i-02cd28287c031457d", + "ip": "54.191.143.191" }, "validators": [ { - "id": "i-074aabc2ebd03819b", - "ip": "34.212.237.118" + "id": "i-023598d60862a9575", + "ip": "54.213.58.75" }, { - "id": "i-0cc80924a8124f3e6", - "ip": "34.219.123.201" + "id": "i-0a29153b8b04ab7c1", + "ip": "34.211.239.153" } ] } From 55d01ab9877e1935b6e3718d780c4daaf3c0c0ed Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Mon, 13 Nov 2023 09:13:26 -0300 Subject: [PATCH 10/30] Updating --- my_deployment_package.zip | Bin 17382211 -> 17384993 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/my_deployment_package.zip b/my_deployment_package.zip index 6827c25793c9d46ff5868585af34417f64db47ec..9792d77e2ee65cae0af40c4fc89fca61bea133f0 100644 GIT binary patch delta 289594 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 z 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 delta 284875 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 z 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 Date: Mon, 13 Nov 2023 11:23:25 -0300 Subject: [PATCH 11/30] Updating mainnet nodes --- src/utils/types.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/utils/types.js b/src/utils/types.js index 2454972..80e3d18 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -62,21 +62,22 @@ const NETWORK_NODES = { id: "46daea11ca239cb8c0c8cdeb27db9dbe9c03744908a8a389a60d14df2ddde409260a93334d74957331eec1af323f458b12b3a6c3b8e05885608aae7e3a77eac7" }, }, + //DOR METAGRAPH GL0s mainnet: { node_1: { - ip: "52.53.46.33", + ip: "54.191.143.91", port: 9000, - id: "e0c1ee6ec43510f0e16d2969a7a7c074a5c8cdb477c074fe9c32a9aad8cbc8ff1dff60bb81923e0db437d2686a9b65b86c403e6a21fa32b6acc4e61be4d70925" + id: "ced1b13081d75a8c2e1463a8c2ff09f1ea14ff7af3265bcd3d4acfa3290626f965001a7ed6dbf2a748145ddecf1eb8ffeddf42d29dee3541a769601ea4cbba02" }, node_2: { - ip: "54.215.18.98", + ip: "54.213.58.75", port: 9000, - id: "629880a5b8d4cc6d12aec26f24230a463825c429723153aeaff29475b29e39d2406af0f8b034ba7798ae598dbd5f513d642bcbbeef088290abeadac61a0445d6" + id: "c54ccbea2a8d3c989281a51e7e41298e1e0f668c0c8112f1837944d137744d0c38c0a493d0c45ddfe5e0489bef180bccfcd654b250a539116e83965b90e0413c" }, node_3: { - ip: "54.151.19.111", + ip: "34.211.239.153", port: 9000, - id: "710b3dc521b805aea7a798d61f5d4dae39601124f1f34fac9738a78047adeff60931ba522250226b87a2194d3b7d39da8d2cbffa35d6502c70f1a7e97132a4b0" + id: "f27242529710fd85a58fcacba31e34857e9bc92d622b4ca856c79a12825bca8fa133dd5697fd650d3caedc93d1524670dd1150b266505c1350d8aafce5f364f8" }, } } From 94769a23992251cde329c222927bac7cf4d5ffb7 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Mon, 13 Nov 2023 14:29:43 -0300 Subject: [PATCH 12/30] Fixing --- src/utils/types.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/utils/types.js b/src/utils/types.js index 80e3d18..2454972 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -62,22 +62,21 @@ const NETWORK_NODES = { id: "46daea11ca239cb8c0c8cdeb27db9dbe9c03744908a8a389a60d14df2ddde409260a93334d74957331eec1af323f458b12b3a6c3b8e05885608aae7e3a77eac7" }, }, - //DOR METAGRAPH GL0s mainnet: { node_1: { - ip: "54.191.143.91", + ip: "52.53.46.33", port: 9000, - id: "ced1b13081d75a8c2e1463a8c2ff09f1ea14ff7af3265bcd3d4acfa3290626f965001a7ed6dbf2a748145ddecf1eb8ffeddf42d29dee3541a769601ea4cbba02" + id: "e0c1ee6ec43510f0e16d2969a7a7c074a5c8cdb477c074fe9c32a9aad8cbc8ff1dff60bb81923e0db437d2686a9b65b86c403e6a21fa32b6acc4e61be4d70925" }, node_2: { - ip: "54.213.58.75", + ip: "54.215.18.98", port: 9000, - id: "c54ccbea2a8d3c989281a51e7e41298e1e0f668c0c8112f1837944d137744d0c38c0a493d0c45ddfe5e0489bef180bccfcd654b250a539116e83965b90e0413c" + id: "629880a5b8d4cc6d12aec26f24230a463825c429723153aeaff29475b29e39d2406af0f8b034ba7798ae598dbd5f513d642bcbbeef088290abeadac61a0445d6" }, node_3: { - ip: "34.211.239.153", + ip: "54.151.19.111", port: 9000, - id: "f27242529710fd85a58fcacba31e34857e9bc92d622b4ca856c79a12825bca8fa133dd5697fd650d3caedc93d1524670dd1150b266505c1350d8aafce5f364f8" + id: "710b3dc521b805aea7a798d61f5d4dae39601124f1f34fac9738a78047adeff60931ba522250226b87a2194d3b7d39da8d2cbffa35d6502c70f1a7e97132a4b0" }, } } From 56a00b8dcb02a61f79fb6fca91b5f1d564c1909f Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 14 Nov 2023 09:45:32 -0300 Subject: [PATCH 13/30] Adding feature to move snapshots instead of deleting --- src/shared/index.js | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/shared/index.js b/src/shared/index.js index b72fff9..5b7cea7 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -79,42 +79,39 @@ const killCurrentProcesses = async (ssmClient, event, ec2InstancesIds) => { await sendCommand(ssmClient, commands, ec2InstancesIds) } -const getRemoveInstructionByOrdinal = async (event, ordinal) => { - const beUrl = `https://be-${event.network.name}.constellationnetwork.io/currency/${event.metagraph.id}/snapshots/${ordinal}` - try { - const response = await axios.get(beUrl) - const lastSnapshotOrdinal = response.data.data.ordinal - const lastSnapshotHash = response.data.data.hash - - return [`rm data/incremental_snapshot/${lastSnapshotOrdinal}`, `rm data/incremental_snapshot/${lastSnapshotHash}`] - } catch (e) { - return [`rm data/incremental_snapshot/${ordinal}`] - } -} - const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => { const { file_system } = event.metagraph const { lastSnapshotOrdinal } = await getLastMetagraphInfo(event) const initialSnapshotToRemove = lastSnapshotOrdinal const finalSnapshotToRemove = initialSnapshotToRemove + 50 - console.log(`Removing snapshots on data folder between: ${initialSnapshotToRemove} - ${finalSnapshotToRemove}`) - - //Somehow the syntax rm data/incremental_snapshot/{x..y} doesn't work, so we put individually - const promises = [] - for (let idx = initialSnapshotToRemove; idx <= finalSnapshotToRemove; idx++) { - promises.push(getRemoveInstructionByOrdinal(event, idx)) - } - - const deletingCommands = await Promise.all(promises) - const allDeletingCommands = deletingCommands.reduce((acc, curr) => [...acc, ...curr], []) + console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) + const creatingCommands = [ + `cd ${file_system.base_metagraph_l0_directory}`, + `mkdir -p data/incremental_snapshot_bkp`, + + `echo "# Set the source and target directories + source_dir="data/incremental_snapshot" + target_dir="data/incremental_snapshot_bkp/" + # Use find to locate the files within the specified range + for ((i=\$1; i<=\$2; i++)); do + echo "Processing file with ID \$source_dir/\$i" + find data/incremental_snapshot -mount -samefile data/incremental_snapshot/\$i -exec mv {} "\$target_dir" \; + done" > mv_snapshots.sh`, + + `sudo chmod +x mv_snapshots.sh`, + ] + await sendCommand(ssmClient, creatingCommands, ec2InstancesIds) + console.log(`Finished creating mv_snapshot.sh script`) + console.log(`Moving incremental snapshots on data/incremental_snapshot to data/incremental_snapshot_bkp between: ${initialSnapshotToRemove} - ${finalSnapshotToRemove}`) const commands = [ `cd ${file_system.base_metagraph_l0_directory}`, - ...allDeletingCommands + `/mv_snapshots.sh ${initialSnapshotToRemove} ${finalSnapshotToRemove}` ] await sendCommand(ssmClient, commands, ec2InstancesIds) + console.log(`Finishing moving the snapshots`) } const joinNodeToCluster = async (ssmClient, event, layer, joiningNodeId, ec2InstancesIds) => { From aa540e89122fcfc28b3fd290e6b290c7444f0ed3 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 14 Nov 2023 14:56:24 -0300 Subject: [PATCH 14/30] Fixing CR comment --- src/shared/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shared/index.js b/src/shared/index.js index 5b7cea7..18b3ba8 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -86,13 +86,14 @@ const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => const finalSnapshotToRemove = initialSnapshotToRemove + 50 console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) + const bkpDirectoryName = `incremental_snapshot_bkp_${moment.utc().format('YYYY_MM_DD_HH_mm_ss')}` const creatingCommands = [ `cd ${file_system.base_metagraph_l0_directory}`, - `mkdir -p data/incremental_snapshot_bkp`, + `mkdir -p data/${bkpDirectoryName}`, `echo "# Set the source and target directories source_dir="data/incremental_snapshot" - target_dir="data/incremental_snapshot_bkp/" + target_dir="data/${bkpDirectoryName}/" # Use find to locate the files within the specified range for ((i=\$1; i<=\$2; i++)); do echo "Processing file with ID \$source_dir/\$i" From 483f1fb9ddfa6f029389c7df1810e90947d4909b Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 14 Nov 2023 09:45:32 -0300 Subject: [PATCH 15/30] Adding feature to move snapshots instead of deleting --- src/shared/index.js | 45 +++++++++++++++++++++------------------------ 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/src/shared/index.js b/src/shared/index.js index 726910b..86348e2 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -141,42 +141,39 @@ const killCurrentProcesses = async (ssmClient, event, ec2InstancesIds) => { await sendCommand(ssmClient, commands, ec2InstancesIds) } -const getRemoveInstructionByOrdinal = async (event, ordinal) => { - const beUrl = `https://be-${event.network.name}.constellationnetwork.io/currency/${event.metagraph.id}/snapshots/${ordinal}` - try { - const response = await axios.get(beUrl) - const lastSnapshotOrdinal = response.data.data.ordinal - const lastSnapshotHash = response.data.data.hash - - return [`rm data/incremental_snapshot/${lastSnapshotOrdinal}`, `rm data/incremental_snapshot/${lastSnapshotHash}`] - } catch (e) { - return [`rm data/incremental_snapshot/${ordinal}`] - } -} - const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => { const { file_system } = event.metagraph const { lastSnapshotOrdinal } = await getLastMetagraphInfo(event) const initialSnapshotToRemove = lastSnapshotOrdinal const finalSnapshotToRemove = initialSnapshotToRemove + 50 - console.log(`Removing snapshots on data folder between: ${initialSnapshotToRemove} - ${finalSnapshotToRemove}`) - - //Somehow the syntax rm data/incremental_snapshot/{x..y} doesn't work, so we put individually - const promises = [] - for (let idx = initialSnapshotToRemove; idx <= finalSnapshotToRemove; idx++) { - promises.push(getRemoveInstructionByOrdinal(event, idx)) - } - - const deletingCommands = await Promise.all(promises) - const allDeletingCommands = deletingCommands.reduce((acc, curr) => [...acc, ...curr], []) + console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) + const creatingCommands = [ + `cd ${file_system.base_metagraph_l0_directory}`, + `mkdir -p data/incremental_snapshot_bkp`, + + `echo "# Set the source and target directories + source_dir="data/incremental_snapshot" + target_dir="data/incremental_snapshot_bkp/" + # Use find to locate the files within the specified range + for ((i=\$1; i<=\$2; i++)); do + echo "Processing file with ID \$source_dir/\$i" + find data/incremental_snapshot -mount -samefile data/incremental_snapshot/\$i -exec mv {} "\$target_dir" \; + done" > mv_snapshots.sh`, + + `sudo chmod +x mv_snapshots.sh`, + ] + await sendCommand(ssmClient, creatingCommands, ec2InstancesIds) + console.log(`Finished creating mv_snapshot.sh script`) + console.log(`Moving incremental snapshots on data/incremental_snapshot to data/incremental_snapshot_bkp between: ${initialSnapshotToRemove} - ${finalSnapshotToRemove}`) const commands = [ `cd ${file_system.base_metagraph_l0_directory}`, - ...allDeletingCommands + `/mv_snapshots.sh ${initialSnapshotToRemove} ${finalSnapshotToRemove}` ] await sendCommand(ssmClient, commands, ec2InstancesIds) + console.log(`Finishing moving the snapshots`) } const joinNodeToCluster = async (ssmClient, event, layer, joiningNodeId, ec2InstancesIds) => { From e777f0e8a7ff01abf01629bef77586f1a11fc7ce Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 14 Nov 2023 14:56:24 -0300 Subject: [PATCH 16/30] Fixing CR comment --- src/shared/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shared/index.js b/src/shared/index.js index 86348e2..bc739d5 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -148,13 +148,14 @@ const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => const finalSnapshotToRemove = initialSnapshotToRemove + 50 console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) + const bkpDirectoryName = `incremental_snapshot_bkp_${moment.utc().format('YYYY_MM_DD_HH_mm_ss')}` const creatingCommands = [ `cd ${file_system.base_metagraph_l0_directory}`, - `mkdir -p data/incremental_snapshot_bkp`, + `mkdir -p data/${bkpDirectoryName}`, `echo "# Set the source and target directories source_dir="data/incremental_snapshot" - target_dir="data/incremental_snapshot_bkp/" + target_dir="data/${bkpDirectoryName}/" # Use find to locate the files within the specified range for ((i=\$1; i<=\$2; i++)); do echo "Processing file with ID \$source_dir/\$i" From 195a51987a85d7cd75ea6506a6a3e0a1a4e5cfe5 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Wed, 15 Nov 2023 15:59:53 -0300 Subject: [PATCH 17/30] Adding moment --- src/shared/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shared/index.js b/src/shared/index.js index bc739d5..8e79b68 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -1,4 +1,5 @@ import axios from 'axios' +import moment from 'moment' import { SendCommandCommand, GetParameterCommand } from '@aws-sdk/client-ssm' import { LAYERS, NETWORK_NODES } from '../utils/types.js' From c34c13d498d3f7f3d034b46cb491dfd8436d4daa Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Sun, 19 Nov 2023 10:35:35 -0300 Subject: [PATCH 18/30] Fixing --- src/shared/index.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shared/index.js b/src/shared/index.js index 8e79b68..a21f725 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -146,7 +146,7 @@ const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => const { file_system } = event.metagraph const { lastSnapshotOrdinal } = await getLastMetagraphInfo(event) const initialSnapshotToRemove = lastSnapshotOrdinal - const finalSnapshotToRemove = initialSnapshotToRemove + 50 + const finalSnapshotToRemove = initialSnapshotToRemove + 100 console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) const bkpDirectoryName = `incremental_snapshot_bkp_${moment.utc().format('YYYY_MM_DD_HH_mm_ss')}` @@ -158,9 +158,9 @@ const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => source_dir="data/incremental_snapshot" target_dir="data/${bkpDirectoryName}/" # Use find to locate the files within the specified range - for ((i=\$1; i<=\$2; i++)); do - echo "Processing file with ID \$source_dir/\$i" - find data/incremental_snapshot -mount -samefile data/incremental_snapshot/\$i -exec mv {} "\$target_dir" \; + for ((i=$1; i<=$2; i++)); do + echo "Processing file with ID $source_dir/$i" + find data/incremental_snapshot -mount -samefile data/incremental_snapshot/$i -exec mv {} "$target_dir"; done" > mv_snapshots.sh`, `sudo chmod +x mv_snapshots.sh`, @@ -171,7 +171,7 @@ const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => console.log(`Moving incremental snapshots on data/incremental_snapshot to data/incremental_snapshot_bkp between: ${initialSnapshotToRemove} - ${finalSnapshotToRemove}`) const commands = [ `cd ${file_system.base_metagraph_l0_directory}`, - `/mv_snapshots.sh ${initialSnapshotToRemove} ${finalSnapshotToRemove}` + `./mv_snapshots.sh ${initialSnapshotToRemove} ${finalSnapshotToRemove}` ] await sendCommand(ssmClient, commands, ec2InstancesIds) From fe7c83945553b89ca71d6d9a6d04730aa6d2c9f5 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Sun, 19 Nov 2023 10:37:47 -0300 Subject: [PATCH 19/30] Increasing timeout --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index c80ceed..76a7005 100644 --- a/index.js +++ b/index.js @@ -19,7 +19,7 @@ import { createMetagraphRestartSuccessfullyAlert, createMetagraphRestartFailureA import { LAYERS, VALID_NETWORKS, RESTART_REASONS, DYNAMO_RESTART_STATE, DATE_FORMAT } from './src/utils/types.js' import { deleteMetagraphRestart, getMetagraphRestartOrCreateNew, upsertMetagraphRestart } from './src/external/aws/dynamo.js' -const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 240 +const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 600 const getLogsNames = () => { const now = moment.utc().format('YYY-MM-DD_HH-mm-ss') From d0aab52397b3928e8b7dd019d6b6a3ca6c0687bd Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Mon, 20 Nov 2023 09:51:35 -0300 Subject: [PATCH 20/30] Updating auto-restart script to try more than one time get cluster information --- index.js | 1 + src/shared/index.js | 78 ++++++++++++++++++++++++++++----------------- src/utils/types.js | 2 ++ 3 files changed, 52 insertions(+), 29 deletions(-) diff --git a/index.js b/index.js index 76a7005..0e671f1 100644 --- a/index.js +++ b/index.js @@ -99,6 +99,7 @@ const checkIfNewSnapshotsAreProducedAfterRestart = async (event) => { const lastSnapshotTimestampDiff = moment.utc().diff(lastSnapshotTimestamp, 'minutes') if (lastSnapshotTimestampDiff > 4) { + await deleteMetagraphRestart(event.metagraph.id) throw Error("Snapshots keep not being produced even after restarting, take a look at the instances") } diff --git a/src/shared/index.js b/src/shared/index.js index a21f725..8904947 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -1,7 +1,7 @@ import axios from 'axios' import moment from 'moment' import { SendCommandCommand, GetParameterCommand } from '@aws-sdk/client-ssm' -import { LAYERS, NETWORK_NODES } from '../utils/types.js' +import { CHECK_CLUSTER_HEALTHY_LIMIT, LAYERS, NETWORK_NODES } from '../utils/types.js' const sleep = (ms) => { return new Promise(resolve => setTimeout(resolve, ms)) @@ -65,7 +65,7 @@ const getReferenceSourceNode = async (event) => { const networkName = network.name console.log(`Starting to get reference source node for network: ${networkName}`) - + const networkNodes = NETWORK_NODES[networkName] if (!networkNodes || Object.keys(networkNodes).length === 0) { throw Error(`Could not find nodes of network: ${networkName}`) @@ -75,17 +75,17 @@ const getReferenceSourceNode = async (event) => { const { lastSnapshotHash } = await getLatestMetagraphOfNetwork(networkName) const snapshotExistsOnNode1 = await checkIfSnapshotExistsOnNode(node_1.ip, node_1.port, lastSnapshotHash) - if(snapshotExistsOnNode1){ + if (snapshotExistsOnNode1) { return node_1 } const snapshotExistsOnNode2 = await checkIfSnapshotExistsOnNode(node_2.ip, node_2.port, lastSnapshotHash) - if(snapshotExistsOnNode2){ + if (snapshotExistsOnNode2) { return node_2 } const snapshotExistsOnNode3 = await checkIfSnapshotExistsOnNode(node_3.ip, node_3.port, lastSnapshotHash) - if(snapshotExistsOnNode3){ + if (snapshotExistsOnNode3) { return node_3 } @@ -331,53 +331,73 @@ const getAllEC2NodesInstances = (event) => { return [genesisNodeId, ...validatorNodesId] } -const getUnhealthyClusters = async (event) => { - const { ports } = event.metagraph - let urls = [`http://${event.aws.ec2.instances.genesis.ip}:${ports.metagraph_l0_public_port}/cluster/info`] - - if (event.metagraph.include_currency_l1_layer) { - urls.push(`http://${event.aws.ec2.instances.genesis.ip}:${ports.currency_l1_public_port}/cluster/info`) - } - - if (event.metagraph.include_data_l1_layer) { - urls.push(`http://${event.aws.ec2.instances.genesis.ip}:${ports.data_l1_public_port}/cluster/info`) - } - - const unhealthyClusters = [] - for (const url of urls) { +const _checkIfClusterIsUnhealthy = async (url, ports) => { + for (let idx = 0; idx < CHECK_CLUSTER_HEALTHY_LIMIT; idx++) { try { const response = await axios.get(url) const clusterInfo = response.data const isL0Url = url.includes(ports.metagraph_l0_public_port) + console.log(`Cluster Info ${url} response: ${JSON.stringify(clusterInfo)}`) + if (isL0Url) { + console.log(`L0 Cluster, at least one node should be Ready`) + const anyNodeReady = clusterInfo.some(node => { return node.state === 'Ready' }) if (!anyNodeReady) { console.log("All L0 nodes are not ready") - unhealthyClusters.push(url) + return true } - continue + return false } + console.log(`L1 Cluster, at least 3 nodes should be Ready`) if (clusterInfo.length < 3) { - console.log(`Less than 3: ${url}`) - unhealthyClusters.push(url) - continue + console.log(`Less than 3 nodes: ${url}`) + return true } - const anyNodeNotReady = clusterInfo.some(node => { - return node.state !== 'Ready' + const readyNodes = clusterInfo.filter(node => { + return node.state === 'Ready' }) - if (anyNodeNotReady) { - console.log(`Not READY: ${url}`) - unhealthyClusters.push(url) + if (readyNodes.length < 3) { + console.log(`We should have at least 3 ready nodes: ${url}`) + return true } + + return false } catch (e) { + if (idx === 4) { + console.log(`Unhealthy cluster after trying ${CHECK_CLUSTER_HEALTHY_LIMIT} times`) + return true + } + console.log(`Could not get cluster information at URL: ${url}. Trying again in 5s (${idx + 1}/${CHECK_CLUSTER_HEALTHY_LIMIT})`) + await sleep(5 * 1000) + } + } +} + +const getUnhealthyClusters = async (event) => { + const { ports } = event.metagraph + let urls = [`http://${event.aws.ec2.instances.genesis.ip}:${ports.metagraph_l0_public_port}/cluster/info`] + + if (event.metagraph.include_currency_l1_layer) { + urls.push(`http://${event.aws.ec2.instances.genesis.ip}:${ports.currency_l1_public_port}/cluster/info`) + } + + if (event.metagraph.include_data_l1_layer) { + urls.push(`http://${event.aws.ec2.instances.genesis.ip}:${ports.data_l1_public_port}/cluster/info`) + } + + const unhealthyClusters = [] + for (const url of urls) { + const clusterIsUnhealthy = await _checkIfClusterIsUnhealthy(url, ports) + if(clusterIsUnhealthy){ unhealthyClusters.push(url) } } diff --git a/src/utils/types.js b/src/utils/types.js index 2454972..92f070b 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -26,6 +26,7 @@ const DYNAMO_RESTART_STATE = { } const DYNAMO_DB_TABLE_AUTO_RESTART = 'auto_restart' +const CHECK_CLUSTER_HEALTHY_LIMIT = 5 const NETWORK_NODES = { testnet: { @@ -89,5 +90,6 @@ export { RESTART_REASONS, DYNAMO_RESTART_STATE, DYNAMO_DB_TABLE_AUTO_RESTART, + CHECK_CLUSTER_HEALTHY_LIMIT, NETWORK_NODES } \ No newline at end of file From 157dac725d2c1f5c04f8ea3dde8b81cdfde4561e Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Mon, 20 Nov 2023 10:42:26 -0300 Subject: [PATCH 21/30] Fixing mv_snapshot script --- src/shared/index.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/shared/index.js b/src/shared/index.js index 8904947..96af514 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -146,7 +146,7 @@ const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => const { file_system } = event.metagraph const { lastSnapshotOrdinal } = await getLastMetagraphInfo(event) const initialSnapshotToRemove = lastSnapshotOrdinal - const finalSnapshotToRemove = initialSnapshotToRemove + 100 + const finalSnapshotToRemove = initialSnapshotToRemove + 1 console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) const bkpDirectoryName = `incremental_snapshot_bkp_${moment.utc().format('YYYY_MM_DD_HH_mm_ss')}` @@ -158,9 +158,16 @@ const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => source_dir="data/incremental_snapshot" target_dir="data/${bkpDirectoryName}/" # Use find to locate the files within the specified range - for ((i=$1; i<=$2; i++)); do - echo "Processing file with ID $source_dir/$i" - find data/incremental_snapshot -mount -samefile data/incremental_snapshot/$i -exec mv {} "$target_dir"; + for i in \\$(seq \\$1 \\$2); do + source_file="\\$source_dir/\\$i" + + # Check if the source file exists before attempting to move it + if [ -e "\\$source_file" ]; then + echo "Processing file with ID \\$source_file" + find \\$source_dir -mount -samefile \\$source_file -exec mv {} "\\$target_dir" \\; + else + echo "File \\$source_file does not exist." + fi done" > mv_snapshots.sh`, `sudo chmod +x mv_snapshots.sh`, From 4b3453a34607d3722f6502f5a677f8d0355bb345 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 21 Nov 2023 12:12:13 -0300 Subject: [PATCH 22/30] Refactoring metagraph-auto-restart --- index.js | 284 +++++------ src/currency-l1/index.js | 93 ++-- src/data-l1/index.js | 93 ++-- src/external/aws/dynamo.js | 27 +- src/external/aws/ssm.js | 42 ++ .../opsgenie/index.js} | 83 ++-- src/metagraph-l0/index.js | 101 +--- src/restarts/check_restart_progress.js | 183 +++++++ src/restarts/full_cluster.js | 103 ++++ src/restarts/index.js | 12 + src/restarts/individual_cluster.js | 18 + src/restarts/individual_node.js | 79 +++ src/shared/check_nodes_health.js | 123 +++++ src/shared/get_metagraph_info.js | 235 +++++++++ src/shared/index.js | 462 +----------------- src/shared/restart_operations.js | 144 ++++++ src/shared/shared.js | 7 + src/utils/types.js | 34 +- 18 files changed, 1294 insertions(+), 829 deletions(-) create mode 100644 src/external/aws/ssm.js rename src/{services/opsgenie_service.js => external/opsgenie/index.js} (60%) create mode 100644 src/restarts/check_restart_progress.js create mode 100644 src/restarts/full_cluster.js create mode 100644 src/restarts/index.js create mode 100644 src/restarts/individual_cluster.js create mode 100644 src/restarts/individual_node.js create mode 100644 src/shared/check_nodes_health.js create mode 100644 src/shared/get_metagraph_info.js create mode 100644 src/shared/restart_operations.js create mode 100644 src/shared/shared.js diff --git a/index.js b/index.js index 0e671f1..86b94a0 100644 --- a/index.js +++ b/index.js @@ -2,81 +2,24 @@ import { SSMClient } from '@aws-sdk/client-ssm' import moment from 'moment' import { getLastMetagraphInfo, - killCurrentProcesses, - printSeparatorWithMessage, checkIfAllNodesAreReady, sleep, - getAllEC2NodesInstances, - deleteSnapshotNotSyncToGL0, - getUnhealthyClusters, - checkIfRollbackFinished, + getAllUnhealthyNodes, + getLogsNames, + groupBy, getReferenceSourceNode } from './src/shared/index.js' -import { restartL0Nodes } from './src/metagraph-l0/index.js' -import { restartCurrencyL1Nodes } from './src/currency-l1/index.js' -import { restartDataL1Nodes } from './src/data-l1/index.js' -import { createMetagraphRestartSuccessfullyAlert, createMetagraphRestartFailureAlert } from './src/services/opsgenie_service.js' -import { LAYERS, VALID_NETWORKS, RESTART_REASONS, DYNAMO_RESTART_STATE, DATE_FORMAT } from './src/utils/types.js' +import { LAYERS, RESTART_REASONS, DYNAMO_RESTART_STATE, DYNAMO_RESTART_TYPES } from './src/utils/types.js' import { deleteMetagraphRestart, getMetagraphRestartOrCreateNew, upsertMetagraphRestart } from './src/external/aws/dynamo.js' - -const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 600 - -const getLogsNames = () => { - const now = moment.utc().format('YYY-MM-DD_HH-mm-ss') - - const l0LogName = `log-${now}-l0.zip` - const cl1LogName = `log-${now}-cl1.zip` - const dl1LogName = `log-${now}-dl1.zip` - - return { - l0LogName, - cl1LogName, - dl1LogName - } -} - -const restartNodes = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogName }, currentMetagraphRestart) => { - const allEC2NodesIntances = getAllEC2NodesInstances(event) - - const referenceSourceNode = await getReferenceSourceNode(event) - if(!referenceSourceNode) { - throw Error(`Could not get reference node to network ${event.network.name}`) - } - console.log(`RefrenceSourceNode found: ${JSON.stringify(referenceSourceNode)}`) - - if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { - printSeparatorWithMessage('Killing current processes on nodes') - await killCurrentProcesses(ssmClient, event, allEC2NodesIntances) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Deleting snapshots not sent to GL0 on Metagraph') - await deleteSnapshotNotSyncToGL0(ssmClient, event, allEC2NodesIntances) - printSeparatorWithMessage('Finished') - } - - printSeparatorWithMessage('METAGRAPH L0') - const nodeId = await restartL0Nodes(ssmClient, event, l0LogName, currentMetagraphRestart, referenceSourceNode) - printSeparatorWithMessage('Finished') - - if (!nodeId || currentMetagraphRestart.state !== DYNAMO_RESTART_STATE.READY) { - console.log("Genesis node still not ready, skipping") - return - } - - if (event.metagraph.include_currency_l1_layer) { - printSeparatorWithMessage('CURRENCY L1') - await restartCurrencyL1Nodes(ssmClient, event, nodeId, cl1LogName, referenceSourceNode) - printSeparatorWithMessage('Finished') - } - - if (event.metagraph.include_data_l1_layer) { - printSeparatorWithMessage('DATA L1') - await restartDataL1Nodes(ssmClient, event, nodeId, dl1LogName, referenceSourceNode) - printSeparatorWithMessage('Finished') - } -} +import { startMetagraphRollback } from './src/restarts/full_cluster.js' +import { restartIndividualNode } from './src/restarts/individual_node.js' +import { createMetagraphRestartFailureAlert, createMetagraphRestartStartedAlert } from './src/external/opsgenie/index.js' +import { getMetagraphRestartProgress } from './src/restarts/check_restart_progress.js' +import { restartIndividualCluster } from './src/restarts/individual_cluster.js' const validateIfAllNodesAreReady = async (event) => { + console.log(`Starting validation to check if all nodes are ready`) + const promises = [] promises.push(checkIfAllNodesAreReady(event, LAYERS.L0)) @@ -89,12 +32,13 @@ const validateIfAllNodesAreReady = async (event) => { } await Promise.all(promises) + + console.log(`All nodes are ready\n\n`) } const checkIfNewSnapshotsAreProducedAfterRestart = async (event) => { - printSeparatorWithMessage("CHECKING IF NEW SNAPSHOTS WERE PRODUCED") - console.log("Waiting 30s ...") - await sleep(30000) + console.log("Checking if new snapshots was produced after restart. Waiting 10s ...") + await sleep(10 * 1000) const { lastSnapshotTimestamp } = await getLastMetagraphInfo(event) const lastSnapshotTimestampDiff = moment.utc().diff(lastSnapshotTimestamp, 'minutes') @@ -103,131 +47,195 @@ const checkIfNewSnapshotsAreProducedAfterRestart = async (event) => { throw Error("Snapshots keep not being produced even after restarting, take a look at the instances") } - printSeparatorWithMessage("New snapshots were produced") + console.log(`New snapshots were produced`) } -const shouldRestartMetagraph = async (event, lastSnapshotTimestamp) => { +const getMetagraphRestartType = async (event, lastSnapshotTimestamp) => { + console.log(`Starting to get the metagraph restart type`) + if (event.force_metagraph_restart) { - console.log('Force metagraph restart provided. Deleting dynamo row and restarting') + console.log(`Restarting FULL CLUSTER: Force metagraph restart provided`) await deleteMetagraphRestart(event.metagraph.id) return { - should_restart: true, - reason: RESTART_REASONS.FORCE_METAGRAPH_RESTART + restartType: DYNAMO_RESTART_TYPES.FULL_CLUSTER, + reason: RESTART_REASONS.FORCE_METAGRAPH_RESTART, + unhealthyNodes: {} } } const lastSnapshotTimestampDiff = moment.utc().diff(lastSnapshotTimestamp, 'minutes') if (lastSnapshotTimestampDiff > 4) { + console.log(`Restart type FULL CLUSTER: Snapshots stopped being produced`) return { - should_restart: true, - reason: RESTART_REASONS.STOP_PRODUCING_SNAPSHOTS + restartType: DYNAMO_RESTART_TYPES.FULL_CLUSTER, + reason: RESTART_REASONS.STOP_PRODUCING_SNAPSHOTS, + unhealthyNodes: {} } } - const unhealthyClusters = await getUnhealthyClusters(event) - if (unhealthyClusters.length > 0) { - console.log(`Unhealthy clusters: ${unhealthyClusters}`) + console.log(`Snapshots are being producing normally, last snapshot timestamp: ${lastSnapshotTimestamp}`) + + const unhealthyNodes = await getAllUnhealthyNodes(event) + if (unhealthyNodes.length > 0) { + const unhealthyNodesGroupedByLayer = groupBy(unhealthyNodes, 'layer') + const unhealthyMetagraphL0 = unhealthyNodesGroupedByLayer[LAYERS.L0] ?? [] + const unhealthyCurrencyL1 = unhealthyNodesGroupedByLayer[LAYERS.CURRENCY_L1] ?? [] + const unhealthyDataL1 = unhealthyNodesGroupedByLayer[LAYERS.DATA_L1] ?? [] + + if (unhealthyNodes.length === 9 || unhealthyMetagraphL0.length === 3) { + console.log(`Restart type FULL CLUSTER: Unhealthy clusters. ML0: ${JSON.stringify(unhealthyMetagraphL0)}, CL1: ${unhealthyCurrencyL1}, DL1: ${unhealthyDataL1}`) + return { + restartType: DYNAMO_RESTART_TYPES.FULL_CLUSTER, + reason: RESTART_REASONS.UNHEALTHY_CLUSTER, + unhealthyNodes: { + unhealthyMetagraphL0, + unhealthyCurrencyL1, + unhealthyDataL1 + } + } + } + + console.log(`Restart type INDIVIDUAL NODES: Unhealthy clusters. ML0: ${unhealthyMetagraphL0}, CL1: ${unhealthyCurrencyL1}, DL1: ${unhealthyDataL1}`) return { - should_restart: true, - reason: RESTART_REASONS.UNHEALTHY_CLUSTER + restartType: DYNAMO_RESTART_TYPES.INDIVIDUAL_NODES, + reason: RESTART_REASONS.UNHEALTHY_CLUSTER, + unhealthyNodes: { + unhealthyMetagraphL0, + unhealthyCurrencyL1, + unhealthyDataL1 + } } } + console.log(`Restart type NOT RESTART: Metagraph healthy`) return { - should_restart: false, - reason: '' + restartType: DYNAMO_RESTART_TYPES.NOT_RESTART, + reason: '', + unhealthyNodes: {} } } -const getCurrentMetagraphRestart = async (event) => { - printSeparatorWithMessage('GETTING CURRENT METAGRAPH RESTART') - - let currentMetagraphRestart = await getMetagraphRestartOrCreateNew(event.metagraph.id) - if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { - return currentMetagraphRestart - } - - const rollbackFinished = await checkIfRollbackFinished(event) - if (rollbackFinished) { - currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATE.READY) +const getReferenceSourceNodeFromNetwork = async (event) => { + console.log(`Getting reference source node from network`) + const referenceSourceNode = await getReferenceSourceNode(event) + if (!referenceSourceNode) { + throw Error(`Could not get reference node to network ${event.network.name}`) } - console.log("Current Metagraph Restart:", JSON.stringify(currentMetagraphRestart)) - printSeparatorWithMessage('Finished') + console.log(`ReferenceSourceNode found: ${JSON.stringify(referenceSourceNode)}`) - return currentMetagraphRestart + return referenceSourceNode } export const handler = async (event) => { const ssmClient = new SSMClient({ region: event.aws.region }) + const referenceSourceNode = await getReferenceSourceNodeFromNetwork(event) + const metagraphId = event.metagraph.id + + const currentMetagraphRestart = await getMetagraphRestartOrCreateNew(metagraphId) + const restartProgress = await getMetagraphRestartProgress( + ssmClient, + event, + currentMetagraphRestart, + referenceSourceNode + ) + + if (restartProgress.restartState !== DYNAMO_RESTART_STATE.NEW) { + return { + statusCode: 200, + body: restartProgress.body, + } + } - if (!VALID_NETWORKS.includes(event.network.name)) { - throw Error(`Network should be one of the following: ${JSON.stringify(VALID_NETWORKS)}`) + if (restartProgress.restartState === DYNAMO_RESTART_STATE.READY) { + await validateIfAllNodesAreReady(event) + await checkIfNewSnapshotsAreProducedAfterRestart(event) + + return { + statusCode: 200, + body: JSON.stringify('Metagraph healthy, after restart'), + } } - let shouldRestart = null try { const { lastSnapshotTimestamp } = await getLastMetagraphInfo(event) - - shouldRestart = await shouldRestartMetagraph(event, lastSnapshotTimestamp) - if (!shouldRestart.should_restart) { + const metagraphRestartType = await getMetagraphRestartType(event, lastSnapshotTimestamp) + if (metagraphRestartType.restartType === DYNAMO_RESTART_TYPES.NOT_RESTART) { return { statusCode: 200, body: JSON.stringify('Metagraph healthy, ignoring restart!'), } } - let currentMetagraphRestart = await getCurrentMetagraphRestart(event) - if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS) { - const lastRestartTimeDiff = moment.utc().diff(moment.utc(currentMetagraphRestart.updatedAt), 'minutes') - - if (lastRestartTimeDiff <= ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES) { - const timeoutTime = moment.utc(currentMetagraphRestart.updatedAt).add(ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES, 'minutes') + const logsNames = getLogsNames() - console.log(`Operation running since: ${currentMetagraphRestart.updatedAt} will timeout at ${timeoutTime.format(DATE_FORMAT)}`) + if (metagraphRestartType.restartType === DYNAMO_RESTART_TYPES.FULL_CLUSTER) { + await startMetagraphRollback(ssmClient, event, logsNames.l0LogName, referenceSourceNode) + const metagraphRestart = await upsertMetagraphRestart( + metagraphId, + DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS, + DYNAMO_RESTART_TYPES.FULL_CLUSTER, + metagraphRestartType.reason, + event.aws.ec2.instances.genesis.ip + ) - return { - statusCode: 200, - body: JSON.stringify('There is already one ROLLBACK_IN_PROGRESS for this metagraph, please wait this operation could take hours'), - } + await createMetagraphRestartStartedAlert(ssmClient, event, metagraphRestart) + return { + statusCode: 200, + body: JSON.stringify(RESTART_REASONS.STOP_PRODUCING_SNAPSHOTS), } - await deleteMetagraphRestart(event.metagraph.id) - await createMetagraphRestartFailureAlert( - ssmClient, - event, - `The last restart of metagraph is taking more than ${ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES} minutes, please check the logs. Triggering a new restart...`, - shouldRestart ? shouldRestart.reason : 'Unknow reason' - ) - - currentMetagraphRestart = await getCurrentMetagraphRestart(event) } - printSeparatorWithMessage('STARTING THE RESTART') - - const logsNames = getLogsNames() - - await restartNodes(ssmClient, event, logsNames, currentMetagraphRestart) + if (metagraphRestartType.restartType === DYNAMO_RESTART_TYPES.INDIVIDUAL_NODES) { + const unhealthyNodes = [...metagraphRestartType.unhealthyNodes.unhealthyMetagraphL0] + if ( + metagraphRestartType.unhealthyNodes.unhealthyCurrencyL1 && + metagraphRestartType.unhealthyNodes.unhealthyCurrencyL1.length === 3 + ) { + await restartIndividualCluster(ssmClient, event, logsNames.cl1LogName, LAYERS.CURRENCY_L1, referenceSourceNode) + } else { + unhealthyNodes.push(...metagraphRestartType.unhealthyNodes.unhealthyCurrencyL1) + } - if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.READY) { - await validateIfAllNodesAreReady(event) + if ( + metagraphRestartType.unhealthyNodes.unhealthyDataL1 && + metagraphRestartType.unhealthyNodes.unhealthyDataL1.length === 3 + ) { + await restartIndividualCluster(ssmClient, event, logsNames.dl1LogName, LAYERS.DATA_L1, referenceSourceNode) + } else { + unhealthyNodes.push(...metagraphRestartType.unhealthyNodes.unhealthyDataL1) + } - await checkIfNewSnapshotsAreProducedAfterRestart(event) + for (const node of unhealthyNodes) { + const logName = node.layer === LAYERS.L0 ? logsNames.l0LogName : node.layer === LAYERS.CURRENCY_L1 ? logsNames.cl1LogName : logsNames.dl1LogName + await restartIndividualNode(ssmClient, event, logName, node, referenceSourceNode) + } - await createMetagraphRestartSuccessfullyAlert(ssmClient, event, logsNames, `Metagraph need to be restarted: ${shouldRestart.reason}`) + const nodesIpsWithPorts = unhealthyNodes.map(node => `${node.ip}:${node.port}`) + const metagraphRestart = await upsertMetagraphRestart( + metagraphId, + DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS, + DYNAMO_RESTART_TYPES.INDIVIDUAL_NODES, + metagraphRestartType.reason, + '', + nodesIpsWithPorts.join(',') + ) - await deleteMetagraphRestart(event.metagraph.id) + await createMetagraphRestartStartedAlert(ssmClient, event, metagraphRestart) + return { + statusCode: 200, + body: JSON.stringify(RESTART_REASONS.UNHEALTHY_CLUSTER), + } } - printSeparatorWithMessage('FINISHED THE RESTART') - return { statusCode: 200, body: JSON.stringify('Finished cluster restart'), } } catch (e) { - await createMetagraphRestartFailureAlert(ssmClient, event, e.message, shouldRestart ? shouldRestart.reason : 'Unknow reason') + await createMetagraphRestartFailureAlert(ssmClient, event, e.message, 'Unknow reason') throw e } } \ No newline at end of file diff --git a/src/currency-l1/index.js b/src/currency-l1/index.js index fb849f4..e22f604 100644 --- a/src/currency-l1/index.js +++ b/src/currency-l1/index.js @@ -1,17 +1,14 @@ -import { - sendCommand, - getInformationToJoinNode, - checkIfValidatorsStarted, - joinNodeToCluster, - printSeparatorWithMessage, - getKeys, - saveLogs, - getAllEC2NodesInstances -} from '../shared/index.js' -import { LAYERS } from '../utils/types.js' - -const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2InstancesIds, referenceSourceNode) => { - const cl1Keys = await getKeys(ssmClient, event.aws.ec2.instances.genesis.id, 'cl1') +import { getKeys, sendCommand } from '../external/aws/ssm.js' +import { saveLogs, killCurrentExecution } from '../shared/index.js' +import { KEY_LAYERS, LAYERS } from '../utils/types.js' + +const startInitialValidatorNodeCurrencyL1 = async (ssmClient, event, logName, mL0NodeId, rollbackNode, referenceSourceNode, shouldKillCurrentExecution = true) => { + if (shouldKillCurrentExecution) { + await killCurrentExecution(ssmClient, event, LAYERS.CURRENCY_L1, [rollbackNode.id]) + } + + await saveLogs(ssmClient, event, logName, LAYERS.CURRENCY_L1, [rollbackNode.id]) + const cl1Keys = await getKeys(ssmClient, rollbackNode.id, KEY_LAYERS.CURRENCY_L1) const { ports } = event.metagraph const { @@ -50,13 +47,20 @@ const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2Insta const commands = [ ...envVariables, `cd ${file_system.base_currency_l1_directory}`, - `nohup java -jar currency-l1.jar run-initial-validator --ip ${event.aws.ec2.instances.genesis.ip} > node-l1.log 2>&1 &` + `nohup java -jar currency-l1.jar run-initial-validator --ip ${rollbackNode.ip} > node-l1.log 2>&1 &` ] - await sendCommand(ssmClient, commands, ec2InstancesIds) + await sendCommand(ssmClient, commands, [rollbackNode.id]) } -const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceIp, ec2InstancesIds, referenceSourceNode) => { +const startValidatorNodeCurrencyL1 = async (ssmClient, event, logName, mL0NodeId, validator, referenceSourceNode, shouldKillCurrentExecution = true) => { + if (shouldKillCurrentExecution) { + await killCurrentExecution(ssmClient, event, LAYERS.CURRENCY_L1, [validator.id]) + } + + await saveLogs(ssmClient, event, logName, LAYERS.CURRENCY_L1, [validator.id]) + const validatorKeys = await getKeys(ssmClient, validator.id, KEY_LAYERS.CURRENCY_L1) + const { ports } = event.metagraph const { id, @@ -66,6 +70,10 @@ const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceI } = event.metagraph const envVariables = [ + `export CL_KEYSTORE="${validatorKeys.keyStore}"`, + `export CL_KEYALIAS="${validatorKeys.keyAlias}"`, + `export CL_PASSWORD="${validatorKeys.password}"`, + `export CL_PUBLIC_HTTP_PORT=${ports.currency_l1_public_port}`, `export CL_P2P_HTTP_PORT=${ports.currency_l1_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.currency_l1_cli_port}`, @@ -90,55 +98,10 @@ const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceI const commands = [ ...envVariables, `cd ${file_system.base_currency_l1_directory}`, - `nohup java -jar currency-l1.jar run-validator --ip ${instanceIp} > node-l1.log 2>&1 &` + `nohup java -jar currency-l1.jar run-validator --ip ${validator.ip} > node-l1.log 2>&1 &` ] - await sendCommand(ssmClient, [...keys, ...commands], ec2InstancesIds) -} - -const restartCurrencyL1Nodes = async (ssmClient, event, metagraphL0NodeId, logName, referenceSourceNode) => { - const allEC2NodesIntances = getAllEC2NodesInstances(event) - await saveLogs(ssmClient, event, logName, LAYERS.CURRENCY_L1, allEC2NodesIntances) - - printSeparatorWithMessage('Starting initial validator currency l1 node') - await startInitialValidatorNodeL1(ssmClient, event, metagraphL0NodeId, [event.aws.ec2.instances.genesis.id], referenceSourceNode) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Starting validators currency l1 node') - for (const validator of event.aws.ec2.instances.validators) { - console.log(`Starting validator ${validator.ip}`) - const validator1Keys = await getKeys(ssmClient, validator.id, 'cl1') - await startValidatorNodeL1( - ssmClient, - event, - metagraphL0NodeId, - [ - `export CL_KEYSTORE="${validator1Keys.keyStore}"`, - `export CL_KEYALIAS="${validator1Keys.keyAlias}"`, - `export CL_PASSWORD="${validator1Keys.password}"` - ], - validator.ip, - [validator.id], - referenceSourceNode - ) - } - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Starting to get information to join node') - const { nodeId } = await getInformationToJoinNode(event, LAYERS.CURRENCY_L1) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Check if validators started successfully') - await checkIfValidatorsStarted(event, LAYERS.CURRENCY_L1) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage(`Joining validators currency L1 to the cluster. GenesisNodeId: ${nodeId}`) - for (const validator of event.aws.ec2.instances.validators) { - console.log(`Joining validator ${validator.ip}`) - await joinNodeToCluster(ssmClient, event, LAYERS.CURRENCY_L1, nodeId, [validator.id]) - } - printSeparatorWithMessage('Finished') - + await sendCommand(ssmClient, commands, [validator.id]) } -export { restartCurrencyL1Nodes } \ No newline at end of file +export { startInitialValidatorNodeCurrencyL1, startValidatorNodeCurrencyL1 } \ No newline at end of file diff --git a/src/data-l1/index.js b/src/data-l1/index.js index 5cfac98..1418c82 100644 --- a/src/data-l1/index.js +++ b/src/data-l1/index.js @@ -1,17 +1,14 @@ -import { - sendCommand, - getInformationToJoinNode, - checkIfValidatorsStarted, - joinNodeToCluster, - printSeparatorWithMessage, - getKeys, - saveLogs, - getAllEC2NodesInstances -} from '../shared/index.js' -import { LAYERS } from '../utils/types.js' - -const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2InstancesIds, referenceSourceNode) => { - const dl1Keys = await getKeys(ssmClient, event.aws.ec2.instances.genesis.id, 'dl1') +import { getKeys, sendCommand } from '../external/aws/ssm.js' +import { saveLogs, killCurrentExecution } from '../shared/index.js' +import { KEY_LAYERS, LAYERS } from '../utils/types.js' + +const startInitialValidatorNodeDataL1 = async (ssmClient, event, logName, mL0NodeId, rollbackNode, referenceSourceNode, shouldKillCurrentExecution = true) => { + if (shouldKillCurrentExecution) { + await killCurrentExecution(ssmClient, event, LAYERS.DATA_L1, [rollbackNode.id]) + } + + await saveLogs(ssmClient, event, logName, LAYERS.DATA_L1, [rollbackNode.id]) + const dl1Keys = await getKeys(ssmClient, rollbackNode.id, KEY_LAYERS.DATA_L1) const { ports } = event.metagraph const { @@ -50,13 +47,20 @@ const startInitialValidatorNodeL1 = async (ssmClient, event, mL0NodeId, ec2Insta const commands = [ ...envVariables, `cd ${file_system.base_data_l1_directory}`, - `nohup java -jar data-l1.jar run-initial-validator --ip ${event.aws.ec2.instances.genesis.ip} > node-l1.log 2>&1 &` + `nohup java -jar data-l1.jar run-initial-validator --ip ${rollbackNode.ip} > node-l1.log 2>&1 &` ] - await sendCommand(ssmClient, commands, ec2InstancesIds) + await sendCommand(ssmClient, commands, [rollbackNode.id]) } -const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceIp, ec2InstancesIds, referenceSourceNode) => { +const startValidatorNodeDataL1 = async (ssmClient, event, logName, mL0NodeId, validator, referenceSourceNode, shouldKillCurrentExecution = true) => { + if (shouldKillCurrentExecution) { + await killCurrentExecution(ssmClient, event, LAYERS.DATA_L1, [validator.id]) + } + + await saveLogs(ssmClient, event, logName, LAYERS.DATA_L1, [validator.id]) + const validatorKeys = await getKeys(ssmClient, validator.id, KEY_LAYERS.DATA_L1) + const { ports } = event.metagraph const { id, @@ -66,6 +70,10 @@ const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceI } = event.metagraph const envVariables = [ + `export CL_KEYSTORE="${validatorKeys.keyStore}"`, + `export CL_KEYALIAS="${validatorKeys.keyAlias}"`, + `export CL_PASSWORD="${validatorKeys.password}"`, + `export CL_PUBLIC_HTTP_PORT=${ports.data_l1_public_port}`, `export CL_P2P_HTTP_PORT=${ports.data_l1_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.data_l1_cli_port}`, @@ -90,55 +98,10 @@ const startValidatorNodeL1 = async (ssmClient, event, mL0NodeId, keys, instanceI const commands = [ ...envVariables, `cd ${file_system.base_data_l1_directory}`, - `nohup java -jar data-l1.jar run-validator --ip ${instanceIp} > node-l1.log 2>&1 &` + `nohup java -jar data-l1.jar run-validator --ip ${validator.ip} > node-l1.log 2>&1 &` ] - await sendCommand(ssmClient, [...keys, ...commands], ec2InstancesIds) -} - -const restartDataL1Nodes = async (ssmClient, event, metagraphL0NodeId, logName, referenceSourceNode) => { - const allEC2NodesIntances = getAllEC2NodesInstances(event) - await saveLogs(ssmClient, event, logName, LAYERS.DATA_L1, allEC2NodesIntances) - - printSeparatorWithMessage('Starting initial validator data l1 node') - await startInitialValidatorNodeL1(ssmClient, event, metagraphL0NodeId, [event.aws.ec2.instances.genesis.id], referenceSourceNode) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Starting validators data L1 nodes') - for (const validator of event.aws.ec2.instances.validators) { - console.log(`Starting validator ${validator.ip}`) - const validator1Keys = await getKeys(ssmClient, validator.id, 'cl1') - await startValidatorNodeL1( - ssmClient, - event, - metagraphL0NodeId, - [ - `export CL_KEYSTORE="${validator1Keys.keyStore}"`, - `export CL_KEYALIAS="${validator1Keys.keyAlias}"`, - `export CL_PASSWORD="${validator1Keys.password}"` - ], - validator.ip, - [validator.id], - referenceSourceNode - ) - } - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Starting to get information to join node') - const { nodeId } = await getInformationToJoinNode(event, LAYERS.DATA_L1) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Check if validators started successfully') - await checkIfValidatorsStarted(event, LAYERS.DATA_L1) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage(`Joining validators data L1 to the cluster. GenesisNodeId: ${nodeId}`) - for (const validator of event.aws.ec2.instances.validators) { - console.log(`Joining validator ${validator.ip}`) - await joinNodeToCluster(ssmClient, event, LAYERS.DATA_L1, nodeId, [validator.id]) - } - printSeparatorWithMessage('Finished') - + await sendCommand(ssmClient, commands, [validator.id]) } -export { restartDataL1Nodes } \ No newline at end of file +export { startInitialValidatorNodeDataL1, startValidatorNodeDataL1 } \ No newline at end of file diff --git a/src/external/aws/dynamo.js b/src/external/aws/dynamo.js index 31358a5..ca1c1ab 100644 --- a/src/external/aws/dynamo.js +++ b/src/external/aws/dynamo.js @@ -8,14 +8,18 @@ import { const dynamodb = new AWS.DynamoDB() -const upsertMetagraphRestart = async (metagraphId, state, updatedAt) => { +const upsertMetagraphRestart = async (metagraphId, state, restartType, restartReason, referenceNodeIp, individualNodesIpsWithPorts) => { const item = { TableName: DYNAMO_DB_TABLE_AUTO_RESTART, Item: { id: { S: metagraphId }, state: { S: state }, type: { S: 'metagraph' }, - updated_at: { S: updatedAt || moment.utc().format(DATE_FORMAT) }, + restart_type: { S: restartType || '' }, + restart_reason: { S: restartReason || ''}, + reference_node_ip: { S: referenceNodeIp || '' }, + individual_nodes_ips_with_ports: { S: individualNodesIpsWithPorts || '' }, + updated_at: { S: moment.utc().format(DATE_FORMAT) }, }, } @@ -29,6 +33,7 @@ const upsertMetagraphRestart = async (metagraphId, state, updatedAt) => { } const getMetagraphRestartOrCreateNew = async (metagraphId) => { + console.log(`Starting to get metagraph restart or create new`) const params = { TableName: DYNAMO_DB_TABLE_AUTO_RESTART, Key: { @@ -54,12 +59,24 @@ const getMetagraphRestartOrCreateNew = async (metagraphId) => { } const state = Item.state.S - const updatedAt = Item.updated_at.S - return { + const updatedAt = Item.updated_at?.S + const restartType = Item.restart_type?.S + const restartReason = Item.restart_reason?.S + const referenceNodeIp = Item.reference_node_ip?.S + const individualNodesIpsWithPorts = Item.individual_nodes_ips_with_ports?.S + + const body = { state, - updatedAt + updatedAt, + restartType, + restartReason, + referenceNodeIp, + individualNodesIpsWithPorts } + console.log(`Metagraph restart on Dynamo: ${JSON.stringify(body)}`) + + return body } const deleteMetagraphRestart = async (metagraphId) => { diff --git a/src/external/aws/ssm.js b/src/external/aws/ssm.js new file mode 100644 index 0000000..19d6a66 --- /dev/null +++ b/src/external/aws/ssm.js @@ -0,0 +1,42 @@ +import { SendCommandCommand, GetParameterCommand } from '@aws-sdk/client-ssm' + +const sendCommand = async (ssmClient, commands, ec2InstancesIds) => { + const params = { + DocumentName: "AWS-RunShellScript", + InstanceIds: ec2InstancesIds, + Parameters: { + commands + }, + } + + try { + const commandResponse = await ssmClient.send(new SendCommandCommand(params)) + console.log("Command sent successfully. Command ID:", commandResponse.Command.CommandId) + } catch (error) { + console.error("Error sending command:", error) + } +} + +const getSSMParameter = async (ssmClient, parameterName) => { + console.log(`Starting to get parameter: ${parameterName} on SSM (Parameter Store)`) + const getParameterCommand = new GetParameterCommand({ + Name: parameterName, + }) + + const parameter = await ssmClient.send(getParameterCommand) + return parameter.Parameter.Value +} + +const getKeys = async (ssmClient, instanceId, layer) => { + const keyStore = await getSSMParameter(ssmClient, `/metagraph-nodes/${instanceId}/${layer}/keystore`) + const keyAlias = await getSSMParameter(ssmClient, `/metagraph-nodes/${instanceId}/${layer}/keyalias`) + const password = await getSSMParameter(ssmClient, `/metagraph-nodes/${instanceId}/${layer}/password`) + + return { keyStore, keyAlias, password } +} + +export { + sendCommand, + getSSMParameter, + getKeys +} \ No newline at end of file diff --git a/src/services/opsgenie_service.js b/src/external/opsgenie/index.js similarity index 60% rename from src/services/opsgenie_service.js rename to src/external/opsgenie/index.js index 6753c2a..f914d96 100644 --- a/src/services/opsgenie_service.js +++ b/src/external/opsgenie/index.js @@ -1,6 +1,6 @@ import axios from 'axios' -import { getSSMParameter, printSeparatorWithMessage } from '../shared/index.js' -import { VALID_NETWORKS_TAGS_OPSGENIE } from '../utils/types.js' +import { getSSMParameter } from '../../external/aws/ssm.js' +import { OPSGENIE_API_KEY_PATH, VALID_NETWORKS_TAGS_OPSGENIE, DYNAMO_RESTART_TYPES } from '../../utils/types.js' const OPSGENIE_ALERT_URL = "https://api.opsgenie.com/v2/alerts" @@ -23,16 +23,18 @@ const buildValidatorsLogsInstances = (validators) => { return messages.join('\n') } -const buildSuccessfullyRestartAlertBody = (event, logNames, restartReason) => { +const buildStartedRestartAlertBody = (event, metagraphRestart) => { const { name: metagraphName, id, ports, include_currency_l1_layer, include_data_l1_layer } = event.metagraph const { name: networkName } = event.network const { genesis, validators } = event.aws.ec2.instances return { - message: `${metagraphName} Metagraph Restarted Successfully`, + message: `${metagraphName} Metagraph Started a Restart`, description: ` - The ${metagraphName} Metagraph restarted succesfully on ${networkName}. - Restart reason: ${restartReason} + The ${metagraphName} Metagraph started a restart on ${networkName}. + Restart Type: ${metagraphRestart.restartType} + Restart reason: ${metagraphRestart.restartReason} + ${metagraphRestart.restartType === DYNAMO_RESTART_TYPES.FULL_CLUSTER ? `Referece Node IP: ${metagraphRestart.referenceNodeIp}` : `Nodes Ips: ${metagraphRestart.individualNodesIpsWithPorts}`} You can check the metagraph nodes on these URLs: ML0 - Genesis: http://${genesis.ip}:${ports.metagraph_l0_public_port}/node/info @@ -51,31 +53,26 @@ const buildSuccessfullyRestartAlertBody = (event, logNames, restartReason) => { ${buildValidatorsLogsURLs(validators, 'DL1', ports.data_l1_public_port)} `: '' } - - The following logs were stored in the following directories on EC2 instances: - /home/ubuntu/code/restart_logs/${logNames.l0LogName} - ${include_currency_l1_layer ? `/home/ubuntu/code/restart_logs/${logNames.cl1LogName}` : ''} - ${include_data_l1_layer ? `/home/ubuntu/code/restart_logs/${logNames.dl1LogName}` : ''} EC2 instances: Instance 1 (Genesis) ID: ${genesis.id} Instance 1 (Genesis) IP: ${genesis.ip} ${buildValidatorsLogsInstances(validators)} `, - alias: `${id}_successfully_restarted`, + alias: `${id}_restart`, actions: ["Metagraph", "Restart"], - tags: ["Metagraph", "Restart", "Successfully", VALID_NETWORKS_TAGS_OPSGENIE[networkName]], + tags: [VALID_NETWORKS_TAGS_OPSGENIE[networkName]], details: { metagraphId: id, network: networkName, metagraphName: metagraphName }, entity: "Metagraph", - priority: "P4" + priority: "P3" } } -const buildFailureRestartAlertBody = (event, errorMessage, restartReason) => { +const buildFailureRestartAlertBody = (event, errorMessage, metagraphRestart) => { const { name: metagraphName, id, ports, include_currency_l1_layer, include_data_l1_layer } = event.metagraph const { name: networkName } = event.network const { genesis, validators } = event.aws.ec2.instances @@ -84,7 +81,9 @@ const buildFailureRestartAlertBody = (event, errorMessage, restartReason) => { message: `${metagraphName} Metagraph Failed to Restart`, description: ` The ${metagraphName} Metagraph failed to restart on ${networkName}. - Restart reason: ${restartReason} + Restart Type: ${metagraphRestart.restartType} + Restart Reason: ${metagraphRestart.restartReason} + ${metagraphRestart.restartType === DYNAMO_RESTART_TYPES.FULL_CLUSTER ? `Referece Node IP: ${metagraphRestart.referenceNodeIp}` : `Nodes Ips: ${metagraphRestart.individualNodesIpsWithPorts}`} Error message returned: ${errorMessage} You can check the metagraph nodes on these URLs: @@ -112,7 +111,7 @@ const buildFailureRestartAlertBody = (event, errorMessage, restartReason) => { `, actions: ["Metagraph", "Restart"], alias: `${id}_failure_restarted`, - tags: ["Metagraph", "Restart", "Failure", VALID_NETWORKS_TAGS_OPSGENIE[networkName]], + tags: [VALID_NETWORKS_TAGS_OPSGENIE[networkName]], details: { metagraphId: id, network: networkName, @@ -136,25 +135,53 @@ const createRemoteAlert = async (body, opsgenieApiKey) => { } } -const createMetagraphRestartSuccessfullyAlert = async (ssmClient, event, logNames, restartReason) => { - printSeparatorWithMessage("CREATING SUCCESSFULY RESTART ALERT ON OPSGENIE") - const opsgenieApiKey = await getSSMParameter(ssmClient, '/metagraph-nodes/opsgenie-api-key') - const alertBody = buildSuccessfullyRestartAlertBody(event, logNames, restartReason) +const closeRemoteAlert = async (alias, opsgenieApiKey) => { + const body = { + "user": "Monitoring Script", + "source": "AWS Lambda", + "note": "Action executed via Alert API" + } + try { + await axios.post(`${OPSGENIE_ALERT_URL}/${alias}/close?identifierType=alias`, body, { + headers: { + 'Content-Type': 'application/json', + 'Authorization': `GenieKey ${opsgenieApiKey}` + } + }) + } catch (e) { + throw Error(`Failing when creating remote alert: ${e}`) + } +} + +const createMetagraphRestartStartedAlert = async (ssmClient, event, metagraphRestart) => { + console.log(`Creating Metagraph Restart Started Alert`) + const opsgenieApiKey = await getSSMParameter(ssmClient, OPSGENIE_API_KEY_PATH) + const alertBody = buildStartedRestartAlertBody(event, metagraphRestart) await createRemoteAlert(alertBody, opsgenieApiKey) - printSeparatorWithMessage("Finished") + console.log(`Alert created`) +} + +const closeCurrentMetagraphRestartAlert = async (ssmClient, event) => { + console.log(`Closing metagraph restart alert`) + const opsgenieApiKey = await getSSMParameter(ssmClient, OPSGENIE_API_KEY_PATH) + const alias = `${event.metagraph.id}_restart` + + await closeRemoteAlert(alias, opsgenieApiKey) + console.log(`Alert close`) } -const createMetagraphRestartFailureAlert = async (ssmClient, event, errorMessage, restartReason) => { - printSeparatorWithMessage("CREATING FAILURE RESTART ALERT ON OPSGENIE") - const opsgenieApiKey = await getSSMParameter(ssmClient, '/metagraph-nodes/opsgenie-api-key') - const alertBody = buildFailureRestartAlertBody(event, errorMessage, restartReason) +const createMetagraphRestartFailureAlert = async (ssmClient, event, errorMessage, metagraphRestart) => { + console.log(`Creating Metagraph Restart Failure Alert`) + const opsgenieApiKey = await getSSMParameter(ssmClient, OPSGENIE_API_KEY_PATH) + const alertBody = buildFailureRestartAlertBody(event, errorMessage, metagraphRestart) await createRemoteAlert(alertBody, opsgenieApiKey) - printSeparatorWithMessage("Finished") + console.log(`Alert created`) } export { - createMetagraphRestartSuccessfullyAlert, + createMetagraphRestartStartedAlert, + closeCurrentMetagraphRestartAlert, createMetagraphRestartFailureAlert } \ No newline at end of file diff --git a/src/metagraph-l0/index.js b/src/metagraph-l0/index.js index 1b5b3e8..d632e17 100644 --- a/src/metagraph-l0/index.js +++ b/src/metagraph-l0/index.js @@ -1,19 +1,15 @@ -import { upsertMetagraphRestart } from '../external/aws/dynamo.js' -import { - sendCommand, - getInformationToJoinNode, - checkIfValidatorsStarted, - joinNodeToCluster, - printSeparatorWithMessage, - getKeys, - saveLogs, - getAllEC2NodesInstances -} from '../shared/index.js' -import { DYNAMO_RESTART_STATE, LAYERS } from '../utils/types.js' - -const startRollbackFirstNodeL0 = async (ssmClient, event, ec2InstancesIds, referenceSourceNode) => { - const l0Keys = await getKeys(ssmClient, event.aws.ec2.instances.genesis.id, LAYERS.L0) +import { getKeys, sendCommand } from '../external/aws/ssm.js' +import { saveLogs, killCurrentExecution } from '../shared/index.js' +import { KEY_LAYERS, LAYERS } from '../utils/types.js' +const startRollbackNodeL0 = async (ssmClient, event, rollbackNode, referenceSourceNode, logName, shouldKillCurrentExecution = true) => { + if (shouldKillCurrentExecution) { + await killCurrentExecution(ssmClient, event, LAYERS.L0, [rollbackNode.id]) + } + + await saveLogs(ssmClient, event, logName, LAYERS.L0, [rollbackNode.id]) + const l0Keys = await getKeys(ssmClient, rollbackNode.id, KEY_LAYERS.L0) + const { ports } = event.metagraph const { id, @@ -50,10 +46,17 @@ const startRollbackFirstNodeL0 = async (ssmClient, event, ec2InstancesIds, refer `nohup java -jar metagraph-l0.jar run-rollback --ip ${event.aws.ec2.instances.genesis.ip} > node-l0.log 2>&1 &` ] - await sendCommand(ssmClient, commands, ec2InstancesIds) + await sendCommand(ssmClient, commands, [rollbackNode.id]) } -const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2InstancesIds, referenceSourceNode) => { +const startValidatorNodeL0 = async (ssmClient, event, logName, validator, referenceSourceNode, shouldKillCurrentExecution = true) => { + if (shouldKillCurrentExecution) { + await killCurrentExecution(ssmClient, event, LAYERS.L0, [validator.id]) + } + + await saveLogs(ssmClient, event, logName, LAYERS.L0, [validator.id]) + const validatorKeys = await getKeys(ssmClient, validator.id, KEY_LAYERS.L0) + const { ports } = event.metagraph const { id, @@ -63,6 +66,9 @@ const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2Insta } = event.metagraph const envVariables = [ + `export CL_KEYSTORE="${validatorKeys.keyStore}"`, + `export CL_KEYALIAS="${validatorKeys.keyAlias}"`, + `export CL_PASSWORD="${validatorKeys.password}"`, `export CL_PUBLIC_HTTP_PORT=${ports.metagraph_l0_public_port}`, `export CL_P2P_HTTP_PORT=${ports.metagraph_l0_p2p_port}`, `export CL_CLI_HTTP_PORT=${ports.metagraph_l0_cli_port}`, @@ -81,66 +87,13 @@ const startValidatorNodeL0 = async (ssmClient, event, keys, instanceIp, ec2Insta const commands = [ ...envVariables, `cd ${file_system.base_metagraph_l0_directory}`, - `nohup java -jar metagraph-l0.jar run-validator --ip ${instanceIp} > node-l0.log 2>&1 &` + `nohup java -jar metagraph-l0.jar run-validator --ip ${validator.ip} > node-l0.log 2>&1 &` ] - await sendCommand(ssmClient, [...keys, ...commands], ec2InstancesIds) -} - -const restartL0Nodes = async (ssmClient, event, logName, currentMetagraphRestart, referenceSourceNode) => { - if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { - const allEC2NodesIntances = getAllEC2NodesInstances(event) - await saveLogs(ssmClient, event, logName, LAYERS.L0, allEC2NodesIntances) - - printSeparatorWithMessage('Starting rollback genesis l0 node') - await startRollbackFirstNodeL0(ssmClient, event, [event.aws.ec2.instances.genesis.id], referenceSourceNode) - - console.log("Updating state to ROLLBACK_IN_PROGRESS") - currentMetagraphRestart = await upsertMetagraphRestart(event.metagraph.id, DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS) - printSeparatorWithMessage('Finished') - } - - if (currentMetagraphRestart.state !== DYNAMO_RESTART_STATE.READY) { - return null - } - - printSeparatorWithMessage('Starting validators L0 nodes') - for (const validator of event.aws.ec2.instances.validators) { - console.log(`Starting validator ${validator.ip}`) - const validator1Keys = await getKeys(ssmClient, validator.id, LAYERS.L0) - await startValidatorNodeL0( - ssmClient, - event, - [ - `export CL_KEYSTORE="${validator1Keys.keyStore}"`, - `export CL_KEYALIAS="${validator1Keys.keyAlias}"`, - `export CL_PASSWORD="${validator1Keys.password}"` - ], - validator.ip, - [validator.id], - referenceSourceNode - ) - } - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Starting to get information to join node') - const { nodeId } = await getInformationToJoinNode(event, LAYERS.L0) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage('Check if validators started successfully') - await checkIfValidatorsStarted(event, LAYERS.L0) - printSeparatorWithMessage('Finished') - - printSeparatorWithMessage(`Joining validators L0 to the cluster. GenesisNodeId: ${nodeId}`) - for (const validator of event.aws.ec2.instances.validators) { - console.log(`Joining validator ${validator.ip}`) - await joinNodeToCluster(ssmClient, event, LAYERS.L0, nodeId, [validator.id]) - } - printSeparatorWithMessage('Finished') - - return nodeId + await sendCommand(ssmClient, commands, [validator.id]) } export { - restartL0Nodes + startRollbackNodeL0, + startValidatorNodeL0 } \ No newline at end of file diff --git a/src/restarts/check_restart_progress.js b/src/restarts/check_restart_progress.js new file mode 100644 index 0000000..03fc839 --- /dev/null +++ b/src/restarts/check_restart_progress.js @@ -0,0 +1,183 @@ +import moment from 'moment' +import { deleteMetagraphRestart, getMetagraphRestartOrCreateNew, upsertMetagraphRestart } from "../external/aws/dynamo.js" +import { closeCurrentMetagraphRestartAlert, createMetagraphRestartFailureAlert } from "../external/opsgenie/index.js" +import { checkIfNodeIsReady, getLogsNames } from "../shared/index.js" +import { DYNAMO_RESTART_STATE, DYNAMO_RESTART_TYPES, ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES, DATE_FORMAT } from "../utils/types.js" +import { finishMetagraphRollback } from "./full_cluster.js" + +const checkFullClusterRestart = async (event, metagraphId, currentMetagraphRestart) => { + console.log(`Checking full cluster restart`) + const { state, restartType, restartReason, referenceNodeIp } = currentMetagraphRestart; + + const node1 = event.aws.ec2.instances.genesis + const node2 = event.aws.ec2.instances.validators[0] + const node3 = event.aws.ec2.instances.validators[1] + const { ports } = event.metagraph + + const node1Ready = await checkIfNodeIsReady(node1.ip, ports.metagraph_l0_public_port) + const node2Ready = await checkIfNodeIsReady(node2.ip, ports.metagraph_l0_public_port) + const node3Ready = await checkIfNodeIsReady(node3.ip, ports.metagraph_l0_public_port) + + if (node1Ready && node2Ready && node3Ready) { + console.log('All nodes are READY') + return await upsertMetagraphRestart(metagraphId, DYNAMO_RESTART_STATE.READY, restartType, restartReason, referenceNodeIp) + } + + if ((node1Ready || node2Ready || node3Ready) && state === DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS) { + console.log('Initial node ready to JOIN') + return await upsertMetagraphRestart(metagraphId, DYNAMO_RESTART_STATE.READY_TO_JOIN, restartType, restartReason, referenceNodeIp) + } + + console.log(`Still restarting`) + return currentMetagraphRestart +} + +const checkIndividualNodesRestart = async (metagraphId, currentMetagraphRestart) => { + console.log(`Checking inidivudal node restart`) + const { restartType, restartReason, individualNodesIpsWithPorts } = currentMetagraphRestart; + if (!individualNodesIpsWithPorts) { + throw Error(`Could not get individualNodesIpsWithPorts from individual nodes restart`) + } + + const individualNodesIpsWithPortsAsList = individualNodesIpsWithPorts.split(',') + const nodesReady = [] + + console.log(`Starting to check the status of nodes: ${JSON.stringify(individualNodesIpsWithPortsAsList)}`) + for (const currentNodeIpAndPort of individualNodesIpsWithPortsAsList) { + const node = currentNodeIpAndPort.split(':') + const nodeReady = await checkIfNodeIsReady(node[0], node[1]) + if (nodeReady) { + nodesReady.push(currentNodeIpAndPort) + } + } + + if (nodesReady.length === individualNodesIpsWithPortsAsList.length) { + console.log(`All nodes READY`) + return await upsertMetagraphRestart(metagraphId, DYNAMO_RESTART_STATE.READY, restartType, restartReason, '', individualNodesIpsWithPorts) + } + + console.log(`Still restarting`) + return currentMetagraphRestart +} + +const checkRestartStatus = async (event, networkName, currentMetagraphRestart) => { + const { restartType, state } = currentMetagraphRestart; + const metagraphId = event.metagraph.id + + if (state === DYNAMO_RESTART_STATE.NEW) { + return currentMetagraphRestart + } + if (restartType === DYNAMO_RESTART_TYPES.FULL_CLUSTER) { + return await checkFullClusterRestart(event, metagraphId, currentMetagraphRestart) + } + if (restartType === DYNAMO_RESTART_TYPES.INDIVIDUAL_NODES) { + return await checkIndividualNodesRestart(metagraphId, currentMetagraphRestart) + } + + throw Error(`Error when checking restart status of metagraph: ${networkName}`) +} + +const checkMetagraphRestartProgress = async (event, metagraphId, oldMetagraphRestart) => { + console.log(`Getting current restart status`) + const metagraphRestart = await checkRestartStatus(event, metagraphId, oldMetagraphRestart) + if (metagraphRestart.state === DYNAMO_RESTART_STATE.READY) { + return { + statusCode: 200, + finishCurrentDynamoDBMetagraphRestart: true, + message: 'All nodes are in READY state', + metagraphRestart + } + } + + const { updatedAt } = metagraphRestart + const lastRestartTimeDiff = moment.utc().diff(moment.utc(updatedAt), 'minutes') + + if (lastRestartTimeDiff <= ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES) { + const timeoutTime = moment.utc(updatedAt).add(ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES, 'minutes') + console.log(`Operation running since: ${updatedAt} will timeout at ${timeoutTime.format(DATE_FORMAT)}`) + + return { + statusCode: 200, + finishCurrentDynamoDBMetagraphRestart: false, + message: 'There is already one restart in progress for this metagraph, please wait this operation could take hours', + metagraphRestart + } + } + + return { + statusCode: 400, + finishCurrentDynamoDBMetagraphRestart: true, + message: `The last restart of network is taking more than ${ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES} minutes, please check the logs. Triggering a new restart...`, + metagraphRestart + } +} + +const getMetagraphRestartProgress = async (ssmClient, event, currentMetagraphRestart, referenceSourceNode) => { + console.log(`Starting to get metagraph restart progress`) + if (currentMetagraphRestart.state === DYNAMO_RESTART_STATE.NEW) { + console.log(`New restart`) + return { + status: 200, + body: 'New Restart', + restartState: DYNAMO_RESTART_STATE.NEW, + metagraphRestart: currentMetagraphRestart + } + } + + const metagraphRestartProgress = await checkMetagraphRestartProgress( + event, + event.metagraph.id, + currentMetagraphRestart + ) + + if ( + metagraphRestartProgress.metagraphRestart.state === DYNAMO_RESTART_STATE.READY_TO_JOIN && + metagraphRestartProgress.metagraphRestart.restartType === DYNAMO_RESTART_TYPES.FULL_CLUSTER + ) { + console.log(`Metagraph is READY_TO_JOIN triggering finishMetagraphRollback`) + const logsNames = getLogsNames() + await finishMetagraphRollback(ssmClient, event, logsNames, referenceSourceNode) + + return { + status: 200, + restartState: DYNAMO_RESTART_STATE.READY_TO_JOIN, + body: 'finishMetagraphRollback triggered, finishing current execution.', + metagraphRestart: currentMetagraphRestart + } + } + + if (metagraphRestartProgress.finishCurrentDynamoDBMetagraphRestart) { + console.log(`Deleting current metagraph restart on dynamo table`) + await deleteMetagraphRestart(event.metagraph.id) + if (metagraphRestartProgress.statusCode === 200) { + await closeCurrentMetagraphRestartAlert(ssmClient, event) + } + } + + if (metagraphRestartProgress.statusCode === 200) { + return { + statusCode: 200, + body: JSON.stringify(metagraphRestartProgress.message), + metagraphRestart: currentMetagraphRestart + } + } + + await createMetagraphRestartFailureAlert( + ssmClient, + event, + metagraphRestartProgress.message, + metagraphRestartProgress.metagraphRestart + ) + + const metagraphRestart = await getMetagraphRestartOrCreateNew(metagraphId) + return { + status: 200, + restartState: DYNAMO_RESTART_STATE.NEW, + body: 'Starting a new restart because the last one timed out', + metagraphRestart + } +} + +export { + getMetagraphRestartProgress +} \ No newline at end of file diff --git a/src/restarts/full_cluster.js b/src/restarts/full_cluster.js new file mode 100644 index 0000000..70cf0ef --- /dev/null +++ b/src/restarts/full_cluster.js @@ -0,0 +1,103 @@ +import { startInitialValidatorNodeCurrencyL1, startValidatorNodeCurrencyL1 } from "../currency-l1/index.js" +import { startInitialValidatorNodeDataL1, startValidatorNodeDataL1 } from "../data-l1/index.js" +import { startRollbackNodeL0, startValidatorNodeL0 } from "../metagraph-l0/index.js" +import { getInformationToJoinNode, checkIfValidatorsStarted, sleep, joinNodeToCluster, killCurrentExecution } from "../shared/index.js" +import { LAYERS } from "../utils/types.js" + +const startMetagraphL0Validators = async (ssmClient, event, logName, nodeId, referenceSourceNode) => { + for (const validator of event.aws.ec2.instances.validators) { + console.log(`Starting validator ${validator.ip}`) + await startValidatorNodeL0( + ssmClient, + event, + logName, + validator, + referenceSourceNode + ) + } + + await checkIfValidatorsStarted(event, LAYERS.L0) + for (const validator of event.aws.ec2.instances.validators) { + console.log(`Joining validator ${validator.ip}`) + await joinNodeToCluster(ssmClient, event, LAYERS.L0, nodeId, [validator.id]) + } +} + +const startCurrencyL1Nodes = async (ssmClient, event, logName, ml0NodeId, referenceSourceNode) => { + console.log(`Starting initial validator`) + await startInitialValidatorNodeCurrencyL1(ssmClient, event, logName, ml0NodeId, event.aws.ec2.instances.genesis, referenceSourceNode) + await sleep(10 * 1000) + + const nodeInformation = await getInformationToJoinNode(event, LAYERS.CURRENCY_L1) + for (const validator of event.aws.ec2.instances.validators) { + console.log(`Starting validator ${validator.ip}`) + await startValidatorNodeCurrencyL1( + ssmClient, + event, + logName, + ml0NodeId, + validator, + referenceSourceNode + ) + } + + await checkIfValidatorsStarted(event, LAYERS.CURRENCY_L1) + for (const validator of event.aws.ec2.instances.validators) { + console.log(`Joining validator ${validator.ip}`) + await joinNodeToCluster(ssmClient, event, LAYERS.CURRENCY_L1, nodeInformation, [validator.id]) + } +} + +const startDataL1Nodes = async (ssmClient, event, logName, ml0NodeId, referenceSourceNode) => { + await startInitialValidatorNodeDataL1(ssmClient, event, logName, ml0NodeId, event.aws.ec2.instances.genesis, referenceSourceNode) + await sleep(10 * 1000) + + const nodeInformation = await getInformationToJoinNode(event, LAYERS.DATA_L1) + for (const validator of event.aws.ec2.instances.validators) { + console.log(`Starting validator ${validator.ip}`) + await startValidatorNodeDataL1( + ssmClient, + event, + logName, + ml0NodeId, + validator, + referenceSourceNode + ) + } + + await checkIfValidatorsStarted(event, LAYERS.DATA_L1) + for (const validator of event.aws.ec2.instances.validators) { + console.log(`Joining validator ${validator.ip}`) + await joinNodeToCluster(ssmClient, event, LAYERS.DATA_L1, nodeInformation, [validator.id]) + } +} + +const startMetagraphRollback = async (ssmClient, event, l0LogName, referenceSourceNode) => { + const allInstancesIds = [event.aws.ec2.instances.genesis.id, event.aws.ec2.instances.validators[0].id, event.aws.ec2.instances.validators[1].id] + + await killCurrentExecution(ssmClient, event, LAYERS.L0, allInstancesIds) + await killCurrentExecution(ssmClient, event, LAYERS.CURRENCY_L1, allInstancesIds) + await killCurrentExecution(ssmClient, event, LAYERS.DATA_L1, allInstancesIds) + + await startRollbackNodeL0(ssmClient, event, event.aws.ec2.instances.genesis, referenceSourceNode, l0LogName, false) +} + +const finishMetagraphRollback = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogName }, referenceSourceNode) => { + const { nodeId } = await getInformationToJoinNode(event, LAYERS.L0) + + await startMetagraphL0Validators(ssmClient, event, l0LogName, nodeId, referenceSourceNode) + if (event.metagraph.include_currency_l1_layer) { + await startCurrencyL1Nodes(ssmClient, event, cl1LogName, nodeId, referenceSourceNode) + } + + if (event.metagraph.include_data_l1_layer) { + await startDataL1Nodes(ssmClient, event, nodeId, dl1LogName, referenceSourceNode) + } +} + +export { + startMetagraphRollback, + finishMetagraphRollback, + startCurrencyL1Nodes, + startDataL1Nodes +} \ No newline at end of file diff --git a/src/restarts/index.js b/src/restarts/index.js new file mode 100644 index 0000000..0d1d6eb --- /dev/null +++ b/src/restarts/index.js @@ -0,0 +1,12 @@ +import { startMetagraphRollback, finishMetagraphRollback } from "./full_cluster.js" +import { restartIndividualNode } from "./individual_node.js" +import { restartIndividualCluster } from "./individual_cluster.js" +import { getMetagraphRestartProgress } from "./check_restart_progress.js" + +export { + startMetagraphRollback, + finishMetagraphRollback, + restartIndividualNode, + restartIndividualCluster, + getMetagraphRestartProgress +} \ No newline at end of file diff --git a/src/restarts/individual_cluster.js b/src/restarts/individual_cluster.js new file mode 100644 index 0000000..9411ba7 --- /dev/null +++ b/src/restarts/individual_cluster.js @@ -0,0 +1,18 @@ +import { getInformationToJoinNode } from "../shared/index.js" +import { LAYERS } from "../utils/types.js" +import { startCurrencyL1Nodes, startDataL1Nodes } from "./full_cluster.js" + +const restartIndividualCluster = async (ssmClient, event, logName, layer, referenceSourceNode) => { + const { nodeId } = await getInformationToJoinNode(event, LAYERS.L0) + + if (layer === LAYERS.CURRENCY_L1) { + await startCurrencyL1Nodes(ssmClient,event, logName, nodeId, referenceSourceNode) + } + if (layer === LAYERS.DATA_L1) { + await startDataL1Nodes(ssmClient,event, logName, nodeId, referenceSourceNode) + } +} + +export { + restartIndividualCluster +} \ No newline at end of file diff --git a/src/restarts/individual_node.js b/src/restarts/individual_node.js new file mode 100644 index 0000000..ad977d1 --- /dev/null +++ b/src/restarts/individual_node.js @@ -0,0 +1,79 @@ +import { startValidatorNodeCurrencyL1 } from "../currency-l1/index.js" +import { startValidatorNodeDataL1 } from "../data-l1/index.js" +import { startValidatorNodeL0 } from "../metagraph-l0/index.js" +import { getInformationToJoinNode, sleep, joinNodeToCluster, checkIfNodeStarted } from "../shared/index.js" +import { LAYERS } from "../utils/types.js" + +const startMetagraphL0ValidatorNode = async (ssmClient, event, node, logName, nodeId, referenceSourceNode) => { + console.log(`Starting validator ${node.ip}`) + await startValidatorNodeL0( + ssmClient, + event, + logName, + node, + referenceSourceNode + ) + + await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) + await sleep(10 * 1000) + await joinNodeToCluster(ssmClient, event, LAYERS.L0, nodeId, [node.id]) + + return nodeId +} + +const startCurrencyL1ValidatorNode = async (ssmClient, event, node, logName, ml0NodeId, referenceSourceNode) => { + const nodeInformation = await getInformationToJoinNode(event, LAYERS.CURRENCY_L1) + console.log(`Starting validator ${node.ip}`) + await startValidatorNodeCurrencyL1( + ssmClient, + event, + logName, + ml0NodeId, + node, + referenceSourceNode + ) + + await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) + await sleep(10 * 1000) + + console.log(`Joining validator ${node.ip}`) + await joinNodeToCluster(ssmClient, event, LAYERS.CURRENCY_L1, nodeInformation, [node.id]) +} + +const startDataL1ValidatorNode = async (ssmClient, event, node, logName, ml0NodeId, referenceSourceNode) => { + const nodeInformation = await getInformationToJoinNode(event, LAYERS.DATA_L1) + + console.log(`Starting validator ${node.ip}`) + await startValidatorNodeDataL1( + ssmClient, + event, + logName, + ml0NodeId, + node, + referenceSourceNode + ) + + await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) + await sleep(10 * 1000) + + console.log(`Joining validator ${node.ip}`) + await joinNodeToCluster(ssmClient, event, LAYERS.DATA_L1, nodeInformation, [node.id]) +} + +const restartIndividualNode = async (ssmClient, event, logName, node, referenceSourceNode) => { + const { nodeId } = await getInformationToJoinNode(event, LAYERS.L0) + + if (node.layer === LAYERS.L0) { + await startMetagraphL0ValidatorNode(ssmClient, event, node, logName, nodeId, referenceSourceNode) + } + if (node.layer === LAYERS.CURRENCY_L1) { + await startCurrencyL1ValidatorNode(ssmClient, event, node, logName, nodeId, referenceSourceNode) + } + if (node.layer === LAYERS.DATA_L1) { + await startDataL1ValidatorNode(ssmClient, event, node, logName, nodeId, referenceSourceNode) + } +} + +export { + restartIndividualNode +} \ No newline at end of file diff --git a/src/shared/check_nodes_health.js b/src/shared/check_nodes_health.js new file mode 100644 index 0000000..2e247f9 --- /dev/null +++ b/src/shared/check_nodes_health.js @@ -0,0 +1,123 @@ +import axios from 'axios' +import { LAYERS } from '../utils/types.js' +import { sleep } from './shared.js' + +const checkIfNodeIsReady = async (nodeIp, nodePort) => { + try { + const url = `http://${nodeIp}:${nodePort}/node/info` + + const response = await axios.get(url) + const nodeState = response.data.state + console.log(`Current state of node ${nodeIp}:${nodePort}: ${nodeState}`) + if (nodeState === 'Ready') { + return true + } + + return false + } catch (e) { + console.log(`Could not get response of node: ${nodeIp}`) + return false + } +} + +const checkIfValidatorsStarted = async (event, layer) => { + const { ports } = event.metagraph + var layerPorts = { + [LAYERS.L0]: ports.metagraph_l0_public_port, + [LAYERS.CURRENCY_L1]: ports.currency_l1_public_port, + [LAYERS.DATA_L1]: ports.data_l1_public_port + } + + const validatorsUrls = event.aws.ec2.instances.validators.map(validator => { + return `http://${validator.ip}:${layerPorts[layer]}/node/info` + }) + + for (const url of validatorsUrls) { + console.log(`Checking validator at URL: ${url}`) + for (let idx = 0; idx < 11; idx++) { + try { + await axios.get(url) + console.log(`Node started and healthy`) + return + } catch (e) { + if (idx === 10) { + throw Error(`Could not get information of node in URL: ${url}`) + } + console.log(`Node is possibly not READY yet, waiting for 10s to try again (${idx + 1}/11)`) + await sleep(10 * 1000) + } + } + } +} + +const checkIfNodeStarted = async (url) => { + for (let idx = 0; idx < 11; idx++) { + try { + await axios.get(url) + console.log(`Node started`) + return + } catch (e) { + if (idx === 10) { + throw Error(`Could not get information of node in URL: ${url}`) + } + console.log(`Node possibly not started yet, waiting for 10s to try again (${idx + 1}/11)`) + await sleep(10 * 1000) + } + + } +} + +const checkIfAllNodesAreReady = async (event, layer) => { + const { ports } = event.metagraph + var layerPorts = { + [LAYERS.L0]: ports.metagraph_l0_public_port, + [LAYERS.CURRENCY_L1]: ports.currency_l1_public_port, + [LAYERS.DATA_L1]: ports.data_l1_public_port + } + + const validatorsUrls = layer === LAYERS.L0 ? [] : event.aws.ec2.instances.validators.map(validator => { + return `http://${validator.ip}:${layerPorts[layer]}/node/info` + }) + + let urls = [`http://${event.aws.ec2.instances.genesis.ip}:${layerPorts[layer]}/node/info`, ...validatorsUrls] + for (let idx = 0; idx < 20; idx++) { + try { + const readyNodesUrls = [] + for (const url of urls) { + const response = await axios.get(url) + const nodeState = response.data.state + if (nodeState === 'Ready') { + readyNodesUrls.push(url) + } + } + if (readyNodesUrls.length > 0) { + console.log(`[${layer}] The following nodes are already ready: ${JSON.stringify(readyNodesUrls)}`) + urls = urls.filter(url => !readyNodesUrls.includes(url)) + } + + if (urls.length === 0) { + console.log(`[${layer}] All nodes are on ready state`) + return + } else { + console.log(`[${layer}] The following nodes are not ready yet: ${JSON.stringify(urls)}`) + console.log(`[${layer}] Not all nodes are on Ready state, trying again in 10s (${idx + 1}/20)`) + await sleep(10 * 1000) + } + } catch (e) { + if (idx === 19) { + throw new Error(`[${layer}] Failing when restarting nodes. All nodes should be on READY state`) + } + + console.log(`[${layer}] Not all nodes are on Ready state, trying again in 10s (${idx + 1}/20)`) + await sleep(10 * 1000) + } + } + +} + +export { + checkIfNodeIsReady, + checkIfValidatorsStarted, + checkIfNodeStarted, + checkIfAllNodesAreReady +} \ No newline at end of file diff --git a/src/shared/get_metagraph_info.js b/src/shared/get_metagraph_info.js new file mode 100644 index 0000000..131ccba --- /dev/null +++ b/src/shared/get_metagraph_info.js @@ -0,0 +1,235 @@ +import axios from 'axios' +import { LAYERS, NETWORK_NODES, CHECK_NODE_HEALTHY_LIMIT } from '../utils/types.js' +import { sleep } from './shared.js' + +const _getLatestMetagraphOfNetwork = async (networkName) => { + const beUrl = `https://be-${networkName}.constellationnetwork.io/global-snapshots/latest` + try { + const response = await axios.get(beUrl) + const lastSnapshotOrdinal = response.data.data.ordinal + const lastSnapshotHash = response.data.data.hash + + console.log(`LAST SNAPSHOT OF NETWORK: ${networkName}. Ordinal: ${lastSnapshotOrdinal}. Hash: ${lastSnapshotHash}`) + + return { + lastSnapshotOrdinal, + lastSnapshotHash + } + } catch (e) { + console.log(e) + throw Error(`Error when searching for snapshot on: ${beUrl}`, e) + } +} + +const _checkIfSnapshotExistsOnNode = async (nodeIp, nodePort, snapshotHash) => { + const nodeUrl = `http://${nodeIp}:${nodePort}/global-snapshots/${snapshotHash}` + try { + await axios.get(nodeUrl) + console.log(`Snapshot exists on node: ${nodeIp}`) + return true + } catch (e) { + console.log(`Snapshot does not exists on node: ${nodeIp}`) + return false + } +} + +const _getUnhealthyNodes = async (clusterInfo) => { + const { layer, nodes } = clusterInfo + + console.log(`Checking nodes health of cluster: ${layer}`) + const unhealthyNodes = [] + + for (const node of nodes) { + console.log(`Checking node: ${node.ip}:${node.port}`) + for (let idx = 0; idx < CHECK_NODE_HEALTHY_LIMIT; idx++) { + try { + const response = await axios.get(`http://${node.ip}:${node.port}/node/info`) + const nodeInfo = response.data + if (nodeInfo.state !== 'Ready') { + console.log(`Node is unhealthy`) + unhealthyNodes.push({ + layer, + ip: node.ip, + port: node.port, + id: node.id + }) + break + } + + console.log('Node is healthy') + break + } catch (e) { + if (idx === 4) { + console.log(`Unhealthy node after trying ${CHECK_NODE_HEALTHY_LIMIT} times`) + unhealthyNodes.push({ + layer, + ip: node.ip, + port: node.port, + id: node.id + }) + + break + } + console.log(`Could not get node information at: ${node.ip}. Trying again in 5s (${idx + 1}/${CHECK_NODE_HEALTHY_LIMIT})`) + await sleep(5 * 1000) + } + } + } + + return unhealthyNodes +} + +const getLastMetagraphInfo = async (event) => { + const { network, metagraph } = event + const beUrl = `https://be-${network.name}.constellationnetwork.io/currency/${metagraph.id}/snapshots/latest` + try { + const response = await axios.get(beUrl) + const lastSnapshotTimestamp = response.data.data.timestamp + const lastSnapshotOrdinal = response.data.data.ordinal + const lastSnapshotHash = response.data.data.hash + + console.log(`LAST SNAPSHOT OF METAGRAPH ${metagraph.id}: ${lastSnapshotTimestamp}. Ordinal: ${lastSnapshotOrdinal}. Hash: ${lastSnapshotHash}`) + + return { + lastSnapshotTimestamp, + lastSnapshotOrdinal, + lastSnapshotHash + } + } catch (e) { + console.log(e) + throw Error(`Error when searching for metagraph on: ${beUrl}`, e) + } +} + +const getReferenceSourceNode = async (event) => { + const { network } = event + const networkName = network.name + + console.log(`Starting to get reference source node for network: ${networkName}`) + + const networkNodes = NETWORK_NODES[networkName] + if (!networkNodes || Object.keys(networkNodes).length === 0) { + throw Error(`Could not find nodes of network: ${networkName}`) + } + + const { node_1, node_2, node_3 } = networkNodes + const { lastSnapshotHash } = await _getLatestMetagraphOfNetwork(networkName) + + const snapshotExistsOnNode1 = await _checkIfSnapshotExistsOnNode(node_1.ip, node_1.port, lastSnapshotHash) + if (snapshotExistsOnNode1) { + return node_1 + } + + const snapshotExistsOnNode2 = await _checkIfSnapshotExistsOnNode(node_2.ip, node_2.port, lastSnapshotHash) + if (snapshotExistsOnNode2) { + return node_2 + } + + const snapshotExistsOnNode3 = await _checkIfSnapshotExistsOnNode(node_3.ip, node_3.port, lastSnapshotHash) + if (snapshotExistsOnNode3) { + return node_3 + } + + return null +} + +const getInformationToJoinNode = async (event, layer) => { + const { ports } = event.metagraph + var urls = { + [LAYERS.L0]: [ + `http://${event.aws.ec2.instances.genesis.ip}:${ports.metagraph_l0_public_port}/node/info`, + `http://${event.aws.ec2.instances.validators[0].ip}:${ports.metagraph_l0_public_port}/node/info`, + `http://${event.aws.ec2.instances.validators[1].ip}:${ports.metagraph_l0_public_port}/node/info`, + ], + [LAYERS.CURRENCY_L1]: [ + `http://${event.aws.ec2.instances.genesis.ip}:${ports.currency_l1_public_port}/node/info`, + `http://${event.aws.ec2.instances.validators[0].ip}:${ports.currency_l1_public_port}/node/info`, + `http://${event.aws.ec2.instances.validators[1].ip}:${ports.currency_l1_public_port}/node/info`, + ], + [LAYERS.DATA_L1]: [ + `http://${event.aws.ec2.instances.genesis.ip}:${ports.data_l1_public_port}/node/info`, + `http://${event.aws.ec2.instances.validators[0].ip}:${ports.data_l1_public_port}/node/info`, + `http://${event.aws.ec2.instances.validators[1].ip}:${ports.data_l1_public_port}/node/info`, + ] + } + + for (let idx = 0; idx < 60; idx++) { + for (const url of urls[layer]) { + try { + const response = await axios.get(url) + const nodeId = response.data.id + const nodeHost = response.data.host + const nodeP2pPort = response.data.p2pPort + const state = response.data.state + if (state !== 'Ready') { + throw Error('Node not ready yet') + } + + console.log(`Node selected to JOIN on layer ${layer}: + peerId: ${nodeId} + nodeHost: ${nodeHost} + nodeP2pPort: ${nodeP2pPort} + `) + return { nodeId, nodeHost, nodeP2pPort } + } catch (e) { + if (idx === 59) { + throw Error(`Could not get information of node in URL: ${urls[layer]}`) + } + console.log(`Node ${url} is possibly not READY yet, waiting for 10s to try again (${idx + 1}/60)`) + await sleep(10 * 1000) + } + } + } +} + +const getAllUnhealthyNodes = async (event) => { + const { ports } = event.metagraph + let clusterInfos = [{ + layer: LAYERS.L0, + nodes: [ + { ip: event.aws.ec2.instances.genesis.ip, port: ports.metagraph_l0_public_port, id: event.aws.ec2.instances.genesis.id }, + { ip: event.aws.ec2.instances.validators[0].ip, port: ports.metagraph_l0_public_port, id: event.aws.ec2.instances.validators[0].id }, + { ip: event.aws.ec2.instances.validators[1].ip, port: ports.metagraph_l0_public_port, id: event.aws.ec2.instances.validators[1].id }, + ] + }] + + if (event.metagraph.include_currency_l1_layer) { + clusterInfos.push({ + layer: LAYERS.CURRENCY_L1, + nodes: [ + { ip: event.aws.ec2.instances.genesis.ip, port: ports.currency_l1_public_port, id: event.aws.ec2.instances.genesis.id }, + { ip: event.aws.ec2.instances.validators[0].ip, port: ports.currency_l1_public_port, id: event.aws.ec2.instances.validators[0].id }, + { ip: event.aws.ec2.instances.validators[1].ip, port: ports.currency_l1_public_port, id: event.aws.ec2.instances.validators[1].id }, + ] + }) + } + + if (event.metagraph.include_data_l1_layer) { + clusterInfos.push({ + layer: LAYERS.DATA_L1, + nodes: [ + { ip: event.aws.ec2.instances.genesis.ip, port: ports.data_l1_public_port, id: event.aws.ec2.instances.genesis.id }, + { ip: event.aws.ec2.instances.validators[0].ip, port: ports.data_l1_public_port, id: event.aws.ec2.instances.validators[0].id }, + { ip: event.aws.ec2.instances.validators[1].ip, port: ports.data_l1_public_port, id: event.aws.ec2.instances.validators[1].id }, + ] + }) + } + + const allUnhealthyNodes = [] + for (const clusterInfo of clusterInfos) { + const unhealthyNodes = await _getUnhealthyNodes(clusterInfo) + if (unhealthyNodes.length > 0) { + console.log(`Some nodes of layer: ${clusterInfo.layer} are unhealthy: ${JSON.stringify(unhealthyNodes)}`) + allUnhealthyNodes.push(...unhealthyNodes) + } + } + + return allUnhealthyNodes +} + +export { + getLastMetagraphInfo, + getReferenceSourceNode, + getInformationToJoinNode, + getAllUnhealthyNodes +} \ No newline at end of file diff --git a/src/shared/index.js b/src/shared/index.js index 96af514..02af939 100644 --- a/src/shared/index.js +++ b/src/shared/index.js @@ -1,455 +1,21 @@ -import axios from 'axios' -import moment from 'moment' -import { SendCommandCommand, GetParameterCommand } from '@aws-sdk/client-ssm' -import { CHECK_CLUSTER_HEALTHY_LIMIT, LAYERS, NETWORK_NODES } from '../utils/types.js' - -const sleep = (ms) => { - return new Promise(resolve => setTimeout(resolve, ms)) -} - -const getLastMetagraphInfo = async (event) => { - const { network, metagraph } = event - const beUrl = `https://be-${network.name}.constellationnetwork.io/currency/${metagraph.id}/snapshots/latest` - try { - const response = await axios.get(beUrl) - const lastSnapshotTimestamp = response.data.data.timestamp - const lastSnapshotOrdinal = response.data.data.ordinal - const lastSnapshotHash = response.data.data.hash - - console.log(`LAST SNAPSHOT OF METAGRAPH ${metagraph.id}: ${lastSnapshotTimestamp}. Ordinal: ${lastSnapshotOrdinal}. Hash: ${lastSnapshotHash}`) - - return { - lastSnapshotTimestamp, - lastSnapshotOrdinal, - lastSnapshotHash - } - } catch (e) { - console.log(e) - throw Error(`Error when searching for metagraph on: ${beUrl}`, e) - } -} - -const getLatestMetagraphOfNetwork = async (networkName) => { - const beUrl = `https://be-${networkName}.constellationnetwork.io/global-snapshots/latest` - try { - const response = await axios.get(beUrl) - const lastSnapshotOrdinal = response.data.data.ordinal - const lastSnapshotHash = response.data.data.hash - - console.log(`LAST SNAPSHOT OF NETWORK: ${networkName}. Ordinal: ${lastSnapshotOrdinal}. Hash: ${lastSnapshotHash}`) - - return { - lastSnapshotOrdinal, - lastSnapshotHash - } - } catch (e) { - console.log(e) - throw Error(`Error when searching for snapshot on: ${beUrl}`, e) - } -} - -const checkIfSnapshotExistsOnNode = async (nodeIp, nodePort, snapshotHash) => { - const nodeUrl = `http://${nodeIp}:${nodePort}/global-snapshots/${snapshotHash}` - try { - await axios.get(nodeUrl) - console.log(`Snapshot exists on node: ${nodeIp}`) - return true - } catch (e) { - console.log(`Snapshot does not exists on node: ${nodeIp}`) - return false - } -} - -const getReferenceSourceNode = async (event) => { - const { network } = event - const networkName = network.name - - console.log(`Starting to get reference source node for network: ${networkName}`) - - const networkNodes = NETWORK_NODES[networkName] - if (!networkNodes || Object.keys(networkNodes).length === 0) { - throw Error(`Could not find nodes of network: ${networkName}`) - } - - const { node_1, node_2, node_3 } = networkNodes - const { lastSnapshotHash } = await getLatestMetagraphOfNetwork(networkName) - - const snapshotExistsOnNode1 = await checkIfSnapshotExistsOnNode(node_1.ip, node_1.port, lastSnapshotHash) - if (snapshotExistsOnNode1) { - return node_1 - } - - const snapshotExistsOnNode2 = await checkIfSnapshotExistsOnNode(node_2.ip, node_2.port, lastSnapshotHash) - if (snapshotExistsOnNode2) { - return node_2 - } - - const snapshotExistsOnNode3 = await checkIfSnapshotExistsOnNode(node_3.ip, node_3.port, lastSnapshotHash) - if (snapshotExistsOnNode3) { - return node_3 - } - - return null -} - -const sendCommand = async (ssmClient, commands, ec2InstancesIds) => { - const params = { - DocumentName: "AWS-RunShellScript", - InstanceIds: ec2InstancesIds, - Parameters: { - commands - }, - } - - try { - const commandResponse = await ssmClient.send(new SendCommandCommand(params)) - console.log("Command sent successfully. Command ID:", commandResponse.Command.CommandId) - } catch (error) { - console.error("Error sending command:", error) - } -} - -const getSSMParameter = async (ssmClient, parameterName) => { - const getParameterCommand = new GetParameterCommand({ - Name: parameterName, - }) - - const parameter = await ssmClient.send(getParameterCommand) - return parameter.Parameter.Value -} - -const getKeys = async (ssmClient, instanceId, layer) => { - const keyStore = await getSSMParameter(ssmClient, `/metagraph-nodes/${instanceId}/${layer}/keystore`) - const keyAlias = await getSSMParameter(ssmClient, `/metagraph-nodes/${instanceId}/${layer}/keyalias`) - const password = await getSSMParameter(ssmClient, `/metagraph-nodes/${instanceId}/${layer}/password`) - - return { keyStore, keyAlias, password } -} - -const killCurrentProcesses = async (ssmClient, event, ec2InstancesIds) => { - const { - metagraph_l0_public_port, - currency_l1_public_port, - data_l1_public_port, - } = event.metagraph.ports - - const commands = [ - `fuser -k ${metagraph_l0_public_port}/tcp`, - `fuser -k ${currency_l1_public_port}/tcp`, - `fuser -k ${data_l1_public_port}/tcp`, - ] - - await sendCommand(ssmClient, commands, ec2InstancesIds) -} - -const deleteSnapshotNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => { - const { file_system } = event.metagraph - const { lastSnapshotOrdinal } = await getLastMetagraphInfo(event) - const initialSnapshotToRemove = lastSnapshotOrdinal - const finalSnapshotToRemove = initialSnapshotToRemove + 1 - - console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) - const bkpDirectoryName = `incremental_snapshot_bkp_${moment.utc().format('YYYY_MM_DD_HH_mm_ss')}` - const creatingCommands = [ - `cd ${file_system.base_metagraph_l0_directory}`, - `mkdir -p data/${bkpDirectoryName}`, - - `echo "# Set the source and target directories - source_dir="data/incremental_snapshot" - target_dir="data/${bkpDirectoryName}/" - # Use find to locate the files within the specified range - for i in \\$(seq \\$1 \\$2); do - source_file="\\$source_dir/\\$i" - - # Check if the source file exists before attempting to move it - if [ -e "\\$source_file" ]; then - echo "Processing file with ID \\$source_file" - find \\$source_dir -mount -samefile \\$source_file -exec mv {} "\\$target_dir" \\; - else - echo "File \\$source_file does not exist." - fi - done" > mv_snapshots.sh`, - - `sudo chmod +x mv_snapshots.sh`, - ] - await sendCommand(ssmClient, creatingCommands, ec2InstancesIds) - console.log(`Finished creating mv_snapshot.sh script`) - - console.log(`Moving incremental snapshots on data/incremental_snapshot to data/incremental_snapshot_bkp between: ${initialSnapshotToRemove} - ${finalSnapshotToRemove}`) - const commands = [ - `cd ${file_system.base_metagraph_l0_directory}`, - `./mv_snapshots.sh ${initialSnapshotToRemove} ${finalSnapshotToRemove}` - ] - - await sendCommand(ssmClient, commands, ec2InstancesIds) - console.log(`Finishing moving the snapshots`) -} - -const joinNodeToCluster = async (ssmClient, event, layer, joiningNodeId, ec2InstancesIds) => { - const { ports } = event.metagraph - - const joiningInstruction = { - [LAYERS.L0]: `curl -v -X POST http://localhost:${ports.metagraph_l0_cli_port}/cluster/join -H "Content-type: application/json" -d '{ "id":"${joiningNodeId}", "ip": "${event.aws.ec2.instances.genesis.ip}", "p2pPort": ${ports.metagraph_l0_p2p_port} }'`, - [LAYERS.CURRENCY_L1]: `curl -v -X POST http://localhost:${ports.currency_l1_cli_port}/cluster/join -H "Content-type: application/json" -d '{ "id":"${joiningNodeId}", "ip": "${event.aws.ec2.instances.genesis.ip}", "p2pPort": ${ports.currency_l1_p2p_port} }'`, - [LAYERS.DATA_L1]: `curl -v -X POST http://localhost:${ports.data_l1_cli_port}/cluster/join -H "Content-type: application/json" -d '{ "id":"${joiningNodeId}", "ip": "${event.aws.ec2.instances.genesis.ip}", "p2pPort": ${ports.data_l1_p2p_port} }'` - } - - const commands = [joiningInstruction[layer]] - - await sendCommand(ssmClient, commands, ec2InstancesIds) -} - -const getInformationToJoinNode = async (event, layer) => { - const { ports } = event.metagraph - var urls = { - [LAYERS.L0]: `http://${event.aws.ec2.instances.genesis.ip}:${ports.metagraph_l0_public_port}/node/info`, - [LAYERS.CURRENCY_L1]: `http://${event.aws.ec2.instances.genesis.ip}:${ports.currency_l1_public_port}/node/info`, - [LAYERS.DATA_L1]: `http://${event.aws.ec2.instances.genesis.ip}:${ports.data_l1_public_port}/node/info`, - } - - for (let idx = 0; idx < 60; idx++) { - try { - const response = await axios.get(urls[layer]) - const nodeId = response.data.id - const state = response.data.state - if (state !== 'Ready') { - throw Error('Node not ready yet') - } - - return { nodeId } - } catch (e) { - if (idx === 59) { - throw Error(`Could not get information of node in URL: ${urls[layer]}`) - } - console.log(`Node is possibly not READY yet, waiting for 10s to try again (${idx + 1}/60)`) - await sleep(10000) - } - } -} - -const checkIfValidatorsStarted = async (event, layer) => { - const { ports } = event.metagraph - var layerPorts = { - [LAYERS.L0]: ports.metagraph_l0_public_port, - [LAYERS.CURRENCY_L1]: ports.currency_l1_public_port, - [LAYERS.DATA_L1]: ports.data_l1_public_port - } - - const validatorsUrls = event.aws.ec2.instances.validators.map(validator => { - return `http://${validator.ip}:${layerPorts[layer]}/node/info` - }) - - for (const url of validatorsUrls) { - console.log(`Checking validator at URL: ${url}`) - for (let idx = 0; idx < 11; idx++) { - try { - await axios.get(url) - console.log(`Node started and healthy`) - return - } catch (e) { - if (idx === 10) { - throw Error(`Could not get information of node in URL: ${url}`) - } - console.log(`Node is possibly not READY yet, waiting for 10s to try again (${idx + 1}/11)`) - await sleep(10000) - } - } - } -} - -const saveLogs = async (ssmClient, event, logName, layer, ec2InstancesIds) => { - const { file_system } = event.metagraph - printSeparatorWithMessage(`Saving logs ${layer} layer`) - const directory = { - [LAYERS.L0]: `cd ${file_system.base_metagraph_l0_directory}`, - [LAYERS.CURRENCY_L1]: `cd ${file_system.base_currency_l1_directory}`, - [LAYERS.DATA_L1]: `cd ${file_system.base_data_l1_directory}` - } - - const commands = [ - directory[layer], - `mkdir -p ../restart_logs`, - `zip -r ${logName} logs/app.log`, - `mv ${logName} ../restart_logs`, - `rm -r logs` - ] - - await sendCommand(ssmClient, commands, ec2InstancesIds) - - console.log('Waiting 10s to finish the compression...') - await sleep(10000) - printSeparatorWithMessage('Finished') -} - -const checkIfAllNodesAreReady = async (event, layer) => { - printSeparatorWithMessage(`[${layer}] Checking nodes states`) - const { ports } = event.metagraph - var layerPorts = { - [LAYERS.L0]: ports.metagraph_l0_public_port, - [LAYERS.CURRENCY_L1]: ports.currency_l1_public_port, - [LAYERS.DATA_L1]: ports.data_l1_public_port - } - - const validatorsUrls = layer === LAYERS.L0 ? [] : event.aws.ec2.instances.validators.map(validator => { - return `http://${validator.ip}:${layerPorts[layer]}/node/info` - }) - - let urls = [`http://${event.aws.ec2.instances.genesis.ip}:${layerPorts[layer]}/node/info`, ...validatorsUrls] - for (let idx = 0; idx < 20; idx++) { - try { - const readyNodesUrls = [] - for (const url of urls) { - const response = await axios.get(url) - const nodeState = response.data.state - if (nodeState === 'Ready') { - readyNodesUrls.push(url) - } - } - if (readyNodesUrls.length > 0) { - console.log(`[${layer}] The following nodes are already ready: ${JSON.stringify(readyNodesUrls)}`) - urls = urls.filter(url => !readyNodesUrls.includes(url)) - } - - if (urls.length === 0) { - console.log(`[${layer}] All nodes are on ready state`) - printSeparatorWithMessage(`[${layer}] Finished`) - return - } else { - console.log(`[${layer}] The following nodes are not ready yet: ${JSON.stringify(urls)}`) - console.log(`[${layer}] Not all nodes are on Ready state, trying again in 10s (${idx + 1}/20)`) - await sleep(10000) - } - } catch (e) { - if (idx === 19) { - throw new Error(`[${layer}] Failing when restarting nodes. All nodes should be on READY state`) - } - - console.log(`[${layer}] Not all nodes are on Ready state, trying again in 10s (${idx + 1}/20)`) - await sleep(10000) - } - } - -} - -const getAllEC2NodesInstances = (event) => { - const genesisNodeId = event.aws.ec2.instances.genesis.id - const validatorNodesId = event.aws.ec2.instances.validators.map(validator => validator.id) - - return [genesisNodeId, ...validatorNodesId] -} - -const _checkIfClusterIsUnhealthy = async (url, ports) => { - for (let idx = 0; idx < CHECK_CLUSTER_HEALTHY_LIMIT; idx++) { - try { - const response = await axios.get(url) - const clusterInfo = response.data - const isL0Url = url.includes(ports.metagraph_l0_public_port) - - console.log(`Cluster Info ${url} response: ${JSON.stringify(clusterInfo)}`) - - if (isL0Url) { - console.log(`L0 Cluster, at least one node should be Ready`) - - const anyNodeReady = clusterInfo.some(node => { - return node.state === 'Ready' - }) - - if (!anyNodeReady) { - console.log("All L0 nodes are not ready") - return true - } - - return false - } - - console.log(`L1 Cluster, at least 3 nodes should be Ready`) - if (clusterInfo.length < 3) { - console.log(`Less than 3 nodes: ${url}`) - return true - } - - const readyNodes = clusterInfo.filter(node => { - return node.state === 'Ready' - }) - - if (readyNodes.length < 3) { - console.log(`We should have at least 3 ready nodes: ${url}`) - return true - } - - return false - } catch (e) { - if (idx === 4) { - console.log(`Unhealthy cluster after trying ${CHECK_CLUSTER_HEALTHY_LIMIT} times`) - return true - } - console.log(`Could not get cluster information at URL: ${url}. Trying again in 5s (${idx + 1}/${CHECK_CLUSTER_HEALTHY_LIMIT})`) - await sleep(5 * 1000) - } - } -} - -const getUnhealthyClusters = async (event) => { - const { ports } = event.metagraph - let urls = [`http://${event.aws.ec2.instances.genesis.ip}:${ports.metagraph_l0_public_port}/cluster/info`] - - if (event.metagraph.include_currency_l1_layer) { - urls.push(`http://${event.aws.ec2.instances.genesis.ip}:${ports.currency_l1_public_port}/cluster/info`) - } - - if (event.metagraph.include_data_l1_layer) { - urls.push(`http://${event.aws.ec2.instances.genesis.ip}:${ports.data_l1_public_port}/cluster/info`) - } - - const unhealthyClusters = [] - for (const url of urls) { - const clusterIsUnhealthy = await _checkIfClusterIsUnhealthy(url, ports) - if(clusterIsUnhealthy){ - unhealthyClusters.push(url) - } - } - - return unhealthyClusters -} - -const printSeparatorWithMessage = (message) => { - console.log(`\n########################## ${message} ###############################\n`) -} - -const checkIfRollbackFinished = async (event) => { - try { - const { metagraph_l0_public_port } = event.metagraph.ports - const url = `http://${event.aws.ec2.instances.genesis.ip}:${metagraph_l0_public_port}/node/info` - - const response = await axios.get(url) - const nodeState = response.data.state - console.log(`Current state of genesis node: ${nodeState}`) - if (nodeState === 'Ready') { - return true - } - return false - } catch (e) { - console.log("Error when checking node url", e) - return false - } -} +import { sleep } from './shared.js' +import { checkIfNodeIsReady, checkIfValidatorsStarted, checkIfNodeStarted, checkIfAllNodesAreReady } from './check_nodes_health.js' +import { getLastMetagraphInfo, getReferenceSourceNode, getInformationToJoinNode, getAllUnhealthyNodes } from './get_metagraph_info.js' +import { killCurrentExecution, joinNodeToCluster, saveLogs, getLogsNames, groupBy } from './restart_operations.js' export { sleep, + checkIfNodeIsReady, + checkIfValidatorsStarted, + checkIfNodeStarted, + checkIfAllNodesAreReady, getLastMetagraphInfo, - sendCommand, - killCurrentProcesses, - joinNodeToCluster, + getReferenceSourceNode, getInformationToJoinNode, - checkIfValidatorsStarted, - printSeparatorWithMessage, - getSSMParameter, - getKeys, + getAllUnhealthyNodes, + killCurrentExecution, + joinNodeToCluster, saveLogs, - checkIfAllNodesAreReady, - getAllEC2NodesInstances, - deleteSnapshotNotSyncToGL0, - getUnhealthyClusters, - checkIfRollbackFinished, - getReferenceSourceNode + getLogsNames, + groupBy } \ No newline at end of file diff --git a/src/shared/restart_operations.js b/src/shared/restart_operations.js new file mode 100644 index 0000000..a45b03a --- /dev/null +++ b/src/shared/restart_operations.js @@ -0,0 +1,144 @@ +import moment from 'moment' +import { LAYERS, NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE } from '../utils/types.js' +import { sendCommand } from '../external/aws/ssm.js' +import { sleep } from './shared.js' +import { getLastMetagraphInfo } from './get_metagraph_info.js' + +const _movingSnapshotsNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => { + const { file_system } = event.metagraph + const { lastSnapshotOrdinal } = await getLastMetagraphInfo(event) + const initialSnapshotToRemove = lastSnapshotOrdinal + const finalSnapshotToRemove = initialSnapshotToRemove + NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE + + console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) + const bkpDirectoryName = `incremental_snapshot_bkp_${moment.utc().format('YYYY_MM_DD_HH_mm_ss')}` + const creatingCommands = [ + `cd ${file_system.base_metagraph_l0_directory}`, + `mkdir -p data/${bkpDirectoryName}`, + + `echo "# Set the source and target directories + source_dir="data/incremental_snapshot" + target_dir="data/${bkpDirectoryName}/" + # Use find to locate the files within the specified range + for i in \\$(seq \\$1 \\$2); do + source_file="\\$source_dir/\\$i" + + # Check if the source file exists before attempting to move it + if [ -e "\\$source_file" ]; then + echo "Processing file with ID \\$source_file" + find \\$source_dir -mount -samefile \\$source_file -exec mv {} "\\$target_dir" \\; + else + echo "File \\$source_file does not exist." + fi + done" > mv_snapshots.sh`, + + `sudo chmod +x mv_snapshots.sh`, + ] + await sendCommand(ssmClient, creatingCommands, ec2InstancesIds) + console.log(`Finished creating mv_snapshot.sh script`) + + console.log(`Moving incremental snapshots on data/incremental_snapshot to data/${bkpDirectoryName} between: ${initialSnapshotToRemove} - ${finalSnapshotToRemove}`) + const commands = [ + `cd ${file_system.base_metagraph_l0_directory}`, + `./mv_snapshots.sh ${initialSnapshotToRemove} ${finalSnapshotToRemove}` + ] + + await sendCommand(ssmClient, commands, ec2InstancesIds) + console.log(`Finishing moving the snapshots`) +} + +const killCurrentExecution = async (ssmClient, event, layer, ec2InstancesIds) => { + const { + metagraph_l0_public_port, + currency_l1_public_port, + data_l1_public_port, + } = event.metagraph.ports + + console.log(`Stopping ${layer} on ${JSON.stringify(ec2InstancesIds)}`) + + if (layer === LAYERS.L0) { + const commands = [`fuser -k ${metagraph_l0_public_port}/tcp`] + await sendCommand(ssmClient, commands, ec2InstancesIds) + await _movingSnapshotsNotSyncToGL0(ssmClient, event, ec2InstancesIds) + return + } + + if (layer === LAYERS.CURRENCY_L1) { + const commands = [`fuser -k ${currency_l1_public_port}/tcp`] + await sendCommand(ssmClient, commands, ec2InstancesIds) + return + } + + if (layer === LAYERS.DATA_L1) { + const commands = [`fuser -k ${data_l1_public_port}/tcp`] + await sendCommand(ssmClient, commands, ec2InstancesIds) + return + } +} + +const joinNodeToCluster = async (ssmClient, event, layer, nodeInformation, ec2InstancesIds) => { + const { nodeId, nodeHost, nodeP2pPort } = nodeInformation + const { ports } = event.metagraph + + const joiningInstruction = { + [LAYERS.L0]: `curl -v -X POST http://localhost:${ports.metagraph_l0_cli_port}/cluster/join -H "Content-type: application/json" -d '{ "id":"${nodeId}", "ip": "${nodeHost}", "p2pPort": ${nodeP2pPort} }'`, + [LAYERS.CURRENCY_L1]: `curl -v -X POST http://localhost:${ports.currency_l1_cli_port}/cluster/join -H "Content-type: application/json" -d '{ "id":"${nodeId}", "ip": "${nodeHost}", "p2pPort": ${nodeP2pPort} }'`, + [LAYERS.DATA_L1]: `curl -v -X POST http://localhost:${ports.data_l1_cli_port}/cluster/join -H "Content-type: application/json" -d '{ "id":"${nodeId}", "ip": "${nodeHost}", "p2pPort": ${nodeP2pPort} }'` + } + + const commands = [joiningInstruction[layer]] + + await sendCommand(ssmClient, commands, ec2InstancesIds) +} + +const saveLogs = async (ssmClient, event, logName, layer, ec2InstancesIds) => { + console.log(`Saving logs ${layer} nodes: ${JSON.stringify(ec2InstancesIds)}`) + const { file_system } = event.metagraph + const directory = { + [LAYERS.L0]: `cd ${file_system.base_metagraph_l0_directory}`, + [LAYERS.CURRENCY_L1]: `cd ${file_system.base_currency_l1_directory}`, + [LAYERS.DATA_L1]: `cd ${file_system.base_data_l1_directory}` + } + + const commands = [ + directory[layer], + `mkdir -p ../restart_logs`, + `zip -r ${logName} logs/app.log`, + `mv ${logName} ../restart_logs`, + `rm -r logs` + ] + + await sendCommand(ssmClient, commands, ec2InstancesIds) + + console.log('Waiting 10s to finish the compression...') + await sleep(10 * 1000) +} + +const getLogsNames = () => { + const now = moment.utc().format('YYY-MM-DD_HH-mm-ss') + + const l0LogName = `log-${now}-l0.zip` + const cl1LogName = `log-${now}-cl1.zip` + const dl1LogName = `log-${now}-dl1.zip` + + return { + l0LogName, + cl1LogName, + dl1LogName + } +} + +const groupBy = function (xs, key) { + return xs.reduce(function (rv, x) { + (rv[x[key]] = rv[x[key]] || []).push(x); + return rv; + }, {}); +}; + +export { + killCurrentExecution, + joinNodeToCluster, + saveLogs, + getLogsNames, + groupBy +} \ No newline at end of file diff --git a/src/shared/shared.js b/src/shared/shared.js new file mode 100644 index 0000000..a8e1335 --- /dev/null +++ b/src/shared/shared.js @@ -0,0 +1,7 @@ +const sleep = (ms) => { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +export { + sleep +} \ No newline at end of file diff --git a/src/utils/types.js b/src/utils/types.js index 92f070b..ce59422 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -4,7 +4,12 @@ const LAYERS = { DATA_L1: 'data-l1' } -const VALID_NETWORKS = ['mainnet', 'integrationnet', 'testnet'] +const KEY_LAYERS = { + L0: 'l0', + CURRENCY_L1: 'cl1', + DATA_L1: 'dl1' +} + const VALID_NETWORKS_TAGS_OPSGENIE = { mainnet: 'env:MainNet', integrationnet: 'env:IntegrationNet', @@ -19,14 +24,27 @@ const RESTART_REASONS = { UNHEALTHY_CLUSTER: "One of the clusters are unhealthy (less than 3 nodes or nodes with not Ready state)" } +const DYNAMO_RESTART_TYPES = { + NOT_RESTART: "NOT RESTART", + FULL_CLUSTER: "Full Cluster", + INDIVIDUAL_NODES: "Individual Nodes" +} + const DYNAMO_RESTART_STATE = { NEW: 'NEW', - ROLLBACK_IN_PROGRESS: "ROLLBACK IN PROGRESS", + ROLLBACK_IN_PROGRESS: 'ROLLBACK IN PROGRESS', + READY_TO_JOIN: 'READY TO JOIN', READY: 'READY' } const DYNAMO_DB_TABLE_AUTO_RESTART = 'auto_restart' -const CHECK_CLUSTER_HEALTHY_LIMIT = 5 +const CHECK_NODE_HEALTHY_LIMIT = 5 + +const OPSGENIE_API_KEY_PATH = '/metagraph-nodes/opsgenie-api-key' + +const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 600 + +const NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE = 100 const NETWORK_NODES = { testnet: { @@ -84,12 +102,16 @@ const NETWORK_NODES = { export { LAYERS, - VALID_NETWORKS, + KEY_LAYERS, VALID_NETWORKS_TAGS_OPSGENIE, DATE_FORMAT, RESTART_REASONS, + DYNAMO_RESTART_TYPES, DYNAMO_RESTART_STATE, DYNAMO_DB_TABLE_AUTO_RESTART, - CHECK_CLUSTER_HEALTHY_LIMIT, - NETWORK_NODES + CHECK_NODE_HEALTHY_LIMIT, + NETWORK_NODES, + OPSGENIE_API_KEY_PATH, + ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES, + NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE } \ No newline at end of file From de46cdd88d7feb09fcce0e02e8091ae713299875 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 21 Nov 2023 21:03:56 -0300 Subject: [PATCH 23/30] Fixing --- index.js | 4 ++-- src/restarts/individual_node.js | 22 ++++++++++++++-------- src/shared/restart_operations.js | 1 + 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/index.js b/index.js index 86b94a0..698642d 100644 --- a/index.js +++ b/index.js @@ -83,7 +83,7 @@ const getMetagraphRestartType = async (event, lastSnapshotTimestamp) => { const unhealthyDataL1 = unhealthyNodesGroupedByLayer[LAYERS.DATA_L1] ?? [] if (unhealthyNodes.length === 9 || unhealthyMetagraphL0.length === 3) { - console.log(`Restart type FULL CLUSTER: Unhealthy clusters. ML0: ${JSON.stringify(unhealthyMetagraphL0)}, CL1: ${unhealthyCurrencyL1}, DL1: ${unhealthyDataL1}`) + console.log(`Restart type FULL CLUSTER: Unhealthy clusters. ML0: ${JSON.stringify(unhealthyMetagraphL0)}, CL1: ${JSON.stringify(unhealthyCurrencyL1)}, DL1: ${JSON.stringify(unhealthyDataL1)}`) return { restartType: DYNAMO_RESTART_TYPES.FULL_CLUSTER, reason: RESTART_REASONS.UNHEALTHY_CLUSTER, @@ -95,7 +95,7 @@ const getMetagraphRestartType = async (event, lastSnapshotTimestamp) => { } } - console.log(`Restart type INDIVIDUAL NODES: Unhealthy clusters. ML0: ${unhealthyMetagraphL0}, CL1: ${unhealthyCurrencyL1}, DL1: ${unhealthyDataL1}`) + console.log(`Restart type INDIVIDUAL NODES: Unhealthy clusters. ML0: ${JSON.stringify(unhealthyMetagraphL0)}, CL1: ${JSON.stringify(unhealthyCurrencyL1)}, DL1: ${JSON.stringify(unhealthyDataL1)}`) return { restartType: DYNAMO_RESTART_TYPES.INDIVIDUAL_NODES, reason: RESTART_REASONS.UNHEALTHY_CLUSTER, diff --git a/src/restarts/individual_node.js b/src/restarts/individual_node.js index ad977d1..13f7d0c 100644 --- a/src/restarts/individual_node.js +++ b/src/restarts/individual_node.js @@ -4,7 +4,7 @@ import { startValidatorNodeL0 } from "../metagraph-l0/index.js" import { getInformationToJoinNode, sleep, joinNodeToCluster, checkIfNodeStarted } from "../shared/index.js" import { LAYERS } from "../utils/types.js" -const startMetagraphL0ValidatorNode = async (ssmClient, event, node, logName, nodeId, referenceSourceNode) => { +const startMetagraphL0ValidatorNode = async (ssmClient, event, node, logName, nodeInformation, referenceSourceNode) => { console.log(`Starting validator ${node.ip}`) await startValidatorNodeL0( ssmClient, @@ -15,10 +15,12 @@ const startMetagraphL0ValidatorNode = async (ssmClient, event, node, logName, no ) await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) - await sleep(10 * 1000) - await joinNodeToCluster(ssmClient, event, LAYERS.L0, nodeId, [node.id]) - return nodeId + console.log('Waiting 10s before joining...') + await sleep(10 * 1000) + + console.log(`Joining validator ${node.ip}`) + await joinNodeToCluster(ssmClient, event, LAYERS.L0, nodeInformation, [node.id]) } const startCurrencyL1ValidatorNode = async (ssmClient, event, node, logName, ml0NodeId, referenceSourceNode) => { @@ -34,6 +36,8 @@ const startCurrencyL1ValidatorNode = async (ssmClient, event, node, logName, ml0 ) await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) + + console.log('Waiting 10s before joining...') await sleep(10 * 1000) console.log(`Joining validator ${node.ip}`) @@ -54,6 +58,8 @@ const startDataL1ValidatorNode = async (ssmClient, event, node, logName, ml0Node ) await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) + + console.log('Waiting 10s before joining...') await sleep(10 * 1000) console.log(`Joining validator ${node.ip}`) @@ -61,16 +67,16 @@ const startDataL1ValidatorNode = async (ssmClient, event, node, logName, ml0Node } const restartIndividualNode = async (ssmClient, event, logName, node, referenceSourceNode) => { - const { nodeId } = await getInformationToJoinNode(event, LAYERS.L0) + const nodeInformation = await getInformationToJoinNode(event, LAYERS.L0) if (node.layer === LAYERS.L0) { - await startMetagraphL0ValidatorNode(ssmClient, event, node, logName, nodeId, referenceSourceNode) + await startMetagraphL0ValidatorNode(ssmClient, event, node, logName, nodeInformation, referenceSourceNode) } if (node.layer === LAYERS.CURRENCY_L1) { - await startCurrencyL1ValidatorNode(ssmClient, event, node, logName, nodeId, referenceSourceNode) + await startCurrencyL1ValidatorNode(ssmClient, event, node, logName, nodeInformation.nodeId, referenceSourceNode) } if (node.layer === LAYERS.DATA_L1) { - await startDataL1ValidatorNode(ssmClient, event, node, logName, nodeId, referenceSourceNode) + await startDataL1ValidatorNode(ssmClient, event, node, logName, nodeInformation.nodeId, referenceSourceNode) } } diff --git a/src/shared/restart_operations.js b/src/shared/restart_operations.js index a45b03a..3ee423e 100644 --- a/src/shared/restart_operations.js +++ b/src/shared/restart_operations.js @@ -80,6 +80,7 @@ const joinNodeToCluster = async (ssmClient, event, layer, nodeInformation, ec2In const { nodeId, nodeHost, nodeP2pPort } = nodeInformation const { ports } = event.metagraph + console.log(`Joining to node ${nodeHost} with id: ${nodeId}`) const joiningInstruction = { [LAYERS.L0]: `curl -v -X POST http://localhost:${ports.metagraph_l0_cli_port}/cluster/join -H "Content-type: application/json" -d '{ "id":"${nodeId}", "ip": "${nodeHost}", "p2pPort": ${nodeP2pPort} }'`, [LAYERS.CURRENCY_L1]: `curl -v -X POST http://localhost:${ports.currency_l1_cli_port}/cluster/join -H "Content-type: application/json" -d '{ "id":"${nodeId}", "ip": "${nodeHost}", "p2pPort": ${nodeP2pPort} }'`, From 86973bc47e127e3c492c22ecbe5045b4a637c866 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Fri, 24 Nov 2023 14:00:23 -0300 Subject: [PATCH 24/30] Updating restart --- src/restarts/full_cluster.js | 31 +++++++++++++++---------------- src/shared/restart_operations.js | 2 +- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/restarts/full_cluster.js b/src/restarts/full_cluster.js index 70cf0ef..7b04412 100644 --- a/src/restarts/full_cluster.js +++ b/src/restarts/full_cluster.js @@ -1,7 +1,7 @@ import { startInitialValidatorNodeCurrencyL1, startValidatorNodeCurrencyL1 } from "../currency-l1/index.js" import { startInitialValidatorNodeDataL1, startValidatorNodeDataL1 } from "../data-l1/index.js" import { startRollbackNodeL0, startValidatorNodeL0 } from "../metagraph-l0/index.js" -import { getInformationToJoinNode, checkIfValidatorsStarted, sleep, joinNodeToCluster, killCurrentExecution } from "../shared/index.js" +import { getInformationToJoinNode, sleep, joinNodeToCluster, killCurrentExecution, checkIfNodeStarted } from "../shared/index.js" import { LAYERS } from "../utils/types.js" const startMetagraphL0Validators = async (ssmClient, event, logName, nodeId, referenceSourceNode) => { @@ -14,10 +14,9 @@ const startMetagraphL0Validators = async (ssmClient, event, logName, nodeId, ref validator, referenceSourceNode ) - } - await checkIfValidatorsStarted(event, LAYERS.L0) - for (const validator of event.aws.ec2.instances.validators) { + const { metagraph_l0_public_port } = event.metagraph.ports + await checkIfNodeStarted(`http://${validator.ip}:${metagraph_l0_public_port}/node/info`) console.log(`Joining validator ${validator.ip}`) await joinNodeToCluster(ssmClient, event, LAYERS.L0, nodeId, [validator.id]) } @@ -39,10 +38,9 @@ const startCurrencyL1Nodes = async (ssmClient, event, logName, ml0NodeId, refere validator, referenceSourceNode ) - } + const { currency_l1_public_port } = event.metagraph.ports - await checkIfValidatorsStarted(event, LAYERS.CURRENCY_L1) - for (const validator of event.aws.ec2.instances.validators) { + await checkIfNodeStarted(`http://${validator.ip}:${currency_l1_public_port}/node/info`) console.log(`Joining validator ${validator.ip}`) await joinNodeToCluster(ssmClient, event, LAYERS.CURRENCY_L1, nodeInformation, [validator.id]) } @@ -63,10 +61,10 @@ const startDataL1Nodes = async (ssmClient, event, logName, ml0NodeId, referenceS validator, referenceSourceNode ) - } - await checkIfValidatorsStarted(event, LAYERS.DATA_L1) - for (const validator of event.aws.ec2.instances.validators) { + const { data_l1_public_port } = event.metagraph.ports + + await checkIfNodeStarted(`http://${validator.ip}:${data_l1_public_port}/node/info`) console.log(`Joining validator ${validator.ip}`) await joinNodeToCluster(ssmClient, event, LAYERS.DATA_L1, nodeInformation, [validator.id]) } @@ -74,24 +72,25 @@ const startDataL1Nodes = async (ssmClient, event, logName, ml0NodeId, referenceS const startMetagraphRollback = async (ssmClient, event, l0LogName, referenceSourceNode) => { const allInstancesIds = [event.aws.ec2.instances.genesis.id, event.aws.ec2.instances.validators[0].id, event.aws.ec2.instances.validators[1].id] - + await killCurrentExecution(ssmClient, event, LAYERS.L0, allInstancesIds) await killCurrentExecution(ssmClient, event, LAYERS.CURRENCY_L1, allInstancesIds) await killCurrentExecution(ssmClient, event, LAYERS.DATA_L1, allInstancesIds) - + await startRollbackNodeL0(ssmClient, event, event.aws.ec2.instances.genesis, referenceSourceNode, l0LogName, false) } const finishMetagraphRollback = async (ssmClient, event, { l0LogName, cl1LogName, dl1LogName }, referenceSourceNode) => { - const { nodeId } = await getInformationToJoinNode(event, LAYERS.L0) + const node = await getInformationToJoinNode(event, LAYERS.L0) + + await startMetagraphL0Validators(ssmClient, event, l0LogName, node, referenceSourceNode) - await startMetagraphL0Validators(ssmClient, event, l0LogName, nodeId, referenceSourceNode) if (event.metagraph.include_currency_l1_layer) { - await startCurrencyL1Nodes(ssmClient, event, cl1LogName, nodeId, referenceSourceNode) + await startCurrencyL1Nodes(ssmClient, event, cl1LogName, node.nodeId, referenceSourceNode) } if (event.metagraph.include_data_l1_layer) { - await startDataL1Nodes(ssmClient, event, nodeId, dl1LogName, referenceSourceNode) + await startDataL1Nodes(ssmClient, event, dl1LogName, node.nodeId, referenceSourceNode) } } diff --git a/src/shared/restart_operations.js b/src/shared/restart_operations.js index 3ee423e..38e31e7 100644 --- a/src/shared/restart_operations.js +++ b/src/shared/restart_operations.js @@ -88,7 +88,7 @@ const joinNodeToCluster = async (ssmClient, event, layer, nodeInformation, ec2In } const commands = [joiningInstruction[layer]] - + console.log(`Sending joining ${commands} to :${ec2InstancesIds}`) await sendCommand(ssmClient, commands, ec2InstancesIds) } From eee9ce2cbee20cb3008b33414d5eafda7d0b176d Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Fri, 1 Dec 2023 13:20:43 -0300 Subject: [PATCH 25/30] Fixing --- index.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 698642d..dc55553 100644 --- a/index.js +++ b/index.js @@ -189,11 +189,13 @@ export const handler = async (event) => { if (metagraphRestartType.restartType === DYNAMO_RESTART_TYPES.INDIVIDUAL_NODES) { const unhealthyNodes = [...metagraphRestartType.unhealthyNodes.unhealthyMetagraphL0] + const unhealthyClusters = [] if ( metagraphRestartType.unhealthyNodes.unhealthyCurrencyL1 && metagraphRestartType.unhealthyNodes.unhealthyCurrencyL1.length === 3 ) { await restartIndividualCluster(ssmClient, event, logsNames.cl1LogName, LAYERS.CURRENCY_L1, referenceSourceNode) + unhealthyClusters.push(...metagraphRestartType.unhealthyNodes.unhealthyCurrencyL1) } else { unhealthyNodes.push(...metagraphRestartType.unhealthyNodes.unhealthyCurrencyL1) } @@ -203,6 +205,7 @@ export const handler = async (event) => { metagraphRestartType.unhealthyNodes.unhealthyDataL1.length === 3 ) { await restartIndividualCluster(ssmClient, event, logsNames.dl1LogName, LAYERS.DATA_L1, referenceSourceNode) + unhealthyClusters.push(...metagraphRestartType.unhealthyNodes.unhealthyDataL1) } else { unhealthyNodes.push(...metagraphRestartType.unhealthyNodes.unhealthyDataL1) } @@ -212,7 +215,7 @@ export const handler = async (event) => { await restartIndividualNode(ssmClient, event, logName, node, referenceSourceNode) } - const nodesIpsWithPorts = unhealthyNodes.map(node => `${node.ip}:${node.port}`) + const nodesIpsWithPorts = [...unhealthyNodes, ...unhealthyClusters].map(node => `${node.ip}:${node.port}`) const metagraphRestart = await upsertMetagraphRestart( metagraphId, DYNAMO_RESTART_STATE.ROLLBACK_IN_PROGRESS, From 973238f4c8619e00ce5fe93d66894d7af7c993b5 Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Tue, 5 Dec 2023 10:27:27 -0300 Subject: [PATCH 26/30] Fixing bugs --- index.js | 2 +- src/restarts/check_restart_progress.js | 23 +++++++----- src/restarts/individual_node.js | 15 ++------ src/shared/check_nodes_health.js | 24 ++++++------- src/shared/get_metagraph_info.js | 8 ++--- src/shared/restart_operations.js | 48 -------------------------- src/utils/types.js | 3 +- 7 files changed, 36 insertions(+), 87 deletions(-) diff --git a/index.js b/index.js index dc55553..6a5d6a4 100644 --- a/index.js +++ b/index.js @@ -64,7 +64,7 @@ const getMetagraphRestartType = async (event, lastSnapshotTimestamp) => { } const lastSnapshotTimestampDiff = moment.utc().diff(lastSnapshotTimestamp, 'minutes') - if (lastSnapshotTimestampDiff > 4) { + if (lastSnapshotTimestampDiff > 3) { console.log(`Restart type FULL CLUSTER: Snapshots stopped being produced`) return { restartType: DYNAMO_RESTART_TYPES.FULL_CLUSTER, diff --git a/src/restarts/check_restart_progress.js b/src/restarts/check_restart_progress.js index 03fc839..0231470 100644 --- a/src/restarts/check_restart_progress.js +++ b/src/restarts/check_restart_progress.js @@ -8,7 +8,7 @@ import { finishMetagraphRollback } from "./full_cluster.js" const checkFullClusterRestart = async (event, metagraphId, currentMetagraphRestart) => { console.log(`Checking full cluster restart`) const { state, restartType, restartReason, referenceNodeIp } = currentMetagraphRestart; - + const node1 = event.aws.ec2.instances.genesis const node2 = event.aws.ec2.instances.validators[0] const node3 = event.aws.ec2.instances.validators[1] @@ -69,7 +69,7 @@ const checkRestartStatus = async (event, networkName, currentMetagraphRestart) = } if (restartType === DYNAMO_RESTART_TYPES.FULL_CLUSTER) { return await checkFullClusterRestart(event, metagraphId, currentMetagraphRestart) - } + } if (restartType === DYNAMO_RESTART_TYPES.INDIVIDUAL_NODES) { return await checkIndividualNodesRestart(metagraphId, currentMetagraphRestart) } @@ -130,17 +130,24 @@ const getMetagraphRestartProgress = async (ssmClient, event, currentMetagraphRes currentMetagraphRestart ) - if ( - metagraphRestartProgress.metagraphRestart.state === DYNAMO_RESTART_STATE.READY_TO_JOIN && - metagraphRestartProgress.metagraphRestart.restartType === DYNAMO_RESTART_TYPES.FULL_CLUSTER - ) { + const { state, restartType, restartReason, referenceNodeIp } = metagraphRestartProgress.metagraphRestart + if (state === DYNAMO_RESTART_STATE.READY_TO_JOIN && restartType === DYNAMO_RESTART_TYPES.FULL_CLUSTER) { console.log(`Metagraph is READY_TO_JOIN triggering finishMetagraphRollback`) + const logsNames = getLogsNames() await finishMetagraphRollback(ssmClient, event, logsNames, referenceSourceNode) + await upsertMetagraphRestart( + event.metagraph.id, + DYNAMO_RESTART_STATE.JOINING, + restartType, + restartReason, + referenceNodeIp, + ) + return { status: 200, - restartState: DYNAMO_RESTART_STATE.READY_TO_JOIN, + restartState: DYNAMO_RESTART_STATE.JOINING, body: 'finishMetagraphRollback triggered, finishing current execution.', metagraphRestart: currentMetagraphRestart } @@ -169,7 +176,7 @@ const getMetagraphRestartProgress = async (ssmClient, event, currentMetagraphRes metagraphRestartProgress.metagraphRestart ) - const metagraphRestart = await getMetagraphRestartOrCreateNew(metagraphId) + const metagraphRestart = await getMetagraphRestartOrCreateNew(metagraphId) return { status: 200, restartState: DYNAMO_RESTART_STATE.NEW, diff --git a/src/restarts/individual_node.js b/src/restarts/individual_node.js index 13f7d0c..1f70afd 100644 --- a/src/restarts/individual_node.js +++ b/src/restarts/individual_node.js @@ -1,7 +1,7 @@ import { startValidatorNodeCurrencyL1 } from "../currency-l1/index.js" import { startValidatorNodeDataL1 } from "../data-l1/index.js" import { startValidatorNodeL0 } from "../metagraph-l0/index.js" -import { getInformationToJoinNode, sleep, joinNodeToCluster, checkIfNodeStarted } from "../shared/index.js" +import { getInformationToJoinNode, joinNodeToCluster, checkIfNodeStarted } from "../shared/index.js" import { LAYERS } from "../utils/types.js" const startMetagraphL0ValidatorNode = async (ssmClient, event, node, logName, nodeInformation, referenceSourceNode) => { @@ -14,11 +14,7 @@ const startMetagraphL0ValidatorNode = async (ssmClient, event, node, logName, no referenceSourceNode ) - await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) - - console.log('Waiting 10s before joining...') - await sleep(10 * 1000) - + await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) console.log(`Joining validator ${node.ip}`) await joinNodeToCluster(ssmClient, event, LAYERS.L0, nodeInformation, [node.id]) } @@ -36,9 +32,6 @@ const startCurrencyL1ValidatorNode = async (ssmClient, event, node, logName, ml0 ) await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) - - console.log('Waiting 10s before joining...') - await sleep(10 * 1000) console.log(`Joining validator ${node.ip}`) await joinNodeToCluster(ssmClient, event, LAYERS.CURRENCY_L1, nodeInformation, [node.id]) @@ -58,10 +51,6 @@ const startDataL1ValidatorNode = async (ssmClient, event, node, logName, ml0Node ) await checkIfNodeStarted(`http://${node.ip}:${node.port}/node/info`) - - console.log('Waiting 10s before joining...') - await sleep(10 * 1000) - console.log(`Joining validator ${node.ip}`) await joinNodeToCluster(ssmClient, event, LAYERS.DATA_L1, nodeInformation, [node.id]) } diff --git a/src/shared/check_nodes_health.js b/src/shared/check_nodes_health.js index 2e247f9..21cd860 100644 --- a/src/shared/check_nodes_health.js +++ b/src/shared/check_nodes_health.js @@ -1,5 +1,5 @@ import axios from 'axios' -import { LAYERS } from '../utils/types.js' +import { CHECK_NODE_HEALTHY_LIMIT, LAYERS } from '../utils/types.js' import { sleep } from './shared.js' const checkIfNodeIsReady = async (nodeIp, nodePort) => { @@ -34,7 +34,7 @@ const checkIfValidatorsStarted = async (event, layer) => { for (const url of validatorsUrls) { console.log(`Checking validator at URL: ${url}`) - for (let idx = 0; idx < 11; idx++) { + for (let idx = 0; idx < CHECK_NODE_HEALTHY_LIMIT; idx++) { try { await axios.get(url) console.log(`Node started and healthy`) @@ -43,15 +43,15 @@ const checkIfValidatorsStarted = async (event, layer) => { if (idx === 10) { throw Error(`Could not get information of node in URL: ${url}`) } - console.log(`Node is possibly not READY yet, waiting for 10s to try again (${idx + 1}/11)`) - await sleep(10 * 1000) + console.log(`Node is possibly not READY yet, waiting for 1s to try again (${idx + 1}/${CHECK_NODE_HEALTHY_LIMIT})`) + await sleep(1 * 1000) } } } } const checkIfNodeStarted = async (url) => { - for (let idx = 0; idx < 11; idx++) { + for (let idx = 0; idx < CHECK_NODE_HEALTHY_LIMIT; idx++) { try { await axios.get(url) console.log(`Node started`) @@ -60,8 +60,8 @@ const checkIfNodeStarted = async (url) => { if (idx === 10) { throw Error(`Could not get information of node in URL: ${url}`) } - console.log(`Node possibly not started yet, waiting for 10s to try again (${idx + 1}/11)`) - await sleep(10 * 1000) + console.log(`Node possibly not started yet, waiting for 1s to try again (${idx + 1}/${CHECK_NODE_HEALTHY_LIMIT})`) + await sleep(1 * 1000) } } @@ -80,7 +80,7 @@ const checkIfAllNodesAreReady = async (event, layer) => { }) let urls = [`http://${event.aws.ec2.instances.genesis.ip}:${layerPorts[layer]}/node/info`, ...validatorsUrls] - for (let idx = 0; idx < 20; idx++) { + for (let idx = 0; idx < CHECK_NODE_HEALTHY_LIMIT; idx++) { try { const readyNodesUrls = [] for (const url of urls) { @@ -100,16 +100,16 @@ const checkIfAllNodesAreReady = async (event, layer) => { return } else { console.log(`[${layer}] The following nodes are not ready yet: ${JSON.stringify(urls)}`) - console.log(`[${layer}] Not all nodes are on Ready state, trying again in 10s (${idx + 1}/20)`) - await sleep(10 * 1000) + console.log(`[${layer}] Not all nodes are on Ready state, trying again in 1s (${idx + 1}/${CHECK_NODE_HEALTHY_LIMIT})`) + await sleep(1 * 1000) } } catch (e) { if (idx === 19) { throw new Error(`[${layer}] Failing when restarting nodes. All nodes should be on READY state`) } - console.log(`[${layer}] Not all nodes are on Ready state, trying again in 10s (${idx + 1}/20)`) - await sleep(10 * 1000) + console.log(`[${layer}] Not all nodes are on Ready state, trying again in 1s (${idx + 1}/${CHECK_NODE_HEALTHY_LIMIT})`) + await sleep(1 * 1000) } } diff --git a/src/shared/get_metagraph_info.js b/src/shared/get_metagraph_info.js index 131ccba..4ca2188 100644 --- a/src/shared/get_metagraph_info.js +++ b/src/shared/get_metagraph_info.js @@ -70,8 +70,8 @@ const _getUnhealthyNodes = async (clusterInfo) => { break } - console.log(`Could not get node information at: ${node.ip}. Trying again in 5s (${idx + 1}/${CHECK_NODE_HEALTHY_LIMIT})`) - await sleep(5 * 1000) + console.log(`Could not get node information at: ${node.ip}. Trying again in 1s (${idx + 1}/${CHECK_NODE_HEALTHY_LIMIT})`) + await sleep(1 * 1000) } } } @@ -175,8 +175,8 @@ const getInformationToJoinNode = async (event, layer) => { if (idx === 59) { throw Error(`Could not get information of node in URL: ${urls[layer]}`) } - console.log(`Node ${url} is possibly not READY yet, waiting for 10s to try again (${idx + 1}/60)`) - await sleep(10 * 1000) + console.log(`Node ${url} is possibly not READY yet, waiting for 1s to try again (${idx + 1}/60)`) + await sleep(1 * 1000) } } } diff --git a/src/shared/restart_operations.js b/src/shared/restart_operations.js index 38e31e7..e262e4f 100644 --- a/src/shared/restart_operations.js +++ b/src/shared/restart_operations.js @@ -2,50 +2,6 @@ import moment from 'moment' import { LAYERS, NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE } from '../utils/types.js' import { sendCommand } from '../external/aws/ssm.js' import { sleep } from './shared.js' -import { getLastMetagraphInfo } from './get_metagraph_info.js' - -const _movingSnapshotsNotSyncToGL0 = async (ssmClient, event, ec2InstancesIds) => { - const { file_system } = event.metagraph - const { lastSnapshotOrdinal } = await getLastMetagraphInfo(event) - const initialSnapshotToRemove = lastSnapshotOrdinal - const finalSnapshotToRemove = initialSnapshotToRemove + NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE - - console.log(`Creating the mv_snapshot.sh script under metagraph-l0 directory`) - const bkpDirectoryName = `incremental_snapshot_bkp_${moment.utc().format('YYYY_MM_DD_HH_mm_ss')}` - const creatingCommands = [ - `cd ${file_system.base_metagraph_l0_directory}`, - `mkdir -p data/${bkpDirectoryName}`, - - `echo "# Set the source and target directories - source_dir="data/incremental_snapshot" - target_dir="data/${bkpDirectoryName}/" - # Use find to locate the files within the specified range - for i in \\$(seq \\$1 \\$2); do - source_file="\\$source_dir/\\$i" - - # Check if the source file exists before attempting to move it - if [ -e "\\$source_file" ]; then - echo "Processing file with ID \\$source_file" - find \\$source_dir -mount -samefile \\$source_file -exec mv {} "\\$target_dir" \\; - else - echo "File \\$source_file does not exist." - fi - done" > mv_snapshots.sh`, - - `sudo chmod +x mv_snapshots.sh`, - ] - await sendCommand(ssmClient, creatingCommands, ec2InstancesIds) - console.log(`Finished creating mv_snapshot.sh script`) - - console.log(`Moving incremental snapshots on data/incremental_snapshot to data/${bkpDirectoryName} between: ${initialSnapshotToRemove} - ${finalSnapshotToRemove}`) - const commands = [ - `cd ${file_system.base_metagraph_l0_directory}`, - `./mv_snapshots.sh ${initialSnapshotToRemove} ${finalSnapshotToRemove}` - ] - - await sendCommand(ssmClient, commands, ec2InstancesIds) - console.log(`Finishing moving the snapshots`) -} const killCurrentExecution = async (ssmClient, event, layer, ec2InstancesIds) => { const { @@ -59,7 +15,6 @@ const killCurrentExecution = async (ssmClient, event, layer, ec2InstancesIds) => if (layer === LAYERS.L0) { const commands = [`fuser -k ${metagraph_l0_public_port}/tcp`] await sendCommand(ssmClient, commands, ec2InstancesIds) - await _movingSnapshotsNotSyncToGL0(ssmClient, event, ec2InstancesIds) return } @@ -110,9 +65,6 @@ const saveLogs = async (ssmClient, event, logName, layer, ec2InstancesIds) => { ] await sendCommand(ssmClient, commands, ec2InstancesIds) - - console.log('Waiting 10s to finish the compression...') - await sleep(10 * 1000) } const getLogsNames = () => { diff --git a/src/utils/types.js b/src/utils/types.js index ce59422..d6b9cf1 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -34,11 +34,12 @@ const DYNAMO_RESTART_STATE = { NEW: 'NEW', ROLLBACK_IN_PROGRESS: 'ROLLBACK IN PROGRESS', READY_TO_JOIN: 'READY TO JOIN', + JOINING: 'JOINING', READY: 'READY' } const DYNAMO_DB_TABLE_AUTO_RESTART = 'auto_restart' -const CHECK_NODE_HEALTHY_LIMIT = 5 +const CHECK_NODE_HEALTHY_LIMIT = 50 const OPSGENIE_API_KEY_PATH = '/metagraph-nodes/opsgenie-api-key' From d1fe755c276e6b902de3877ce7595a67fbbfb5ba Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Wed, 13 Dec 2023 16:01:49 -0300 Subject: [PATCH 27/30] Reducing timeout to 60 minutes --- src/utils/types.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/types.js b/src/utils/types.js index d6b9cf1..a664d8b 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -43,7 +43,7 @@ const CHECK_NODE_HEALTHY_LIMIT = 50 const OPSGENIE_API_KEY_PATH = '/metagraph-nodes/opsgenie-api-key' -const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 600 +const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 60 const NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE = 100 From adeb62dda112b09b690dc4bd8092be801d9c507b Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Fri, 12 Jan 2024 12:19:20 -0300 Subject: [PATCH 28/30] Updating monitoring to support seedlists --- README.md | 7 +- event.json | 60 +-------------- index.js | 42 ++++++----- .../currency-example-integrationnet.json | 57 ++++++++++++++ .../dor-metagraph-integrationnet.json | 75 +++++++++++++++++++ .../dor-metagraph-mainnet.json | 75 +++++++++++++++++++ .../dor-metagraph-testnet.json | 75 +++++++++++++++++++ src/currency-l1/index.js | 17 ++++- src/data-l1/index.js | 17 ++++- src/metagraph-l0/index.js | 17 ++++- src/utils/build_seedlist_url.js | 40 ++++++++++ src/utils/types.js | 14 +++- 12 files changed, 406 insertions(+), 90 deletions(-) create mode 100644 metagraphs-events-payloads/currency-example-integrationnet.json create mode 100644 metagraphs-events-payloads/dor-metagraph-integrationnet.json create mode 100644 metagraphs-events-payloads/dor-metagraph-mainnet.json create mode 100644 metagraphs-events-payloads/dor-metagraph-testnet.json create mode 100644 src/utils/build_seedlist_url.js diff --git a/README.md b/README.md index 07cc8e7..5a8911b 100644 --- a/README.md +++ b/README.md @@ -70,4 +70,9 @@ We need to create variables in the SSM Parameter Store, following this pattern: You should repeat the above parameters for your 3 instances. Additionally, there is a parameter in the SSM Parameter Store for Opsgenie integration, so you need to create the following parameter: -`/metagraph-nodes/opsgenie-api-key` \ No newline at end of file +`/metagraph-nodes/opsgenie-api-key` + +## Metagraphs Events Payloads +- Locate the events corresponding to the current metagraphs supported by this monitoring tool in metagraphs-events-payload. +- Keeping these files up-to-date is crucial. +- Ensure that the content of these files is transmitted through AWS EventBridge. \ No newline at end of file diff --git a/event.json b/event.json index a1a5cab..9e26dfe 100644 --- a/event.json +++ b/event.json @@ -1,59 +1 @@ -{ - "metagraph": { - "id": "DAG0CyySf35ftDQDQBnd1bdQ9aPyUdacMghpnCuM", - "name": "DOR", - "include_currency_l1_layer": true, - "include_data_l1_layer": true, - "file_system": { - "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", - "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", - "base_data_l1_directory": "/home/ubuntu/code/data-l1" - }, - "ports": { - "metagraph_l0_public_port": 7000, - "metagraph_l0_p2p_port": 7001, - "metagraph_l0_cli_port": 7002, - "currency_l1_public_port": 8000, - "currency_l1_p2p_port": 8001, - "currency_l1_cli_port": 8002, - "data_l1_public_port": 9000, - "data_l1_p2p_port": 9001, - "data_l1_cli_port": 9002 - }, - "required_env_variables": { - "cl_app_env": "mainnet", - "cl_collateral": 0 - }, - "additional_metagraph_l0_env_variables": [ - "METAGRAPH_L0_NODE_URL=http://54.191.143.191:7000/cluster/info", - "DATA_L1_NODE_URL=http://54.191.143.191:9000/cluster/info" - ], - "additional_currency_l1_env_variables": [], - "additional_data_l1_env_variables": [] - }, - "network": { - "name": "mainnet" - }, - "aws": { - "region": "us-west-2", - "ec2": { - "instances": { - "genesis": { - "id": "i-02cd28287c031457d", - "ip": "54.191.143.191" - }, - "validators": [ - { - "id": "i-023598d60862a9575", - "ip": "54.213.58.75" - }, - { - "id": "i-0a29153b8b04ab7c1", - "ip": "34.211.239.153" - } - ] - } - } - }, - "force_metagraph_restart": false -} \ No newline at end of file +{} \ No newline at end of file diff --git a/index.js b/index.js index 6a5d6a4..0995743 100644 --- a/index.js +++ b/index.js @@ -132,31 +132,33 @@ export const handler = async (event) => { const referenceSourceNode = await getReferenceSourceNodeFromNetwork(event) const metagraphId = event.metagraph.id - const currentMetagraphRestart = await getMetagraphRestartOrCreateNew(metagraphId) - const restartProgress = await getMetagraphRestartProgress( - ssmClient, - event, - currentMetagraphRestart, - referenceSourceNode - ) - - if (restartProgress.restartState !== DYNAMO_RESTART_STATE.NEW) { - return { - statusCode: 200, - body: restartProgress.body, + if (!event.force_metagraph_restart) { + const currentMetagraphRestart = await getMetagraphRestartOrCreateNew(metagraphId) + const restartProgress = await getMetagraphRestartProgress( + ssmClient, + event, + currentMetagraphRestart, + referenceSourceNode + ) + + if (restartProgress.restartState !== DYNAMO_RESTART_STATE.NEW) { + return { + statusCode: 200, + body: restartProgress.body, + } } - } - if (restartProgress.restartState === DYNAMO_RESTART_STATE.READY) { - await validateIfAllNodesAreReady(event) - await checkIfNewSnapshotsAreProducedAfterRestart(event) + if (restartProgress.restartState === DYNAMO_RESTART_STATE.READY) { + await validateIfAllNodesAreReady(event) + await checkIfNewSnapshotsAreProducedAfterRestart(event) - return { - statusCode: 200, - body: JSON.stringify('Metagraph healthy, after restart'), + return { + statusCode: 200, + body: JSON.stringify('Metagraph healthy, after restart'), + } } } - + try { const { lastSnapshotTimestamp } = await getLastMetagraphInfo(event) const metagraphRestartType = await getMetagraphRestartType(event, lastSnapshotTimestamp) diff --git a/metagraphs-events-payloads/currency-example-integrationnet.json b/metagraphs-events-payloads/currency-example-integrationnet.json new file mode 100644 index 0000000..c77a1a6 --- /dev/null +++ b/metagraphs-events-payloads/currency-example-integrationnet.json @@ -0,0 +1,57 @@ +{ + "metagraph": { + "id": "DAG4dWrdALPQmvF5UBpuXrqdkMHea1H5f7rjb4qY", + "name": "Biforex", + "include_currency_l1_layer": true, + "include_data_l1_layer": false, + "file_system": { + "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", + "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", + "base_data_l1_directory": "/home/ubuntu/code/data-l1" + }, + "ports": { + "metagraph_l0_public_port": 7000, + "metagraph_l0_p2p_port": 7001, + "metagraph_l0_cli_port": 7002, + "currency_l1_public_port": 8000, + "currency_l1_p2p_port": 8001, + "currency_l1_cli_port": 8002, + "data_l1_public_port": 9000, + "data_l1_p2p_port": 9001, + "data_l1_cli_port": 9002 + }, + "required_env_variables": { + "cl_app_env": "integrationnet", + "cl_collateral": 0 + }, + "additional_metagraph_l0_env_variables": [], + "additional_currency_l1_env_variables": [], + "additional_data_l1_env_variables": [], + "seedlists": {} + }, + "network": { + "name": "integrationnet" + }, + "aws": { + "region": "us-west-1", + "ec2": { + "instances": { + "genesis": { + "id": "i-00e6ff6893a3fcba5", + "ip": "18.144.39.83" + }, + "validators": [ + { + "id": "i-089c6076393c9445a", + "ip": "13.56.11.204" + }, + { + "id": "i-09483e068ef6664a7", + "ip": "13.56.224.220" + } + ] + } + } + }, + "force_metagraph_restart": false +} \ No newline at end of file diff --git a/metagraphs-events-payloads/dor-metagraph-integrationnet.json b/metagraphs-events-payloads/dor-metagraph-integrationnet.json new file mode 100644 index 0000000..3eccb5a --- /dev/null +++ b/metagraphs-events-payloads/dor-metagraph-integrationnet.json @@ -0,0 +1,75 @@ +{ + "metagraph": { + "id": "DAG5kfY9GoHF1CYaY8tuRJxmB3JSzAEARJEAkA2C", + "name": "DOR", + "version": "v1.0.1", + "include_currency_l1_layer": true, + "include_data_l1_layer": true, + "file_system": { + "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", + "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", + "base_data_l1_directory": "/home/ubuntu/code/data-l1" + }, + "ports": { + "metagraph_l0_public_port": 7000, + "metagraph_l0_p2p_port": 7001, + "metagraph_l0_cli_port": 7002, + "currency_l1_public_port": 8000, + "currency_l1_p2p_port": 8001, + "currency_l1_cli_port": 8002, + "data_l1_public_port": 9000, + "data_l1_p2p_port": 9001, + "data_l1_cli_port": 9002 + }, + "required_env_variables": { + "cl_app_env": "integrationnet", + "cl_collateral": 0 + }, + "additional_metagraph_l0_env_variables": [ + "METAGRAPH_L0_NODE_URL=http://54.218.46.24:7000/cluster/info", + "DATA_L1_NODE_URL=http://54.218.46.24:9000/cluster/info" + ], + "additional_currency_l1_env_variables": [], + "additional_data_l1_env_variables": [], + "seedlists": { + "location": "Github", + "ml0": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "ml0-integrationnet-seedlist" + }, + "cl1": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "cl1-integrationnet-seedlist" + }, + "dl1": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "dl1-integrationnet-seedlist" + } + } + }, + "network": { + "name": "integrationnet" + }, + "aws": { + "region": "us-west-2", + "ec2": { + "instances": { + "genesis": { + "id": "i-03b3276264675e661", + "ip": "54.218.46.24" + }, + "validators": [ + { + "id": "i-074aabc2ebd03819b", + "ip": "34.212.237.118" + }, + { + "id": "i-0cc80924a8124f3e6", + "ip": "34.219.123.201" + } + ] + } + } + }, + "force_metagraph_restart": false +} \ No newline at end of file diff --git a/metagraphs-events-payloads/dor-metagraph-mainnet.json b/metagraphs-events-payloads/dor-metagraph-mainnet.json new file mode 100644 index 0000000..114dc99 --- /dev/null +++ b/metagraphs-events-payloads/dor-metagraph-mainnet.json @@ -0,0 +1,75 @@ +{ + "metagraph": { + "id": "DAG0CyySf35ftDQDQBnd1bdQ9aPyUdacMghpnCuM", + "name": "DOR", + "version": "v1.0.1", + "include_currency_l1_layer": true, + "include_data_l1_layer": true, + "file_system": { + "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", + "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", + "base_data_l1_directory": "/home/ubuntu/code/data-l1" + }, + "ports": { + "metagraph_l0_public_port": 7000, + "metagraph_l0_p2p_port": 7001, + "metagraph_l0_cli_port": 7002, + "currency_l1_public_port": 8000, + "currency_l1_p2p_port": 8001, + "currency_l1_cli_port": 8002, + "data_l1_public_port": 9000, + "data_l1_p2p_port": 9001, + "data_l1_cli_port": 9002 + }, + "required_env_variables": { + "cl_app_env": "mainnet", + "cl_collateral": 0 + }, + "additional_metagraph_l0_env_variables": [ + "METAGRAPH_L0_NODE_URL=http://54.191.143.191:7000/cluster/info", + "DATA_L1_NODE_URL=http://54.191.143.191:9000/cluster/info" + ], + "additional_currency_l1_env_variables": [], + "additional_data_l1_env_variables": [], + "seedlists": { + "location": "Github", + "ml0": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "ml0-mainnet-seedlist" + }, + "cl1": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "cl1-mainnet-seedlist" + }, + "dl1": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "dl1-mainnet-seedlist" + } + } + }, + "network": { + "name": "mainnet" + }, + "aws": { + "region": "us-west-2", + "ec2": { + "instances": { + "genesis": { + "id": "i-02cd28287c031457d", + "ip": "54.191.143.191" + }, + "validators": [ + { + "id": "i-023598d60862a9575", + "ip": "54.213.58.75" + }, + { + "id": "i-0a29153b8b04ab7c1", + "ip": "34.211.239.153" + } + ] + } + } + }, + "force_metagraph_restart": false +} \ No newline at end of file diff --git a/metagraphs-events-payloads/dor-metagraph-testnet.json b/metagraphs-events-payloads/dor-metagraph-testnet.json new file mode 100644 index 0000000..10f8f20 --- /dev/null +++ b/metagraphs-events-payloads/dor-metagraph-testnet.json @@ -0,0 +1,75 @@ +{ + "metagraph": { + "id": "DAG8gMagrwoJ4nAMjbGx17WB5D6nqBEPZYChc3zH", + "name": "DOR", + "version": "v1.0.1", + "include_currency_l1_layer": true, + "include_data_l1_layer": true, + "file_system": { + "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", + "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", + "base_data_l1_directory": "/home/ubuntu/code/data-l1" + }, + "ports": { + "metagraph_l0_public_port": 7000, + "metagraph_l0_p2p_port": 7001, + "metagraph_l0_cli_port": 7002, + "currency_l1_public_port": 8000, + "currency_l1_p2p_port": 8001, + "currency_l1_cli_port": 8002, + "data_l1_public_port": 9000, + "data_l1_p2p_port": 9001, + "data_l1_cli_port": 9002 + }, + "required_env_variables": { + "cl_app_env": "testnet", + "cl_collateral": 0 + }, + "additional_metagraph_l0_env_variables": [ + "METAGRAPH_L0_NODE_URL=http://34.212.38.215:7000/cluster/info", + "DATA_L1_NODE_URL=http://34.212.38.215:9000/cluster/info" + ], + "additional_currency_l1_env_variables": [], + "additional_data_l1_env_variables": [], + "seedlists": { + "location": "Github", + "ml0": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "ml0-testnet-seedlist" + }, + "cl1": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "cl1-testnet-seedlist" + }, + "dl1": { + "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", + "file_name": "dl1-testnet-seedlist" + } + } + }, + "network": { + "name": "testnet" + }, + "aws": { + "region": "us-west-2", + "ec2": { + "instances": { + "genesis": { + "id": "i-03f1a976ec6843de1", + "ip": "34.212.38.215" + }, + "validators": [ + { + "id": "i-08ad464855b91963a", + "ip": "34.219.97.95" + }, + { + "id": "i-056d3ced123b2b3ee", + "ip": "35.90.118.112" + } + ] + } + } + }, + "force_metagraph_restart": false +} \ No newline at end of file diff --git a/src/currency-l1/index.js b/src/currency-l1/index.js index e22f604..50a1f86 100644 --- a/src/currency-l1/index.js +++ b/src/currency-l1/index.js @@ -1,6 +1,7 @@ import { getKeys, sendCommand } from '../external/aws/ssm.js' import { saveLogs, killCurrentExecution } from '../shared/index.js' -import { KEY_LAYERS, LAYERS } from '../utils/types.js' +import { buildSeedlistInformation } from '../utils/build_seedlist_url.js' +import { KEY_LAYERS, LAYERS, SEEDLIST_LAYERS } from '../utils/types.js' const startInitialValidatorNodeCurrencyL1 = async (ssmClient, event, logName, mL0NodeId, rollbackNode, referenceSourceNode, shouldKillCurrentExecution = true) => { if (shouldKillCurrentExecution) { @@ -44,10 +45,15 @@ const startInitialValidatorNodeCurrencyL1 = async (ssmClient, event, logName, mL envVariables.push(`export ${variable}`) } + const { url, file_name } = buildSeedlistInformation(event, SEEDLIST_LAYERS.CL1) const commands = [ ...envVariables, `cd ${file_system.base_currency_l1_directory}`, - `nohup java -jar currency-l1.jar run-initial-validator --ip ${rollbackNode.ip} > node-l1.log 2>&1 &` + `${url ? `wget -O ${file_name} ${url}` : ''}`, + `${url ? + `nohup java -jar currency-l1.jar run-initial-validator --ip ${rollbackNode.ip} --seedlist ${file_name} > node-l1.log 2>&1 &` : + `nohup java -jar currency-l1.jar run-initial-validator --ip ${rollbackNode.ip} > node-l1.log 2>&1 &` + }` ] await sendCommand(ssmClient, commands, [rollbackNode.id]) @@ -95,10 +101,15 @@ const startValidatorNodeCurrencyL1 = async (ssmClient, event, logName, mL0NodeId envVariables.push(`export ${variable}`) } + const { url, file_name } = buildSeedlistInformation(event, SEEDLIST_LAYERS.CL1) const commands = [ ...envVariables, `cd ${file_system.base_currency_l1_directory}`, - `nohup java -jar currency-l1.jar run-validator --ip ${validator.ip} > node-l1.log 2>&1 &` + `${url ? `wget -O ${file_name} ${url}` : ''}`, + `${url ? + `nohup java -jar currency-l1.jar run-validator --ip ${validator.ip} --seedlist ${file_name} > node-l1.log 2>&1 &` : + `nohup java -jar currency-l1.jar run-validator --ip ${validator.ip} > node-l1.log 2>&1 &` + }` ] await sendCommand(ssmClient, commands, [validator.id]) diff --git a/src/data-l1/index.js b/src/data-l1/index.js index 1418c82..0d20757 100644 --- a/src/data-l1/index.js +++ b/src/data-l1/index.js @@ -1,6 +1,7 @@ import { getKeys, sendCommand } from '../external/aws/ssm.js' import { saveLogs, killCurrentExecution } from '../shared/index.js' -import { KEY_LAYERS, LAYERS } from '../utils/types.js' +import { buildSeedlistInformation } from '../utils/build_seedlist_url.js' +import { KEY_LAYERS, LAYERS, SEEDLIST_LAYERS } from '../utils/types.js' const startInitialValidatorNodeDataL1 = async (ssmClient, event, logName, mL0NodeId, rollbackNode, referenceSourceNode, shouldKillCurrentExecution = true) => { if (shouldKillCurrentExecution) { @@ -44,10 +45,15 @@ const startInitialValidatorNodeDataL1 = async (ssmClient, event, logName, mL0Nod envVariables.push(`export ${variable}`) } + const { url, file_name } = buildSeedlistInformation(event, SEEDLIST_LAYERS.DL1) const commands = [ ...envVariables, `cd ${file_system.base_data_l1_directory}`, - `nohup java -jar data-l1.jar run-initial-validator --ip ${rollbackNode.ip} > node-l1.log 2>&1 &` + `${url ? `wget -O ${file_name} ${url}` : ''}`, + `${url ? + `nohup java -jar data-l1.jar run-initial-validator --ip ${rollbackNode.ip} --seedlist ${file_name} > node-l1.log 2>&1 &` : + `nohup java -jar data-l1.jar run-initial-validator --ip ${rollbackNode.ip} > node-l1.log 2>&1 &` + }` ] await sendCommand(ssmClient, commands, [rollbackNode.id]) @@ -95,10 +101,15 @@ const startValidatorNodeDataL1 = async (ssmClient, event, logName, mL0NodeId, va envVariables.push(`export ${variable}`) } + const { url, file_name } = buildSeedlistInformation(event, SEEDLIST_LAYERS.DL1) const commands = [ ...envVariables, `cd ${file_system.base_data_l1_directory}`, - `nohup java -jar data-l1.jar run-validator --ip ${validator.ip} > node-l1.log 2>&1 &` + `${url ? `wget -O ${file_name} ${url}` : ''}`, + `${url ? + `nohup java -jar data-l1.jar run-validator --ip ${validator.ip} --seedlist ${file_name} > node-l1.log 2>&1 &` : + `nohup java -jar data-l1.jar run-validator --ip ${validator.ip} > node-l1.log 2>&1 &` + }` ] await sendCommand(ssmClient, commands, [validator.id]) diff --git a/src/metagraph-l0/index.js b/src/metagraph-l0/index.js index 5640b1d..4a31b85 100644 --- a/src/metagraph-l0/index.js +++ b/src/metagraph-l0/index.js @@ -1,6 +1,7 @@ import { getKeys, sendCommand } from '../external/aws/ssm.js' import { saveLogs, killCurrentExecution } from '../shared/index.js' -import { KEY_LAYERS, LAYERS } from '../utils/types.js' +import { buildSeedlistInformation } from '../utils/build_seedlist_url.js' +import { KEY_LAYERS, LAYERS, SEEDLIST_LAYERS } from '../utils/types.js' const startRollbackNodeL0 = async (ssmClient, event, rollbackNode, referenceSourceNode, logName, shouldKillCurrentExecution = true) => { if (shouldKillCurrentExecution) { @@ -40,10 +41,15 @@ const startRollbackNodeL0 = async (ssmClient, event, rollbackNode, referenceSour envVariables.push(`export ${variable}`) } + const { url, file_name } = buildSeedlistInformation(event, SEEDLIST_LAYERS.ML0) const commands = [ ...envVariables, `cd ${file_system.base_metagraph_l0_directory}`, - `nohup java -jar metagraph-l0.jar run-rollback --ip ${event.aws.ec2.instances.genesis.ip} > node-l0.log 2>&1 &` + `${url ? `wget -O ${file_name} ${url}` : ''}`, + `${url ? + `nohup java -jar metagraph-l0.jar run-rollback --ip ${event.aws.ec2.instances.genesis.ip} --seedlist ${file_name} > node-l0.log 2>&1 &` : + `nohup java -jar metagraph-l0.jar run-rollback --ip ${event.aws.ec2.instances.genesis.ip} > node-l0.log 2>&1 &` + }` ] await sendCommand(ssmClient, commands, [rollbackNode.id]) @@ -84,10 +90,15 @@ const startValidatorNodeL0 = async (ssmClient, event, logName, validator, refere envVariables.push(`export ${variable}`) } + const { url, file_name } = buildSeedlistInformation(event, SEEDLIST_LAYERS.ML0) const commands = [ ...envVariables, `cd ${file_system.base_metagraph_l0_directory}`, - `nohup java -jar metagraph-l0.jar run-validator --ip ${validator.ip} > node-l0.log 2>&1 &` + `${url ? `wget -O ${file_name} ${url}` : ''}`, + `${url ? + `nohup java -jar metagraph-l0.jar run-validator --ip ${validator.ip} --seedlist ${file_name} > node-l0.log 2>&1 &` : + `nohup java -jar metagraph-l0.jar run-validator --ip ${validator.ip} > node-l0.log 2>&1 &` + }` ] await sendCommand(ssmClient, commands, [validator.id]) diff --git a/src/utils/build_seedlist_url.js b/src/utils/build_seedlist_url.js new file mode 100644 index 0000000..bb8a450 --- /dev/null +++ b/src/utils/build_seedlist_url.js @@ -0,0 +1,40 @@ +import { SEEDLIST_EXTERNAL_STORAGE } from "./types.js" + +const buildGithubSeedlistInformation = (metagraph, layer) => { + const seedlistInformation = metagraph.seedlists[layer] + if (!seedlistInformation || Object.keys(seedlistInformation).length === 0) { + throw Error(`Could not get information of seedlist at layer ${layer}`) + } + + const { version } = metagraph + const { base_url, file_name } = seedlistInformation + + const seedlistUrl = `${base_url}/${version}/${file_name}` + console.log(`Seedlist URL for layer ${layer}: ${seedlistUrl}`) + + return { + url: seedlistUrl, + file_name + } +} + +const buildSeedlistInformation = (event, layer) => { + const { metagraph } = event + if (Object.keys(metagraph.seedlists).length === 0) { + console.log(`Seedlists not set for metagraph ${metagraph.name}`) + return { + url: null, + file_name: null + } + } + + if (metagraph.seedlists.location === SEEDLIST_EXTERNAL_STORAGE.GITHUB) { + return buildGithubSeedlistInformation(metagraph, layer) + } + + throw Error("Invalid seedlist location type") +} + +export { + buildSeedlistInformation +} \ No newline at end of file diff --git a/src/utils/types.js b/src/utils/types.js index a664d8b..d742e6a 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -10,6 +10,12 @@ const KEY_LAYERS = { DATA_L1: 'dl1' } +const SEEDLIST_LAYERS = { + ML0: 'ml0', + CL1: 'cl1', + DL1: 'dl1' +} + const VALID_NETWORKS_TAGS_OPSGENIE = { mainnet: 'env:MainNet', integrationnet: 'env:IntegrationNet', @@ -101,9 +107,14 @@ const NETWORK_NODES = { } } +const SEEDLIST_EXTERNAL_STORAGE = { + GITHUB: 'Github' +} + export { LAYERS, KEY_LAYERS, + SEEDLIST_LAYERS, VALID_NETWORKS_TAGS_OPSGENIE, DATE_FORMAT, RESTART_REASONS, @@ -114,5 +125,6 @@ export { NETWORK_NODES, OPSGENIE_API_KEY_PATH, ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES, - NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE + NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE, + SEEDLIST_EXTERNAL_STORAGE } \ No newline at end of file From af73375506bb1827f43a891d118b9d7f9ea3adfc Mon Sep 17 00:00:00 2001 From: Marcus Girolneto Date: Fri, 19 Jan 2024 18:04:46 -0300 Subject: [PATCH 29/30] Updating repository --- README.md | 171 ++++++++++++------ event.json | 74 +++++++- .../currency-example-integrationnet.json | 57 ------ .../dor-metagraph-integrationnet.json | 75 -------- .../dor-metagraph-mainnet.json | 75 -------- .../dor-metagraph-testnet.json | 75 -------- src/external/opsgenie/index.js | 51 ++++-- src/shared/restart_operations.js | 3 +- src/utils/types.js | 3 - 9 files changed, 226 insertions(+), 358 deletions(-) delete mode 100644 metagraphs-events-payloads/currency-example-integrationnet.json delete mode 100644 metagraphs-events-payloads/dor-metagraph-integrationnet.json delete mode 100644 metagraphs-events-payloads/dor-metagraph-mainnet.json delete mode 100644 metagraphs-events-payloads/dor-metagraph-testnet.json diff --git a/README.md b/README.md index 5a8911b..9434df1 100644 --- a/README.md +++ b/README.md @@ -1,78 +1,147 @@ - -Network Monitoring Tools +Metagraph Monitoring Tools ======================== -This project has been developed for monitoring metagraphs and initiating a restart if necessary. +This project has been developed to monitor metagraphs and initiate a restart if necessary. We have a Lambda function dedicated to monitoring a metagraph. This monitoring can trigger two types of restarts: **FULL_CLUSTER** or **INDIVIDUAL_NODES**. -We have a lambda function dedicated to monitoring a metagraph and restarting it if the snapshot production stops. It can be enhanced to handle other scenarios requiring a restart. +### Full Cluster Restart -To run the lambda function, you should provide the parameters described in `event.json`. Some parameters are mandatory and need to be populated as SSM Parameters in the Parameter Store. +This restart will involve restarting all the nodes and layers. In other words, it will completely restart the metagraph (3ml0, 3cl1, and 3dl1). We always aim to avoid a complete restart of the metagraph, but there are certain conditions that can trigger this type of restart, such as: + +- Snapshots no longer being produced. +- Snapshots not reaching the global networks (MainNet, IntegrationNet). +- All nodes from layer 0 down (which would cause the snapshots to stop being created). +- All nodes from all layers down. + +### Individual Nodes Restart + +This restart will involve restarting nodes individually. This means that we won't need to restart the full cluster but only specific nodes in certain layers. For example, if node 2 in layer cl1 is down, we can restart only the process of node 2 in layer cl1 instead of the entire cluster or node. The conditions that can trigger this type of restart are: + +- Unhealthy node in layer ml0 +- Unhealthy node in layer cl1 +- Unhealthy node in layer dl1 + +## Guide + +We are using **Node.js 16** to package this Lambda function. You can manage Node.js versions using [nvm](https://github.com/nvm-sh/nvm). -Please remember to create a new role for the lambda function, which should include the following policies: AmazonEventBridgeFullAccess, AWSLambda_FullAccess, AWSLambdaBasicExecutionRole. Additionally, we need to create a custom policy with the following permissions: +For local execution, we are utilizing the [node-lambda](https://www.npmjs.com/package/node-lambda) library. To run it locally, install node-lambda by executing the following command: +`npm install -g node-lambda` + +**This repository was made to run using AWS Cloud.** + +On AWS we will need to use some services: + +- IAM (Policies) +- Lambda +- Event Bridge +- Systems Manager +- Dynamo +- Cloud Watch + +### IAM +When creating a Lambda function, a corresponding role must be provided. This Lambda function will require access to other services such as DynamoDB and Systems Manager (SSM). To establish this role, access to AWS Identity and Access Management (IAM) is required. + +The initial step involves creating a new policy on AWS, named `MetagraphMonitor`. This policy should include the following JSON configuration: ``` { - "Version": "2012-10-17", - "Statement": [ - { - "Sid": "VisualEditor0", - "Effect": "Allow", - "Action": [ - "ssm:SendCommand", - "ssm:CreateAssociation", - "ssm:GetParameter" - ], - "Resource": "*" - } - ] + "Version": "2012-10-17", + "Statement": [ + { + "Sid": "VisualEditor0", + "Effect": "Allow", + "Action": [ + "ssm:SendCommand", + "ssm:CreateAssociation", + "ssm:GetParameter" + ], + "Resource": "*" + } + ] } ``` -We also access instances using SSM, so ensure that your instances have the SSM client set up. +Upon policy creation, the subsequent step is to establish the role. This role should also be named `MetagraphMonitor`. Attach the following policies to this role: -To deploy the function, simply package the changes using `zip -r my_deployment_package.zip .` and then deploy the ZIP file to your function. +1. MetagraphMonitor (previously created) +2. AmazonDynamoDBFullAccess (AWS default policy) +3. AmazonEventBridgeFullAccess (AWS default policy) +4. AWSLambdaBasicExecutionRole (AWS default policy) -Dependencies ------------- +These policies ensure access to the required services. -This project is designed to run as a lambda function and monitor EC2 instances. Therefore, we require the following: +### Lambda +This codebase represents a Lambda function designed for deployment on AWS. To deploy the Lambda function, execute the following script: +`npm run package` -- 3 EC2 instances with an authorized SSM agent and zip installed (use `sudo apt install zip` to install zip for compressing logs). +Running this command will generate a file named `my_deployment_package.zip`. Upload this file to your Lambda function on AWS. -Inside each instance, we should follow a specific directory structure. To run this lambda function, your instance should contain the following files: +To run the lambda function, you should provide the parameters described in `event.json`. Some parameters are mandatory and need to be populated as SSM Parameters in the Parameter Store. -- `your_metagraph_l0_directory` +Ensure that you set the Lambda concurrency to only `1` and the timeout to `15 minutes`. - - `genesis.csv` - - `metagraph-l0.jar` -- `your_currency_l1_directory` +### Event Bridge +This service is responsible for scheduling the Lambda function to be triggered. Currently, we recommend creating a schedule to run every 5 minutes to check the health of the metagraph. The service should provide the Lambda payload, which includes information about **metagraph**, **network**, **aws**, **force_metagraph_restart**, and **enable_opsgenie_alerts**. - - `currency-l1.jar` -- `your_data_l1_directory` +- **metagraph**: This section contains information about the metagraph, such as metagraphID, metagraphName, layers to be monitored besides ml0, ports, file_system, additional environment variables, required environment variables, and seed lists (if necessary). +- **network**: This section contains information about the network on which the metagraph will run. It could be Integrationnet or Mainnet. +- **aws**: This section includes information about the AWS region where we are running our instances and details about the instances, such as **ids** and **ips**. +- **force_metagraph_restart**: This will initiate a restart, even if one is already in progress. Further details about restarts in progress will be discussed in the **Dynamo** section. +- **enable_opsgenie_alerts**: Additionally, we offer support for creating alerts on Opsgenie. Set this to `true` if you want to enable this integration. + +The template for this payload can be found in the file `event.json` in the root directory of this repository. +**Ensure that you fill in this payload correctly, as it is crucial for the proper execution of the Lambda function.** - - `data-l1.jar` +### Systems Manager -We need to create variables in the SSM Parameter Store, following this pattern: +This service plays a crucial role in two key aspects of our monitoring system: enabling commands to be sent to instances (without the need for `ssh`) and securely storing the sensitive parameters required for the proper execution of the Lambda function. -``` -/metagraph-nodes/:ec2_instance_id/l0/keystore -/metagraph-nodes/:ec2_instance_id/l0/keyalias -/metagraph-nodes/:ec2_instance_id/l0/password +It is imperative to ensure SSM access is enabled for your EC2 instances running the metagraph. Refer to the official documentation on how to enable SSM on EC2 instances [here](https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-install-ssm-agent.html). + **This is critically important; without SSM on EC2 instances, the script will not function, as we rely on it to send instructions to the instances.** -/metagraph-nodes/:ec2_instance_id/cl1/keystore -/metagraph-nodes/:ec2_instance_id/cl1/keyalias -/metagraph-nodes/:ec2_instance_id/cl1/password +Additionally, we rely on Systems Manager to store sensitive parameters, such as `p12` key information for the metagraph. These parameters are stored in the `Systems Manager -> Parameters Store` with the following pattern: -/metagraph-nodes/:ec2_instance_id/dl1/keystore -/metagraph-nodes/:ec2_instance_id/dl1/keyalias -/metagraph-nodes/:ec2_instance_id/dl1/password -``` +- `/metagraph-nodes/{instance_id}/{layer}/keyalias` +- `/metagraph-nodes/{instance_id}/{layer}/keystore` +- `/metagraph-nodes/{instance_id}/{layer}/password` + +The layers include: `l0`, `cl1`, and `dl1`. +The instance IDs correspond to the IDs from **EC2**. +Considering we have **3 instances** and **3 layers**, we should have a total of **9 parameters** for each instance (3 for ml0, 3 for cl1, and 3 for dl1). Therefore, **27 parameters** in total should be stored in the end. + +**Note: The example above assumes all 3 layers; this value may vary based on the number of instances.** + +As mentioned earlier, we support **Opsgenie** integration. However, to enable this integration, you need the **Opsgenie API-KEY**. Therefore, an additional parameter is required for this integration: + +- `/metagraph-nodes/opsgenie-api-key` + +**Note: The integration will not work if you enable Opsgenie integration in the payload but forget to provide the API-KEY.** + +### Dynamo + +To prevent multiple restarts in parallel, we utilize **Dynamo** to store the restart state. Currently, the possible states for restarts are: `NEW`, `ROLLBACK_IN_PROGRESS`, `READY_TO_JOIN`, `JOINING`, and `READY`. + +- **NEW**: This is the initial state, and all restarts begin with this state. Even if the metagraph is healthy, we initiate the script with this status. +- **ROLLBACK_IN_PROGRESS**: This state indicates that we've started a restart, but the node is still in the process of starting and is not ready to join the metagraph yet. +- **READY_TO_JOIN**: As the name suggests, it signifies that the node is ready to join the metagraph. +- **JOINING**: This state indicates that the node is currently joining the metagraph. +- **READY**: This is the expected final state, signaling that the restart has successfully concluded. + +After a successful execution, the row will be removed from **Dynamo**. You can check the current state by accessing the table directly on the AWS console. + +To create the table on **Dynamo**, you can run the script `src/utils/scripts/create_dynamo_table.sh`. + +**Note: Ensure that you set all environment variables pointing to the correct AWS account (AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_REGION) before running the script.** + +### Cloud Watch + +This service is responsible for storing the logs of our Lambda execution. You can search by Lambda name and review the logs of both the current and past executions. + +## Additional Informations +This repository is designed to aid in monitoring the health of the metagraph and initiate a restart if needed. In the file `src/utils/types.js`, you will find a variable named `ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES`. This variable determines the timeout for the current execution. If this timeout is exceeded, a new restart will be triggered, and the process will be retried. -You should repeat the above parameters for your 3 instances. Additionally, there is a parameter in the SSM Parameter Store for Opsgenie integration, so you need to create the following parameter: +After deploying the Lambda, monitor the initial executions to ensure everything is functioning correctly and that no parameters are missing or provided incorrectly. -`/metagraph-nodes/opsgenie-api-key` +In the `.github` directory, you will find examples of actions to automate the deployment of the Lambda function to AWS. You can use these examples as a reference for automating your deploys. -## Metagraphs Events Payloads -- Locate the events corresponding to the current metagraphs supported by this monitoring tool in metagraphs-events-payload. -- Keeping these files up-to-date is crucial. -- Ensure that the content of these files is transmitted through AWS EventBridge. \ No newline at end of file +Seedlists are not required. You can leave the `seedlists` field as an empty object in the `event.json` file. \ No newline at end of file diff --git a/event.json b/event.json index 9e26dfe..c72ca30 100644 --- a/event.json +++ b/event.json @@ -1 +1,73 @@ -{} \ No newline at end of file +{ + "metagraph": { + "id": "your_metagraph_id", + "name": "your_metagraph_name", + "version": "metagraph_version", + "include_currency_l1_layer": true, + "include_data_l1_layer": true, + "file_system": { + "base_metagraph_l0_directory": "your_metagraph_l0_directory", + "base_currency_l1_directory": "your_currency_l1_directory", + "base_data_l1_directory": "your_data_l1_directory" + }, + "ports": { + "metagraph_l0_public_port": 7000, + "metagraph_l0_p2p_port": 7001, + "metagraph_l0_cli_port": 7002, + "currency_l1_public_port": 8000, + "currency_l1_p2p_port": 8001, + "currency_l1_cli_port": 8002, + "data_l1_public_port": 9000, + "data_l1_p2p_port": 9001, + "data_l1_cli_port": 9002 + }, + "required_env_variables": { + "cl_app_env": "integrationnet or mainnet", + "cl_collateral": 0 + }, + "additional_metagraph_l0_env_variables": [], + "additional_currency_l1_env_variables": [], + "additional_data_l1_env_variables": [], + "seedlists": { + "location": "Github", + "ml0": { + "base_url": "https://github.com/your_repo/releases/download", + "file_name": "ml0-testnet-seedlist" + }, + "cl1": { + "base_url": "https://github.com/your_repo/releases/download", + "file_name": "cl1-testnet-seedlist" + }, + "dl1": { + "base_url": "https://github.com/your_repo/releases/download", + "file_name": "dl1-testnet-seedlist" + } + } + }, + "network": { + "name": "integrationnet or mainnet" + }, + "aws": { + "region": "aws region", + "ec2": { + "instances": { + "genesis": { + "id": "ec2_instance_id", + "ip": "ec2_instance_ip" + }, + "validators": [ + { + "id": "ec2_instance_id", + "ip": "ec2_instance_ip" + }, + { + "id": "ec2_instance_id", + "ip": "ec2_instance_ip" + } + ] + } + } + }, + "force_metagraph_restart": false, + "enable_opsgenie_alerts": true +} \ No newline at end of file diff --git a/metagraphs-events-payloads/currency-example-integrationnet.json b/metagraphs-events-payloads/currency-example-integrationnet.json deleted file mode 100644 index c77a1a6..0000000 --- a/metagraphs-events-payloads/currency-example-integrationnet.json +++ /dev/null @@ -1,57 +0,0 @@ -{ - "metagraph": { - "id": "DAG4dWrdALPQmvF5UBpuXrqdkMHea1H5f7rjb4qY", - "name": "Biforex", - "include_currency_l1_layer": true, - "include_data_l1_layer": false, - "file_system": { - "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", - "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", - "base_data_l1_directory": "/home/ubuntu/code/data-l1" - }, - "ports": { - "metagraph_l0_public_port": 7000, - "metagraph_l0_p2p_port": 7001, - "metagraph_l0_cli_port": 7002, - "currency_l1_public_port": 8000, - "currency_l1_p2p_port": 8001, - "currency_l1_cli_port": 8002, - "data_l1_public_port": 9000, - "data_l1_p2p_port": 9001, - "data_l1_cli_port": 9002 - }, - "required_env_variables": { - "cl_app_env": "integrationnet", - "cl_collateral": 0 - }, - "additional_metagraph_l0_env_variables": [], - "additional_currency_l1_env_variables": [], - "additional_data_l1_env_variables": [], - "seedlists": {} - }, - "network": { - "name": "integrationnet" - }, - "aws": { - "region": "us-west-1", - "ec2": { - "instances": { - "genesis": { - "id": "i-00e6ff6893a3fcba5", - "ip": "18.144.39.83" - }, - "validators": [ - { - "id": "i-089c6076393c9445a", - "ip": "13.56.11.204" - }, - { - "id": "i-09483e068ef6664a7", - "ip": "13.56.224.220" - } - ] - } - } - }, - "force_metagraph_restart": false -} \ No newline at end of file diff --git a/metagraphs-events-payloads/dor-metagraph-integrationnet.json b/metagraphs-events-payloads/dor-metagraph-integrationnet.json deleted file mode 100644 index 3eccb5a..0000000 --- a/metagraphs-events-payloads/dor-metagraph-integrationnet.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "metagraph": { - "id": "DAG5kfY9GoHF1CYaY8tuRJxmB3JSzAEARJEAkA2C", - "name": "DOR", - "version": "v1.0.1", - "include_currency_l1_layer": true, - "include_data_l1_layer": true, - "file_system": { - "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", - "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", - "base_data_l1_directory": "/home/ubuntu/code/data-l1" - }, - "ports": { - "metagraph_l0_public_port": 7000, - "metagraph_l0_p2p_port": 7001, - "metagraph_l0_cli_port": 7002, - "currency_l1_public_port": 8000, - "currency_l1_p2p_port": 8001, - "currency_l1_cli_port": 8002, - "data_l1_public_port": 9000, - "data_l1_p2p_port": 9001, - "data_l1_cli_port": 9002 - }, - "required_env_variables": { - "cl_app_env": "integrationnet", - "cl_collateral": 0 - }, - "additional_metagraph_l0_env_variables": [ - "METAGRAPH_L0_NODE_URL=http://54.218.46.24:7000/cluster/info", - "DATA_L1_NODE_URL=http://54.218.46.24:9000/cluster/info" - ], - "additional_currency_l1_env_variables": [], - "additional_data_l1_env_variables": [], - "seedlists": { - "location": "Github", - "ml0": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "ml0-integrationnet-seedlist" - }, - "cl1": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "cl1-integrationnet-seedlist" - }, - "dl1": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "dl1-integrationnet-seedlist" - } - } - }, - "network": { - "name": "integrationnet" - }, - "aws": { - "region": "us-west-2", - "ec2": { - "instances": { - "genesis": { - "id": "i-03b3276264675e661", - "ip": "54.218.46.24" - }, - "validators": [ - { - "id": "i-074aabc2ebd03819b", - "ip": "34.212.237.118" - }, - { - "id": "i-0cc80924a8124f3e6", - "ip": "34.219.123.201" - } - ] - } - } - }, - "force_metagraph_restart": false -} \ No newline at end of file diff --git a/metagraphs-events-payloads/dor-metagraph-mainnet.json b/metagraphs-events-payloads/dor-metagraph-mainnet.json deleted file mode 100644 index 114dc99..0000000 --- a/metagraphs-events-payloads/dor-metagraph-mainnet.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "metagraph": { - "id": "DAG0CyySf35ftDQDQBnd1bdQ9aPyUdacMghpnCuM", - "name": "DOR", - "version": "v1.0.1", - "include_currency_l1_layer": true, - "include_data_l1_layer": true, - "file_system": { - "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", - "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", - "base_data_l1_directory": "/home/ubuntu/code/data-l1" - }, - "ports": { - "metagraph_l0_public_port": 7000, - "metagraph_l0_p2p_port": 7001, - "metagraph_l0_cli_port": 7002, - "currency_l1_public_port": 8000, - "currency_l1_p2p_port": 8001, - "currency_l1_cli_port": 8002, - "data_l1_public_port": 9000, - "data_l1_p2p_port": 9001, - "data_l1_cli_port": 9002 - }, - "required_env_variables": { - "cl_app_env": "mainnet", - "cl_collateral": 0 - }, - "additional_metagraph_l0_env_variables": [ - "METAGRAPH_L0_NODE_URL=http://54.191.143.191:7000/cluster/info", - "DATA_L1_NODE_URL=http://54.191.143.191:9000/cluster/info" - ], - "additional_currency_l1_env_variables": [], - "additional_data_l1_env_variables": [], - "seedlists": { - "location": "Github", - "ml0": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "ml0-mainnet-seedlist" - }, - "cl1": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "cl1-mainnet-seedlist" - }, - "dl1": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "dl1-mainnet-seedlist" - } - } - }, - "network": { - "name": "mainnet" - }, - "aws": { - "region": "us-west-2", - "ec2": { - "instances": { - "genesis": { - "id": "i-02cd28287c031457d", - "ip": "54.191.143.191" - }, - "validators": [ - { - "id": "i-023598d60862a9575", - "ip": "54.213.58.75" - }, - { - "id": "i-0a29153b8b04ab7c1", - "ip": "34.211.239.153" - } - ] - } - } - }, - "force_metagraph_restart": false -} \ No newline at end of file diff --git a/metagraphs-events-payloads/dor-metagraph-testnet.json b/metagraphs-events-payloads/dor-metagraph-testnet.json deleted file mode 100644 index 10f8f20..0000000 --- a/metagraphs-events-payloads/dor-metagraph-testnet.json +++ /dev/null @@ -1,75 +0,0 @@ -{ - "metagraph": { - "id": "DAG8gMagrwoJ4nAMjbGx17WB5D6nqBEPZYChc3zH", - "name": "DOR", - "version": "v1.0.1", - "include_currency_l1_layer": true, - "include_data_l1_layer": true, - "file_system": { - "base_metagraph_l0_directory": "/home/ubuntu/code/metagraph-l0", - "base_currency_l1_directory": "/home/ubuntu/code/currency-l1", - "base_data_l1_directory": "/home/ubuntu/code/data-l1" - }, - "ports": { - "metagraph_l0_public_port": 7000, - "metagraph_l0_p2p_port": 7001, - "metagraph_l0_cli_port": 7002, - "currency_l1_public_port": 8000, - "currency_l1_p2p_port": 8001, - "currency_l1_cli_port": 8002, - "data_l1_public_port": 9000, - "data_l1_p2p_port": 9001, - "data_l1_cli_port": 9002 - }, - "required_env_variables": { - "cl_app_env": "testnet", - "cl_collateral": 0 - }, - "additional_metagraph_l0_env_variables": [ - "METAGRAPH_L0_NODE_URL=http://34.212.38.215:7000/cluster/info", - "DATA_L1_NODE_URL=http://34.212.38.215:9000/cluster/info" - ], - "additional_currency_l1_env_variables": [], - "additional_data_l1_env_variables": [], - "seedlists": { - "location": "Github", - "ml0": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "ml0-testnet-seedlist" - }, - "cl1": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "cl1-testnet-seedlist" - }, - "dl1": { - "base_url": "https://github.com/Constellation-Labs/dor-metagraph/releases/download", - "file_name": "dl1-testnet-seedlist" - } - } - }, - "network": { - "name": "testnet" - }, - "aws": { - "region": "us-west-2", - "ec2": { - "instances": { - "genesis": { - "id": "i-03f1a976ec6843de1", - "ip": "34.212.38.215" - }, - "validators": [ - { - "id": "i-08ad464855b91963a", - "ip": "34.219.97.95" - }, - { - "id": "i-056d3ced123b2b3ee", - "ip": "35.90.118.112" - } - ] - } - } - }, - "force_metagraph_restart": false -} \ No newline at end of file diff --git a/src/external/opsgenie/index.js b/src/external/opsgenie/index.js index 5a3d250..c9d657a 100644 --- a/src/external/opsgenie/index.js +++ b/src/external/opsgenie/index.js @@ -4,7 +4,7 @@ import { OPSGENIE_API_KEY_PATH, VALID_NETWORKS_TAGS_OPSGENIE, DYNAMO_RESTART_TYP const OPSGENIE_ALERT_URL = "https://api.opsgenie.com/v2/alerts" -const buildValidatorsLogsURLs = (validators, prefix, port) => { +const _buildValidatorsLogsURLs = (validators, prefix, port) => { const messages = [] for (const validator of validators) { messages.push(`${prefix} - ${validator.ip}: http://${validator.ip}:${port}/node/info`) @@ -13,7 +13,7 @@ const buildValidatorsLogsURLs = (validators, prefix, port) => { return messages.join('\n') } -const buildValidatorsLogsInstances = (validators) => { +const _buildValidatorsLogsInstances = (validators) => { const messages = [] for (const validator of validators) { messages.push(`Instance ${validator.ip} (Validator) ID: ${validator.id}`) @@ -23,7 +23,7 @@ const buildValidatorsLogsInstances = (validators) => { return messages.join('\n') } -const buildStartedRestartAlertBody = (event, metagraphRestart) => { +const _buildStartedRestartAlertBody = (event, metagraphRestart) => { const { name: metagraphName, id, ports, include_currency_l1_layer, include_data_l1_layer } = event.metagraph const { name: networkName } = event.network const { genesis, validators } = event.aws.ec2.instances @@ -38,26 +38,26 @@ const buildStartedRestartAlertBody = (event, metagraphRestart) => { You can check the metagraph nodes on these URLs: ML0 - Genesis: http://${genesis.ip}:${ports.metagraph_l0_public_port}/node/info - ${buildValidatorsLogsURLs(validators, 'ML0', ports.metagraph_l0_public_port)} + ${_buildValidatorsLogsURLs(validators, 'ML0', ports.metagraph_l0_public_port)} ${include_currency_l1_layer ? ` CL1 - Genesis: http://${genesis.ip}:${ports.currency_l1_public_port}/node/info - ${buildValidatorsLogsURLs(validators, 'CL1', ports.currency_l1_public_port)} + ${_buildValidatorsLogsURLs(validators, 'CL1', ports.currency_l1_public_port)} `: '' } ${include_data_l1_layer ? ` DL1 - Genesis: http://${genesis.ip}:${ports.data_l1_public_port}/node/info - ${buildValidatorsLogsURLs(validators, 'DL1', ports.data_l1_public_port)} + ${_buildValidatorsLogsURLs(validators, 'DL1', ports.data_l1_public_port)} `: '' } EC2 instances: Instance 1 (Genesis) ID: ${genesis.id} Instance 1 (Genesis) IP: ${genesis.ip} - ${buildValidatorsLogsInstances(validators)} + ${_buildValidatorsLogsInstances(validators)} `, alias: `${id}_restart`, actions: ["Metagraph", "Restart"], @@ -72,7 +72,7 @@ const buildStartedRestartAlertBody = (event, metagraphRestart) => { } } -const buildFailureRestartAlertBody = (event, errorMessage, metagraphRestart) => { +const _buildFailureRestartAlertBody = (event, errorMessage, metagraphRestart) => { const { name: metagraphName, id, ports, include_currency_l1_layer, include_data_l1_layer } = event.metagraph const { name: networkName } = event.network const { genesis, validators } = event.aws.ec2.instances @@ -88,26 +88,26 @@ const buildFailureRestartAlertBody = (event, errorMessage, metagraphRestart) => You can check the metagraph nodes on these URLs: ML0 - Genesis: http://${genesis.ip}:${ports.metagraph_l0_public_port}/node/info - ${buildValidatorsLogsURLs(validators, 'ML0', ports.metagraph_l0_public_port)} + ${_buildValidatorsLogsURLs(validators, 'ML0', ports.metagraph_l0_public_port)} ${include_currency_l1_layer ? ` CL1 - Genesis: http://${genesis.ip}:${ports.currency_l1_public_port}/node/info - ${buildValidatorsLogsURLs(validators, 'CL1', ports.currency_l1_public_port)} + ${_buildValidatorsLogsURLs(validators, 'CL1', ports.currency_l1_public_port)} `: '' } ${include_data_l1_layer ? ` DL1 - Genesis: http://${genesis.ip}:${ports.data_l1_public_port}/node/info - ${buildValidatorsLogsURLs(validators, 'DL1', ports.data_l1_public_port)} + ${_buildValidatorsLogsURLs(validators, 'DL1', ports.data_l1_public_port)} `: '' } EC2 instances: Instance 1 (Genesis) ID: ${genesis.id} Instance 1 (Genesis) IP: ${genesis.ip} - ${buildValidatorsLogsInstances(validators)} + ${_buildValidatorsLogsInstances(validators)} `, actions: ["Metagraph", "Restart"], alias: `${id}_failure_restarted`, @@ -122,7 +122,7 @@ const buildFailureRestartAlertBody = (event, errorMessage, metagraphRestart) => } } -const createRemoteAlert = async (body, opsgenieApiKey) => { +const _createRemoteAlert = async (body, opsgenieApiKey) => { try { await axios.post(OPSGENIE_ALERT_URL, body, { headers: { @@ -135,7 +135,7 @@ const createRemoteAlert = async (body, opsgenieApiKey) => { } } -const closeRemoteAlert = async (alias, opsgenieApiKey) => { +const _closeRemoteAlert = async (alias, opsgenieApiKey) => { const body = { "user": "Monitoring Script", "source": "AWS Lambda", @@ -154,29 +154,42 @@ const closeRemoteAlert = async (alias, opsgenieApiKey) => { } const createMetagraphRestartStartedAlert = async (ssmClient, event, metagraphRestart) => { + if (!event.enable_opsgenie_alerts) { + console.log('Opsgenie not enabled') + return + } + console.log(`Creating Metagraph Restart Started Alert`) const opsgenieApiKey = await getSSMParameter(ssmClient, OPSGENIE_API_KEY_PATH) - const alertBody = buildStartedRestartAlertBody(event, metagraphRestart) + const alertBody = _buildStartedRestartAlertBody(event, metagraphRestart) - await createRemoteAlert(alertBody, opsgenieApiKey) + await _createRemoteAlert(alertBody, opsgenieApiKey) console.log(`Alert created`) } const closeCurrentMetagraphRestartAlert = async (ssmClient, event) => { + if (!event.enable_opsgenie_alerts) { + console.log('Opsgenie not enabled') + return + } console.log(`Closing metagraph restart alert`) const opsgenieApiKey = await getSSMParameter(ssmClient, OPSGENIE_API_KEY_PATH) const alias = `${event.metagraph.id}_restart` - await closeRemoteAlert(alias, opsgenieApiKey) + await _closeRemoteAlert(alias, opsgenieApiKey) console.log(`Alert close`) } const createMetagraphRestartFailureAlert = async (ssmClient, event, errorMessage, metagraphRestart) => { + if (!event.enable_opsgenie_alerts) { + console.log('Opsgenie not enabled') + return + } console.log(`Creating Metagraph Restart Failure Alert`) const opsgenieApiKey = await getSSMParameter(ssmClient, OPSGENIE_API_KEY_PATH) - const alertBody = buildFailureRestartAlertBody(event, errorMessage, metagraphRestart) + const alertBody = _buildFailureRestartAlertBody(event, errorMessage, metagraphRestart) - await createRemoteAlert(alertBody, opsgenieApiKey) + await _createRemoteAlert(alertBody, opsgenieApiKey) console.log(`Alert created`) } diff --git a/src/shared/restart_operations.js b/src/shared/restart_operations.js index e262e4f..86cf710 100644 --- a/src/shared/restart_operations.js +++ b/src/shared/restart_operations.js @@ -1,7 +1,6 @@ import moment from 'moment' -import { LAYERS, NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE } from '../utils/types.js' +import { LAYERS } from '../utils/types.js' import { sendCommand } from '../external/aws/ssm.js' -import { sleep } from './shared.js' const killCurrentExecution = async (ssmClient, event, layer, ec2InstancesIds) => { const { diff --git a/src/utils/types.js b/src/utils/types.js index d742e6a..08ce92c 100644 --- a/src/utils/types.js +++ b/src/utils/types.js @@ -51,8 +51,6 @@ const OPSGENIE_API_KEY_PATH = '/metagraph-nodes/opsgenie-api-key' const ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES = 60 -const NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE = 100 - const NETWORK_NODES = { testnet: { node_1: { @@ -125,6 +123,5 @@ export { NETWORK_NODES, OPSGENIE_API_KEY_PATH, ROLLBACK_IN_PROGRESS_TIMEOUT_IN_MINUTES, - NUMBER_OF_SNAPSHOTS_TO_MOVE_SINCE_LAST_ON_BE, SEEDLIST_EXTERNAL_STORAGE } \ No newline at end of file From 8393d977bf8a58a001d76f2be218ea949a302954 Mon Sep 17 00:00:00 2001 From: Marcus Vinicius Girolneto Sousa Date: Fri, 19 Jan 2024 18:29:53 -0300 Subject: [PATCH 30/30] Update README.md Co-authored-by: Alex Brandes --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9434df1..f7d9f49 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Metagraph Monitoring Tools ======================== -This project has been developed to monitor metagraphs and initiate a restart if necessary. We have a Lambda function dedicated to monitoring a metagraph. This monitoring can trigger two types of restarts: **FULL_CLUSTER** or **INDIVIDUAL_NODES**. +This project has been developed to monitor metagraphs and initiate a restart if necessary. We have a Lambda function dedicated to monitoring each metagraph node individually as well as the snapshot generation process. The lambda can trigger two types of restarts: **FULL_CLUSTER** or **INDIVIDUAL_NODES**. ### Full Cluster Restart