mirror of
https://github.com/serverless/serverless.git
synced 2026-01-25 15:07:39 +00:00
fix: migrate domain plugin to AWS SDK v3 (#13198)
This commit is contained in:
parent
be57f60f6e
commit
ee3f3cb96b
192
package-lock.json
generated
192
package-lock.json
generated
@ -800,6 +800,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-dynamodb/-/client-dynamodb-3.953.0.tgz",
|
||||
"integrity": "sha512-QeSFxXgRjpr8M2wiLUsgg+mXEDtdhcuMnBWbXyjqUwca38pLEFJzJdFyOGul9RoQ2ICseuAy2/RZt0Ri1UgeZQ==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@aws-crypto/sha256-browser": "5.2.0",
|
||||
"@aws-crypto/sha256-js": "5.2.0",
|
||||
@ -1317,6 +1318,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-s3/-/client-s3-3.953.0.tgz",
|
||||
"integrity": "sha512-Lxxdhq5nt6ONulu1UHbIS0tVIar7itXv1m4TJfkVzuSm/yQzxIwnFkLtgW/0P5KIE+FS1yUoE2lS+dJBS1PLFw==",
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@aws-crypto/sha1-browser": "5.2.0",
|
||||
"@aws-crypto/sha256-browser": "5.2.0",
|
||||
@ -2518,6 +2520,7 @@
|
||||
"version": "7.26.10",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
@ -3435,7 +3438,6 @@
|
||||
"version": "8.57.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
@ -3548,7 +3550,6 @@
|
||||
"version": "0.11.14",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@humanwhocodes/object-schema": "^2.0.2",
|
||||
"debug": "^4.3.1",
|
||||
@ -3851,6 +3852,7 @@
|
||||
"version": "29.7.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jest/environment": "^29.7.0",
|
||||
"@jest/expect": "^29.7.0",
|
||||
@ -4480,6 +4482,7 @@
|
||||
"node_modules/@octokit/core": {
|
||||
"version": "6.1.4",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@octokit/auth-token": "^5.0.0",
|
||||
"@octokit/graphql": "^8.1.2",
|
||||
@ -5962,6 +5965,7 @@
|
||||
"version": "8.14.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
@ -6945,16 +6949,6 @@
|
||||
"version": "3.0.2",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/bignumber.js": {
|
||||
"version": "9.3.1",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.1.tgz",
|
||||
"integrity": "sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.3.0",
|
||||
"license": "MIT",
|
||||
@ -7120,6 +7114,7 @@
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"caniuse-lite": "^1.0.30001688",
|
||||
"electron-to-chromium": "^1.5.73",
|
||||
@ -7185,7 +7180,6 @@
|
||||
"version": "3.3.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
},
|
||||
@ -7197,7 +7191,6 @@
|
||||
"version": "5.1.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"semver": "^7.0.0"
|
||||
}
|
||||
@ -7906,16 +7899,6 @@
|
||||
"node": ">=0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/data-view-buffer": {
|
||||
"version": "1.0.2",
|
||||
"license": "MIT",
|
||||
@ -8863,6 +8846,7 @@
|
||||
"integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@rtsao/scc": "^1.1.0",
|
||||
"array-includes": "^3.1.9",
|
||||
@ -9183,6 +9167,7 @@
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz",
|
||||
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
@ -9259,13 +9244,6 @@
|
||||
"type": "^2.7.2"
|
||||
}
|
||||
},
|
||||
"node_modules/extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/fast-content-type-parse": {
|
||||
"version": "2.0.1",
|
||||
"funding": [
|
||||
@ -9378,30 +9356,6 @@
|
||||
"bser": "2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-blob": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "paypal",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"node-domexception": "^1.0.0",
|
||||
"web-streams-polyfill": "^3.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20 || >= 14.13"
|
||||
}
|
||||
},
|
||||
"node_modules/fetch-retry": {
|
||||
"version": "6.0.0",
|
||||
"license": "MIT"
|
||||
@ -9563,19 +9517,6 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/formdata-polyfill": {
|
||||
"version": "4.0.10",
|
||||
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"fetch-blob": "^3.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20.0"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"license": "MIT",
|
||||
@ -9656,38 +9597,6 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gaxios": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-7.1.3.tgz",
|
||||
"integrity": "sha512-YGGyuEdVIjqxkxVH1pUTMY/XtmmsApXrCVv5EU25iX6inEPbV+VakJfLealkBtJN69AQmh1eGOdCl9Sm1UP6XQ==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"extend": "^3.0.2",
|
||||
"https-proxy-agent": "^7.0.1",
|
||||
"node-fetch": "^3.3.2",
|
||||
"rimraf": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/gaxios/node_modules/rimraf": {
|
||||
"version": "5.0.10",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz",
|
||||
"integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==",
|
||||
"license": "ISC",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"glob": "^10.3.7"
|
||||
},
|
||||
"bin": {
|
||||
"rimraf": "dist/esm/bin.mjs"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"dev": true,
|
||||
@ -9910,16 +9819,6 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/google-logging-utils": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-1.1.3.tgz",
|
||||
"integrity": "sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/gopd": {
|
||||
"version": "1.2.0",
|
||||
"license": "MIT",
|
||||
@ -10314,7 +10213,6 @@
|
||||
"version": "3.2.1",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"builtin-modules": "^3.3.0"
|
||||
},
|
||||
@ -10806,6 +10704,7 @@
|
||||
"version": "29.7.0",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@jest/core": "^29.7.0",
|
||||
"@jest/types": "^29.6.3",
|
||||
@ -11449,16 +11348,6 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/json-bigint": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
|
||||
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"bignumber.js": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-buffer": {
|
||||
"version": "3.0.1",
|
||||
"dev": true,
|
||||
@ -12431,46 +12320,6 @@
|
||||
"version": "1.1.0",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/node-domexception": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||
"deprecated": "Use your platform's native DOMException instead",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/jimmywarting"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://paypal.me/jimmywarting"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"data-uri-to-buffer": "^4.0.0",
|
||||
"fetch-blob": "^3.1.4",
|
||||
"formdata-polyfill": "^4.0.10"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/node-fetch"
|
||||
}
|
||||
},
|
||||
"node_modules/node-int64": {
|
||||
"version": "0.4.0",
|
||||
"dev": true,
|
||||
@ -15188,16 +15037,6 @@
|
||||
"makeerror": "1.0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/web-streams-polyfill": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
|
||||
@ -15435,6 +15274,7 @@
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
@ -15668,6 +15508,7 @@
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
@ -15881,6 +15722,7 @@
|
||||
"version": "4.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-acm": "3.953.0",
|
||||
"@aws-sdk/client-api-gateway": "3.953.0",
|
||||
"@aws-sdk/client-apigatewayv2": "3.953.0",
|
||||
"@aws-sdk/client-cloudformation": "3.953.0",
|
||||
@ -15890,12 +15732,15 @@
|
||||
"@aws-sdk/client-iam": "3.953.0",
|
||||
"@aws-sdk/client-iot": "3.953.0",
|
||||
"@aws-sdk/client-lambda": "3.953.0",
|
||||
"@aws-sdk/client-route-53": "3.953.0",
|
||||
"@aws-sdk/client-s3": "3.953.0",
|
||||
"@aws-sdk/client-sts": "3.953.0",
|
||||
"@aws-sdk/credential-providers": "3.953.0",
|
||||
"@aws-sdk/lib-storage": "3.953.0",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@serverlessinc/sf-core": "*",
|
||||
"@smithy/node-http-handler": "^4.4.5",
|
||||
"@smithy/util-retry": "^4.2.6",
|
||||
"adm-zip": "^0.5.16",
|
||||
"ajv": "8.17.1",
|
||||
"ajv-formats": "2.1.1",
|
||||
@ -16195,7 +16040,7 @@
|
||||
},
|
||||
"packages/sf-core": {
|
||||
"name": "@serverlessinc/sf-core",
|
||||
"version": "4.29.3",
|
||||
"version": "4.29.4",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-cloudformation": "3.953.0",
|
||||
@ -16258,7 +16103,7 @@
|
||||
},
|
||||
"packages/sf-core-installer": {
|
||||
"name": "serverless",
|
||||
"version": "4.29.3",
|
||||
"version": "4.29.4",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"axios": "^1.13.2",
|
||||
@ -16314,6 +16159,7 @@
|
||||
"deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.2.0",
|
||||
"@eslint-community/regexpp": "^4.6.1",
|
||||
|
||||
@ -1,10 +1,21 @@
|
||||
import AWS from 'aws-sdk'
|
||||
import {
|
||||
ACMClient,
|
||||
CertificateStatus,
|
||||
ListCertificatesCommand,
|
||||
RequestCertificateCommand,
|
||||
DescribeCertificateCommand,
|
||||
} from '@aws-sdk/client-acm'
|
||||
import { addProxyToAwsClient } from '@serverless/util'
|
||||
import Globals from '../globals.js'
|
||||
import { getAWSPagedResults, sleep } from '../utils.js'
|
||||
import Logging from '../logging.js'
|
||||
import { ServerlessError, ServerlessErrorCodes } from '@serverless/util'
|
||||
|
||||
const certStatuses = ['PENDING_VALIDATION', 'ISSUED', 'INACTIVE']
|
||||
const certStatuses = [
|
||||
CertificateStatus.PENDING_VALIDATION,
|
||||
CertificateStatus.ISSUED,
|
||||
CertificateStatus.INACTIVE,
|
||||
]
|
||||
|
||||
class ACMWrapper {
|
||||
constructor(credentials, endpointType) {
|
||||
@ -12,15 +23,14 @@ class ACMWrapper {
|
||||
const config = {
|
||||
region: isEdge ? Globals.defaultRegion : Globals.getRegion(),
|
||||
endpoint: Globals.getServiceEndpoint('acm'),
|
||||
...Globals.getRetryStrategy(),
|
||||
...Globals.getRequestHandler(),
|
||||
retryStrategy: Globals.getRetryStrategy(),
|
||||
}
|
||||
|
||||
if (credentials) {
|
||||
config.credentials = credentials
|
||||
}
|
||||
|
||||
this.acm = new AWS.ACM(config)
|
||||
this.acm = addProxyToAwsClient(new ACMClient(config))
|
||||
}
|
||||
|
||||
async getCertArn(domain) {
|
||||
@ -30,11 +40,10 @@ class ACMWrapper {
|
||||
try {
|
||||
const certificates = await getAWSPagedResults(
|
||||
this.acm,
|
||||
'listCertificates',
|
||||
'CertificateSummaryList',
|
||||
'NextToken',
|
||||
'NextToken',
|
||||
{ CertificateStatuses: certStatuses },
|
||||
new ListCertificatesCommand({ CertificateStatuses: certStatuses }),
|
||||
)
|
||||
// enhancement idea: weight the choice of cert so longer expires
|
||||
// and RenewalEligibility = ELIGIBLE is more preferable
|
||||
@ -50,7 +59,9 @@ class ACMWrapper {
|
||||
certificateName,
|
||||
)
|
||||
}
|
||||
Logging.logInfo(`Found a certificate ARN: '${certificateArn}'`)
|
||||
if (certificateArn) {
|
||||
Logging.logInfo(`Found existing certificate ARN: '${certificateArn}'`)
|
||||
}
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`Could not search certificates in Certificate Manager.\n${err.message}`,
|
||||
@ -129,10 +140,9 @@ class ACMWrapper {
|
||||
const params = {
|
||||
DomainName: domainName,
|
||||
ValidationMethod: 'DNS',
|
||||
// SubjectAlternativeNames: [],
|
||||
}
|
||||
|
||||
const result = await this.acm.requestCertificate(params).promise()
|
||||
const result = await this.acm.send(new RequestCertificateCommand(params))
|
||||
Logging.logInfo(
|
||||
`Certificate created with ARN: '${result.CertificateArn}'`,
|
||||
)
|
||||
@ -168,7 +178,9 @@ class ACMWrapper {
|
||||
while (Date.now() - startTime < maxWaitTimeMs) {
|
||||
try {
|
||||
const params = { CertificateArn: certificateArn }
|
||||
const result = await this.acm.describeCertificate(params).promise()
|
||||
const result = await this.acm.send(
|
||||
new DescribeCertificateCommand(params),
|
||||
)
|
||||
|
||||
if (
|
||||
result.Certificate.DomainValidationOptions &&
|
||||
@ -193,7 +205,8 @@ class ACMWrapper {
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`Failed to get validation records for certificate '${certificateArn}': ${err.message}`,
|
||||
ServerlessErrorCodes.domains.ACM_CERTIFICATE_VALIDATION_RECORDS_FAILED,
|
||||
ServerlessErrorCodes.domains
|
||||
.ACM_CERTIFICATE_VALIDATION_RECORDS_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
@ -227,7 +240,9 @@ class ACMWrapper {
|
||||
while (Date.now() - startTime < maxWaitTimeMs) {
|
||||
try {
|
||||
const params = { CertificateArn: certificateArn }
|
||||
const result = await this.acm.describeCertificate(params).promise()
|
||||
const result = await this.acm.send(
|
||||
new DescribeCertificateCommand(params),
|
||||
)
|
||||
|
||||
if (result.Certificate.Status === 'ISSUED') {
|
||||
Logging.logInfo('Certificate validation completed successfully!')
|
||||
|
||||
@ -1,10 +1,19 @@
|
||||
/**
|
||||
* Wrapper class for AWS APIGateway provider
|
||||
*/
|
||||
import DomainConfig from '../models/domain-config.js'
|
||||
import {
|
||||
APIGatewayClient,
|
||||
CreateDomainNameCommand,
|
||||
GetDomainNameCommand,
|
||||
DeleteDomainNameCommand,
|
||||
CreateBasePathMappingCommand,
|
||||
GetBasePathMappingsCommand,
|
||||
UpdateBasePathMappingCommand,
|
||||
DeleteBasePathMappingCommand,
|
||||
} from '@aws-sdk/client-api-gateway'
|
||||
import { addProxyToAwsClient } from '@serverless/util'
|
||||
import DomainInfo from '../models/domain-info.js'
|
||||
import Globals from '../globals.js'
|
||||
import AWS from 'aws-sdk'
|
||||
import ApiGatewayMap from '../models/api-gateway-map.js'
|
||||
import APIGatewayBase from '../models/apigateway-base.js'
|
||||
import Logging from '../logging.js'
|
||||
@ -17,15 +26,14 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
|
||||
const config = {
|
||||
region: Globals.getRegion(),
|
||||
endpoint: Globals.getServiceEndpoint('apigateway'),
|
||||
...Globals.getRetryStrategy(),
|
||||
...Globals.getRequestHandler(),
|
||||
retryStrategy: Globals.getRetryStrategy(),
|
||||
}
|
||||
|
||||
if (credentials) {
|
||||
config.credentials = credentials
|
||||
}
|
||||
|
||||
this.apiGateway = new AWS.APIGateway(config)
|
||||
this.apiGateway = addProxyToAwsClient(new APIGatewayClient(config))
|
||||
}
|
||||
|
||||
async createCustomDomain(domain) {
|
||||
@ -62,9 +70,9 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
|
||||
}
|
||||
|
||||
try {
|
||||
const domainInfo = await this.apiGateway
|
||||
.createDomainName(params)
|
||||
.promise()
|
||||
const domainInfo = await this.apiGateway.send(
|
||||
new CreateDomainNameCommand(params),
|
||||
)
|
||||
return new DomainInfo(domainInfo)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
@ -84,31 +92,33 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
|
||||
async getCustomDomain(domain, silent = true) {
|
||||
// Make API call
|
||||
try {
|
||||
const domainInfo = await this.apiGateway
|
||||
.getDomainName({
|
||||
const domainInfo = await this.apiGateway.send(
|
||||
new GetDomainNameCommand({
|
||||
domainName: domain.givenDomainName,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
return new DomainInfo(domainInfo)
|
||||
} catch (err) {
|
||||
if (!err.statusCode || err.statusCode !== 404 || !silent) {
|
||||
const statusCode = err.$metadata?.httpStatusCode
|
||||
if (!statusCode || statusCode !== 404 || !silent) {
|
||||
throw new ServerlessError(
|
||||
`V1 - Unable to fetch information about '${domain.givenDomainName}':\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.API_GATEWAY_CUSTOM_DOMAIN_FETCH_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
Logging.logWarning(`V1 - '${domain.givenDomainName}' does not exist.`)
|
||||
}
|
||||
}
|
||||
|
||||
async deleteCustomDomain(domain) {
|
||||
// Make API call
|
||||
try {
|
||||
await this.apiGateway
|
||||
.deleteDomainName({
|
||||
await this.apiGateway.send(
|
||||
new DeleteDomainNameCommand({
|
||||
domainName: domain.givenDomainName,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`V1 - Failed to delete custom domain '${domain.givenDomainName}':\n${err.message}`,
|
||||
@ -120,21 +130,22 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
|
||||
|
||||
async createBasePathMapping(domain) {
|
||||
try {
|
||||
await this.apiGateway
|
||||
.createBasePathMapping({
|
||||
await this.apiGateway.send(
|
||||
new CreateBasePathMappingCommand({
|
||||
basePath: domain.basePath,
|
||||
domainName: domain.givenDomainName,
|
||||
restApiId: domain.apiId,
|
||||
stage: domain.stage,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
Logging.logInfo(
|
||||
`V1 - Created API mapping '${Logging.formatBasePathForDisplay(domain.basePath)}' for '${domain.givenDomainName}'`,
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`V1 - Unable to create base path mapping for '${domain.givenDomainName}':\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.API_GATEWAY_BASE_PATH_MAPPING_CREATION_FAILED,
|
||||
ServerlessErrorCodes.domains
|
||||
.API_GATEWAY_BASE_PATH_MAPPING_CREATION_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
@ -144,13 +155,12 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
|
||||
try {
|
||||
const items = await getAWSPagedResults(
|
||||
this.apiGateway,
|
||||
'getBasePathMappings',
|
||||
'items',
|
||||
'position',
|
||||
'position',
|
||||
{
|
||||
new GetBasePathMappingsCommand({
|
||||
domainName: domain.givenDomainName,
|
||||
},
|
||||
}),
|
||||
)
|
||||
return items.map((item) => {
|
||||
return new ApiGatewayMap(
|
||||
@ -174,8 +184,8 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
|
||||
Logging.logInfo(`V1 - Updating API mapping from '${Logging.formatBasePathForDisplay(domain.apiMapping.basePath)}'
|
||||
to '${Logging.formatBasePathForDisplay(domain.basePath)}' for '${domain.givenDomainName}'`)
|
||||
try {
|
||||
await this.apiGateway
|
||||
.updateBasePathMapping({
|
||||
await this.apiGateway.send(
|
||||
new UpdateBasePathMappingCommand({
|
||||
basePath: domain.apiMapping.basePath,
|
||||
domainName: domain.givenDomainName,
|
||||
patchOperations: [
|
||||
@ -185,12 +195,13 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
|
||||
value: domain.basePath,
|
||||
},
|
||||
],
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`V1 - Unable to update base path mapping for '${domain.givenDomainName}':\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.API_GATEWAY_BASE_PATH_MAPPING_UPDATE_FAILED,
|
||||
ServerlessErrorCodes.domains
|
||||
.API_GATEWAY_BASE_PATH_MAPPING_UPDATE_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
@ -198,19 +209,20 @@ class APIGatewayV1Wrapper extends APIGatewayBase {
|
||||
|
||||
async deleteBasePathMapping(domain) {
|
||||
try {
|
||||
await this.apiGateway
|
||||
.deleteBasePathMapping({
|
||||
await this.apiGateway.send(
|
||||
new DeleteBasePathMappingCommand({
|
||||
basePath: domain.apiMapping.basePath,
|
||||
domainName: domain.givenDomainName,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
Logging.logInfo(
|
||||
`V1 - Removed '${Logging.formatBasePathForDisplay(domain.apiMapping.basePath)}' base path mapping`,
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`V1 - Unable to remove base path mapping for '${domain.givenDomainName}':\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.API_GATEWAY_BASE_PATH_MAPPING_DELETION_FAILED,
|
||||
ServerlessErrorCodes.domains
|
||||
.API_GATEWAY_BASE_PATH_MAPPING_DELETION_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,12 +1,21 @@
|
||||
/**
|
||||
* Wrapper class for AWS APIGatewayV2 provider
|
||||
*/
|
||||
import DomainConfig from '../models/domain-config.js'
|
||||
import {
|
||||
ApiGatewayV2Client,
|
||||
CreateDomainNameCommand,
|
||||
GetDomainNameCommand,
|
||||
DeleteDomainNameCommand,
|
||||
CreateApiMappingCommand,
|
||||
GetApiMappingsCommand,
|
||||
UpdateApiMappingCommand,
|
||||
DeleteApiMappingCommand,
|
||||
} from '@aws-sdk/client-apigatewayv2'
|
||||
import { addProxyToAwsClient } from '@serverless/util'
|
||||
import DomainInfo from '../models/domain-info.js'
|
||||
import Globals from '../globals.js'
|
||||
import ApiGatewayMap from '../models/api-gateway-map.js'
|
||||
import APIGatewayBase from '../models/apigateway-base.js'
|
||||
import AWS from 'aws-sdk'
|
||||
import Logging from '../logging.js'
|
||||
import { getAWSPagedResults } from '../utils.js'
|
||||
import { ServerlessError, ServerlessErrorCodes } from '@serverless/util'
|
||||
@ -17,15 +26,14 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
const config = {
|
||||
region: Globals.getRegion(),
|
||||
endpoint: Globals.getServiceEndpoint('apigatewayv2'),
|
||||
...Globals.getRetryStrategy(),
|
||||
...Globals.getRequestHandler(),
|
||||
retryStrategy: Globals.getRetryStrategy(),
|
||||
}
|
||||
|
||||
if (credentials) {
|
||||
config.credentials = credentials
|
||||
}
|
||||
|
||||
this.apiGateway = new AWS.ApiGatewayV2(config)
|
||||
this.apiGateway = addProxyToAwsClient(new ApiGatewayV2Client(config))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -64,9 +72,9 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
}
|
||||
|
||||
try {
|
||||
const domainInfo = await this.apiGateway
|
||||
.createDomainName(params)
|
||||
.promise()
|
||||
const domainInfo = await this.apiGateway.send(
|
||||
new CreateDomainNameCommand(params),
|
||||
)
|
||||
return new DomainInfo(domainInfo)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
@ -86,14 +94,15 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
async getCustomDomain(domain, silent = true) {
|
||||
// Make API call
|
||||
try {
|
||||
const domainInfo = await this.apiGateway
|
||||
.getDomainName({
|
||||
const domainInfo = await this.apiGateway.send(
|
||||
new GetDomainNameCommand({
|
||||
DomainName: domain.givenDomainName,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
return new DomainInfo(domainInfo)
|
||||
} catch (err) {
|
||||
if (!err.statusCode || err.statusCode !== 404 || !silent) {
|
||||
const statusCode = err.$metadata?.httpStatusCode
|
||||
if (!statusCode || statusCode !== 404 || !silent) {
|
||||
throw new ServerlessError(
|
||||
`V2 - Unable to fetch information about '${domain.givenDomainName}':\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.API_GATEWAY_CUSTOM_DOMAIN_FETCH_FAILED,
|
||||
@ -112,11 +121,11 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
async deleteCustomDomain(domain) {
|
||||
// Make API call
|
||||
try {
|
||||
await this.apiGateway
|
||||
.deleteDomainName({
|
||||
await this.apiGateway.send(
|
||||
new DeleteDomainNameCommand({
|
||||
DomainName: domain.givenDomainName,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`V2 - Failed to delete custom domain '${domain.givenDomainName}':\n${err.message}`,
|
||||
@ -133,8 +142,8 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
*/
|
||||
async createBasePathMapping(domain) {
|
||||
try {
|
||||
await this.apiGateway
|
||||
.createApiMapping({
|
||||
await this.apiGateway.send(
|
||||
new CreateApiMappingCommand({
|
||||
ApiId: domain.apiId,
|
||||
ApiMappingKey: domain.basePath,
|
||||
DomainName: domain.givenDomainName,
|
||||
@ -142,15 +151,16 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
domain.apiType === Globals.apiTypes.http
|
||||
? '$default'
|
||||
: domain.stage,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
Logging.logInfo(
|
||||
`V2 - Created API mapping '${Logging.formatBasePathForDisplay(domain.basePath)}' for '${domain.givenDomainName}'`,
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`V2 - Unable to create base path mapping for '${domain.givenDomainName}':\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.API_GATEWAY_BASE_PATH_MAPPING_CREATION_FAILED,
|
||||
ServerlessErrorCodes.domains
|
||||
.API_GATEWAY_BASE_PATH_MAPPING_CREATION_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
@ -165,13 +175,12 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
try {
|
||||
const items = await getAWSPagedResults(
|
||||
this.apiGateway,
|
||||
'getApiMappings',
|
||||
'Items',
|
||||
'NextToken',
|
||||
'NextToken',
|
||||
{
|
||||
new GetApiMappingsCommand({
|
||||
DomainName: domain.givenDomainName,
|
||||
},
|
||||
}),
|
||||
)
|
||||
return items.map(
|
||||
(item) =>
|
||||
@ -198,8 +207,8 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
*/
|
||||
async updateBasePathMapping(domain) {
|
||||
try {
|
||||
await this.apiGateway
|
||||
.updateApiMapping({
|
||||
await this.apiGateway.send(
|
||||
new UpdateApiMappingCommand({
|
||||
ApiId: domain.apiId,
|
||||
ApiMappingId: domain.apiMapping.apiMappingId,
|
||||
ApiMappingKey: domain.basePath,
|
||||
@ -208,15 +217,16 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
domain.apiType === Globals.apiTypes.http
|
||||
? '$default'
|
||||
: domain.stage,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
Logging.logInfo(
|
||||
`V2 - Updated API mapping to '${Logging.formatBasePathForDisplay(domain.basePath)}' for '${domain.givenDomainName}'`,
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`V2 - Unable to update base path mapping for '${domain.givenDomainName}':\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.API_GATEWAY_BASE_PATH_MAPPING_UPDATE_FAILED,
|
||||
ServerlessErrorCodes.domains
|
||||
.API_GATEWAY_BASE_PATH_MAPPING_UPDATE_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
@ -229,19 +239,20 @@ class APIGatewayV2Wrapper extends APIGatewayBase {
|
||||
*/
|
||||
async deleteBasePathMapping(domain) {
|
||||
try {
|
||||
await this.apiGateway
|
||||
.deleteApiMapping({
|
||||
await this.apiGateway.send(
|
||||
new DeleteApiMappingCommand({
|
||||
ApiMappingId: domain.apiMapping.apiMappingId,
|
||||
DomainName: domain.givenDomainName,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
Logging.logInfo(
|
||||
`V2 - Removed API Mapping with id: '${domain.apiMapping.apiMappingId}'`,
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`V2 - Unable to remove base path mapping for '${domain.givenDomainName}':\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.API_GATEWAY_BASE_PATH_MAPPING_DELETION_FAILED,
|
||||
ServerlessErrorCodes.domains
|
||||
.API_GATEWAY_BASE_PATH_MAPPING_DELETION_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
|
||||
@ -2,11 +2,20 @@
|
||||
* Wrapper class for AWS CloudFormation provider
|
||||
*/
|
||||
|
||||
import AWS from 'aws-sdk'
|
||||
import {
|
||||
CloudFormationClient,
|
||||
DescribeStackResourceCommand,
|
||||
DescribeStacksCommand,
|
||||
ListExportsCommand,
|
||||
} from '@aws-sdk/client-cloudformation'
|
||||
import {
|
||||
addProxyToAwsClient,
|
||||
ServerlessError,
|
||||
ServerlessErrorCodes,
|
||||
} from '@serverless/util'
|
||||
import Globals from '../globals.js'
|
||||
import Logging from '../logging.js'
|
||||
import { getAWSPagedResults } from '../utils.js'
|
||||
import { ServerlessError, ServerlessErrorCodes } from '@serverless/util'
|
||||
|
||||
class CloudFormationWrapper {
|
||||
constructor(credentials) {
|
||||
@ -19,15 +28,14 @@ class CloudFormationWrapper {
|
||||
const config = {
|
||||
region: Globals.getRegion(),
|
||||
endpoint: Globals.getServiceEndpoint('cloudformation'),
|
||||
...Globals.getRetryStrategy(),
|
||||
...Globals.getRequestHandler(),
|
||||
retryStrategy: Globals.getRetryStrategy(),
|
||||
}
|
||||
|
||||
if (credentials) {
|
||||
config.credentials = credentials
|
||||
}
|
||||
|
||||
this.cloudFormation = new AWS.CloudFormation(config)
|
||||
this.cloudFormation = addProxyToAwsClient(new CloudFormationClient(config))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -142,11 +150,10 @@ class CloudFormationWrapper {
|
||||
async getImportValues(names) {
|
||||
const exports = await getAWSPagedResults(
|
||||
this.cloudFormation,
|
||||
'listExports',
|
||||
'Exports',
|
||||
'NextToken',
|
||||
'NextToken',
|
||||
{},
|
||||
new ListExportsCommand({}),
|
||||
)
|
||||
// filter Exports by names which we need
|
||||
const filteredExports = exports.filter(
|
||||
@ -168,12 +175,12 @@ class CloudFormationWrapper {
|
||||
*/
|
||||
async getStack(logicalResourceId, stackName) {
|
||||
try {
|
||||
return await this.cloudFormation
|
||||
.describeStackResource({
|
||||
return await this.cloudFormation.send(
|
||||
new DescribeStackResourceCommand({
|
||||
LogicalResourceId: logicalResourceId,
|
||||
StackName: stackName,
|
||||
})
|
||||
.promise()
|
||||
}),
|
||||
)
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`Failed to find CloudFormation resources with an error: ${err.message}\n`,
|
||||
@ -193,11 +200,10 @@ class CloudFormationWrapper {
|
||||
// get all stacks from the CloudFormation
|
||||
const stacks = await getAWSPagedResults(
|
||||
this.cloudFormation,
|
||||
'describeStacks',
|
||||
'Stacks',
|
||||
'NextToken',
|
||||
'NextToken',
|
||||
{},
|
||||
new DescribeStacksCommand({}),
|
||||
)
|
||||
|
||||
// filter stacks by given stackName and check by nested stack RootId
|
||||
|
||||
@ -1,21 +1,16 @@
|
||||
import {
|
||||
Route53Client,
|
||||
ChangeResourceRecordSetsCommand,
|
||||
ListHostedZonesCommand,
|
||||
ChangeAction,
|
||||
RRType,
|
||||
} from '@aws-sdk/client-route-53'
|
||||
import { addProxyToAwsClient } from '@serverless/util'
|
||||
import Globals from '../globals.js'
|
||||
import DomainConfig from '../models/domain-config.js'
|
||||
import Logging from '../logging.js'
|
||||
import AWS from 'aws-sdk'
|
||||
import { getAWSPagedResults } from '../utils.js'
|
||||
import { ServerlessError, ServerlessErrorCodes } from '@serverless/util'
|
||||
|
||||
// Define constants that were imported from v3 SDK
|
||||
const ChangeAction = {
|
||||
UPSERT: 'UPSERT',
|
||||
DELETE: 'DELETE',
|
||||
}
|
||||
|
||||
const RRType = {
|
||||
A: 'A',
|
||||
AAAA: 'AAAA',
|
||||
}
|
||||
|
||||
class Route53Wrapper {
|
||||
constructor(credentials, region) {
|
||||
// not null and not undefined
|
||||
@ -23,8 +18,7 @@ class Route53Wrapper {
|
||||
const config = {
|
||||
region: region || Globals.getRegion(),
|
||||
endpoint: serviceEndpoint,
|
||||
...Globals.getRetryStrategy(),
|
||||
...Globals.getRequestHandler(),
|
||||
retryStrategy: Globals.getRetryStrategy(),
|
||||
}
|
||||
|
||||
if (credentials) {
|
||||
@ -32,7 +26,7 @@ class Route53Wrapper {
|
||||
}
|
||||
|
||||
this.region = config.region
|
||||
this.route53 = new AWS.Route53(config)
|
||||
this.route53 = addProxyToAwsClient(new Route53Client(config))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,11 +51,10 @@ class Route53Wrapper {
|
||||
try {
|
||||
hostedZones = await getAWSPagedResults(
|
||||
this.route53,
|
||||
'listHostedZones',
|
||||
'HostedZones',
|
||||
'Marker',
|
||||
'NextMarker',
|
||||
{},
|
||||
new ListHostedZonesCommand({}),
|
||||
)
|
||||
Logging.logInfo(
|
||||
`Found hosted zones list: ${hostedZones.map((zone) => zone.Name)}.`,
|
||||
@ -114,11 +107,10 @@ class Route53Wrapper {
|
||||
try {
|
||||
const hostedZones = await getAWSPagedResults(
|
||||
this.route53,
|
||||
'listHostedZones',
|
||||
'HostedZones',
|
||||
'Marker',
|
||||
'NextMarker',
|
||||
{},
|
||||
new ListHostedZonesCommand({}),
|
||||
)
|
||||
|
||||
// removing the first part of the domain name, api.test.com => test.com
|
||||
@ -149,11 +141,10 @@ class Route53Wrapper {
|
||||
try {
|
||||
const hostedZones = await getAWSPagedResults(
|
||||
this.route53,
|
||||
'listHostedZones',
|
||||
'HostedZones',
|
||||
'Marker',
|
||||
'NextMarker',
|
||||
{},
|
||||
new ListHostedZonesCommand({}),
|
||||
)
|
||||
|
||||
for (const record of validationRecords) {
|
||||
@ -205,12 +196,13 @@ class Route53Wrapper {
|
||||
HostedZoneId: hostedZoneId,
|
||||
}
|
||||
|
||||
await this.route53.changeResourceRecordSets(params).promise()
|
||||
await this.route53.send(new ChangeResourceRecordSetsCommand(params))
|
||||
}
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`Failed to create certificate validation records: ${err.message}`,
|
||||
ServerlessErrorCodes.route53.ROUTE53_CERTIFICATE_VALIDATION_RECORDS_FAILED,
|
||||
ServerlessErrorCodes.route53
|
||||
.ROUTE53_CERTIFICATE_VALIDATION_RECORDS_FAILED,
|
||||
{ originalMessage: err.message },
|
||||
)
|
||||
}
|
||||
@ -300,7 +292,7 @@ class Route53Wrapper {
|
||||
}
|
||||
// Make API call
|
||||
try {
|
||||
await this.route53.changeResourceRecordSets(params).promise()
|
||||
await this.route53.send(new ChangeResourceRecordSetsCommand(params))
|
||||
} catch (err) {
|
||||
throw new ServerlessError(
|
||||
`Failed to ${action} ${recordsToCreate.join(',')} Alias for '${domain.givenDomainName}':\n
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import DomainConfig from '../models/domain-config.js'
|
||||
import { S3Client, HeadObjectCommand } from '@aws-sdk/client-s3'
|
||||
import { addProxyToAwsClient } from '@serverless/util'
|
||||
import Logging from '../logging.js'
|
||||
import AWS from 'aws-sdk'
|
||||
import Globals from '../globals.js'
|
||||
import { ServerlessError, ServerlessErrorCodes } from '@serverless/util'
|
||||
|
||||
@ -9,15 +9,14 @@ class S3Wrapper {
|
||||
const config = {
|
||||
region: Globals.getRegion(),
|
||||
endpoint: Globals.getServiceEndpoint('s3'),
|
||||
...Globals.getRetryStrategy(),
|
||||
...Globals.getRequestHandler(),
|
||||
retryStrategy: Globals.getRetryStrategy(),
|
||||
}
|
||||
|
||||
if (credentials) {
|
||||
config.credentials = credentials
|
||||
}
|
||||
|
||||
this.s3 = new AWS.S3(config)
|
||||
this.s3 = addProxyToAwsClient(new S3Client(config))
|
||||
}
|
||||
|
||||
/**
|
||||
@ -35,9 +34,10 @@ class S3Wrapper {
|
||||
}
|
||||
|
||||
try {
|
||||
await this.s3.headObject(params).promise()
|
||||
await this.s3.send(new HeadObjectCommand(params))
|
||||
} catch (err) {
|
||||
if (!err.statusCode || err.statusCode !== 403) {
|
||||
const statusCode = err.$metadata?.httpStatusCode
|
||||
if (!statusCode || statusCode !== 403) {
|
||||
throw new ServerlessError(
|
||||
`Could not head S3 object at ${domain.tlsTruststoreUri}.\n${err.message}`,
|
||||
ServerlessErrorCodes.domains.S3_TLS_CERTIFICATE_OBJECT_NOT_FOUND,
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import AWS from 'aws-sdk'
|
||||
import { fromIni } from '@aws-sdk/credential-providers'
|
||||
import { ConfiguredRetryStrategy } from '@smithy/util-retry'
|
||||
|
||||
export default class Globals {
|
||||
static pluginName = 'domains'
|
||||
@ -75,28 +76,30 @@ export default class Globals {
|
||||
}
|
||||
|
||||
static getRegion() {
|
||||
const slsRegion =
|
||||
Globals.options.region || Globals.serverless.service.provider.region
|
||||
return slsRegion || Globals.currentRegion || Globals.defaultRegion
|
||||
return Globals.currentRegion || Globals.defaultRegion
|
||||
}
|
||||
|
||||
/**
|
||||
* Get credentials for a specific AWS profile using AWS SDK V3
|
||||
* @param {string} profile - The AWS profile name
|
||||
* @returns {Promise<object>} - The resolved credentials
|
||||
*/
|
||||
static async getProfileCreds(profile) {
|
||||
const credentials = new AWS.SharedIniFileCredentials({ profile })
|
||||
return credentials
|
||||
return fromIni({ profile })()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get retry strategy for AWS SDK V3 clients
|
||||
* @param {number} attempts - Maximum retry attempts (default: 5)
|
||||
* @param {number} delay - Delay in ms per attempt (default: 3000)
|
||||
* @param {number} backoff - Base backoff in ms (default: 500)
|
||||
* @returns {ConfiguredRetryStrategy} - The retry strategy instance
|
||||
*/
|
||||
static getRetryStrategy(attempts = 5, delay = 3000, backoff = 500) {
|
||||
return {
|
||||
retryDelayOptions: {
|
||||
base: backoff,
|
||||
customBackoff: (retryCount) => backoff + retryCount * delay,
|
||||
},
|
||||
maxRetries: attempts,
|
||||
}
|
||||
}
|
||||
|
||||
static getRequestHandler() {
|
||||
// AWS SDK v2 handles proxy configuration automatically
|
||||
return {}
|
||||
return new ConfiguredRetryStrategy(
|
||||
attempts,
|
||||
// Backoff function: base backoff + delay per attempt
|
||||
(attempt) => backoff + attempt * delay,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,7 +10,6 @@ import { sleep } from './utils.js'
|
||||
import APIGatewayV1Wrapper from './aws/api-gateway-v1-wrapper.js'
|
||||
import APIGatewayV2Wrapper from './aws/api-gateway-v2-wrapper.js'
|
||||
import Logging from './logging.js'
|
||||
import AWS from 'aws-sdk'
|
||||
import { ServerlessError, ServerlessErrorCodes } from '@serverless/util'
|
||||
|
||||
class ServerlessCustomDomain {
|
||||
@ -81,26 +80,6 @@ class ServerlessCustomDomain {
|
||||
await this.initAWSRegion()
|
||||
await this.initAWSResources()
|
||||
|
||||
// start of the legacy AWS SDK V2 creds support
|
||||
// TODO: remove it in case serverless will add V3 support
|
||||
const domain = this.domains[0]
|
||||
if (domain) {
|
||||
try {
|
||||
await this.getApiGateway(domain).getCustomDomain(domain)
|
||||
} catch (error) {
|
||||
if (
|
||||
error.message.includes(
|
||||
'Could not load credentials from any providers',
|
||||
)
|
||||
) {
|
||||
Globals.credentials =
|
||||
await this.serverless.providers.aws.getCredentials()
|
||||
await this.initAWSResources()
|
||||
}
|
||||
}
|
||||
}
|
||||
// end of the legacy AWS SDK V2 creds support
|
||||
|
||||
return lifecycleFunc.call(this)
|
||||
}
|
||||
|
||||
@ -211,7 +190,8 @@ class ServerlessCustomDomain {
|
||||
throw new ServerlessError(
|
||||
"'EDGE' endpointType is not compatible with HTTP APIs. Please change the endpointType to 'REGIONAL' or the apiType to 'rest' or 'websocket'.\n" +
|
||||
'https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-vs-rest.html',
|
||||
ServerlessErrorCodes.domains.DOMAIN_VALIDATION_INCOMPATIBLE_ENDPOINT_TYPE,
|
||||
ServerlessErrorCodes.domains
|
||||
.DOMAIN_VALIDATION_INCOMPATIBLE_ENDPOINT_TYPE,
|
||||
)
|
||||
}
|
||||
} else if (domain.apiType === Globals.apiTypes.websocket) {
|
||||
@ -219,7 +199,8 @@ class ServerlessCustomDomain {
|
||||
if (domain.endpointType === Globals.endpointTypes.edge) {
|
||||
throw new ServerlessError(
|
||||
"'EDGE' endpointType is not compatible with WebSocket APIs",
|
||||
ServerlessErrorCodes.domains.DOMAIN_VALIDATION_INCOMPATIBLE_ENDPOINT_TYPE,
|
||||
ServerlessErrorCodes.domains
|
||||
.DOMAIN_VALIDATION_INCOMPATIBLE_ENDPOINT_TYPE,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -227,30 +208,17 @@ class ServerlessCustomDomain {
|
||||
}
|
||||
|
||||
/**
|
||||
* Init AWS credentials based on sls `provider.profile`
|
||||
* Init AWS credentials from the framework (already honors provider.profile and --aws-profile)
|
||||
*/
|
||||
async initSLSCredentials() {
|
||||
const slsProfile =
|
||||
Globals.options['aws-profile'] ||
|
||||
Globals.serverless.service.provider.profile
|
||||
Globals.credentials = slsProfile
|
||||
? await Globals.getProfileCreds(slsProfile)
|
||||
: null
|
||||
Globals.credentials = await this.serverless.providers.aws.getCredentials()
|
||||
}
|
||||
|
||||
/**
|
||||
* Init AWS current region based on Node options
|
||||
* Init AWS current region from the framework (already honors --region and provider.region)
|
||||
*/
|
||||
async initAWSRegion() {
|
||||
try {
|
||||
// For AWS SDK v2, we can get region from config or environment
|
||||
Globals.currentRegion =
|
||||
AWS.config.region ||
|
||||
process.env.AWS_REGION ||
|
||||
process.env.AWS_DEFAULT_REGION
|
||||
} catch (err) {
|
||||
Logging.logInfo('Node region was not found.')
|
||||
}
|
||||
Globals.currentRegion = this.serverless.providers.aws.getRegion()
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -42,32 +42,30 @@ function evaluateBoolean(value, defaultValue) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through the pages of a AWS SDK v2 response and collect them into a single array
|
||||
* Iterate through the pages of an AWS SDK v3 response and collect them into a single array
|
||||
*
|
||||
* @param {Object} client - The AWS service instance to use to make the calls
|
||||
* @param {string} methodName - The method name to call on the client
|
||||
* @param {Object} client - The AWS SDK v3 client instance
|
||||
* @param {string} resultsKey - The key name in the response that contains the items to return
|
||||
* @param {string} nextTokenKey - The request key name to append to the request that has the paging token value
|
||||
* @param {string} nextResponseTokenKey - The response key name that has the next paging token value
|
||||
* @param {Object} params - Parameters to send in the request
|
||||
* @param {Object} command - The AWS SDK v3 Command instance to execute
|
||||
* @returns {Promise<Array>} Promise that resolves to an array of results
|
||||
*/
|
||||
async function getAWSPagedResults(
|
||||
client,
|
||||
methodName,
|
||||
resultsKey,
|
||||
nextTokenKey,
|
||||
nextResponseTokenKey,
|
||||
params,
|
||||
command,
|
||||
) {
|
||||
let results = []
|
||||
let response = await client[methodName](params).promise()
|
||||
results = results.concat(response[resultsKey] || [])
|
||||
let response = await client.send(command)
|
||||
results = results.concat(response[resultsKey] || results)
|
||||
|
||||
while (response[nextResponseTokenKey]) {
|
||||
params[nextTokenKey] = response[nextResponseTokenKey]
|
||||
response = await client[methodName](params).promise()
|
||||
results = results.concat(response[resultsKey] || [])
|
||||
while (nextResponseTokenKey in response && response[nextResponseTokenKey]) {
|
||||
command.input[nextTokenKey] = response[nextResponseTokenKey]
|
||||
response = await client.send(command)
|
||||
results = results.concat(response[resultsKey])
|
||||
}
|
||||
|
||||
return results
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
],
|
||||
"main": "lib/serverless.js",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-acm": "3.953.0",
|
||||
"@aws-sdk/client-api-gateway": "3.953.0",
|
||||
"@aws-sdk/client-apigatewayv2": "3.953.0",
|
||||
"@aws-sdk/client-cloudformation": "3.953.0",
|
||||
@ -28,12 +29,15 @@
|
||||
"@aws-sdk/client-iam": "3.953.0",
|
||||
"@aws-sdk/client-iot": "3.953.0",
|
||||
"@aws-sdk/client-lambda": "3.953.0",
|
||||
"@aws-sdk/client-route-53": "3.953.0",
|
||||
"@aws-sdk/client-s3": "3.953.0",
|
||||
"@aws-sdk/client-sts": "3.953.0",
|
||||
"@aws-sdk/credential-providers": "3.953.0",
|
||||
"@aws-sdk/lib-storage": "3.953.0",
|
||||
"@iarna/toml": "^2.2.5",
|
||||
"@serverlessinc/sf-core": "*",
|
||||
"@smithy/node-http-handler": "^4.4.5",
|
||||
"@smithy/util-retry": "^4.2.6",
|
||||
"adm-zip": "^0.5.16",
|
||||
"ajv": "8.17.1",
|
||||
"ajv-formats": "2.1.1",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user