@digitraffic/common 2022.10.25-1 → 2022.10.28-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{aws → dist/aws}/infra/api/integration.d.ts +0 -0
- package/dist/aws/infra/api/integration.js +52 -0
- package/dist/aws/infra/api/integration.js.map +1 -0
- package/{aws → dist/aws}/infra/api/response.d.ts +0 -0
- package/dist/aws/infra/api/response.js +61 -0
- package/dist/aws/infra/api/response.js.map +1 -0
- package/{aws → dist/aws}/infra/api/responses.d.ts +3 -3
- package/dist/aws/infra/api/responses.js +82 -0
- package/dist/aws/infra/api/responses.js.map +1 -0
- package/{aws → dist/aws}/infra/api/static-integration.d.ts +0 -0
- package/dist/aws/infra/api/static-integration.js +54 -0
- package/dist/aws/infra/api/static-integration.js.map +1 -0
- package/{aws → dist/aws}/infra/canaries/canary-alarm.d.ts +0 -0
- package/dist/aws/infra/canaries/canary-alarm.js +26 -0
- package/dist/aws/infra/canaries/canary-alarm.js.map +1 -0
- package/dist/aws/infra/canaries/canary-keys.d.ts +3 -0
- package/dist/aws/infra/canaries/canary-keys.js +7 -0
- package/dist/aws/infra/canaries/canary-keys.js.map +1 -0
- package/{aws → dist/aws}/infra/canaries/canary-parameters.d.ts +0 -0
- package/dist/aws/infra/canaries/canary-parameters.js +3 -0
- package/dist/aws/infra/canaries/canary-parameters.js.map +1 -0
- package/{aws → dist/aws}/infra/canaries/canary-role.d.ts +0 -0
- package/dist/aws/infra/canaries/canary-role.js +46 -0
- package/dist/aws/infra/canaries/canary-role.js.map +1 -0
- package/{aws → dist/aws}/infra/canaries/canary.d.ts +0 -0
- package/dist/aws/infra/canaries/canary.js +32 -0
- package/dist/aws/infra/canaries/canary.js.map +1 -0
- package/{aws → dist/aws}/infra/canaries/database-canary.d.ts +0 -0
- package/dist/aws/infra/canaries/database-canary.js +70 -0
- package/dist/aws/infra/canaries/database-canary.js.map +1 -0
- package/{aws → dist/aws}/infra/canaries/database-checker.d.ts +2 -2
- package/dist/aws/infra/canaries/database-checker.js +103 -0
- package/dist/aws/infra/canaries/database-checker.js.map +1 -0
- package/{aws → dist/aws}/infra/canaries/url-canary.d.ts +0 -3
- package/dist/aws/infra/canaries/url-canary.js +47 -0
- package/dist/aws/infra/canaries/url-canary.js.map +1 -0
- package/{aws → dist/aws}/infra/canaries/url-checker.d.ts +0 -0
- package/dist/aws/infra/canaries/url-checker.js +252 -0
- package/dist/aws/infra/canaries/url-checker.js.map +1 -0
- package/{aws → dist/aws}/infra/documentation.d.ts +0 -0
- package/dist/aws/infra/documentation.js +95 -0
- package/dist/aws/infra/documentation.js.map +1 -0
- package/{aws → dist/aws}/infra/scheduler.d.ts +7 -7
- package/dist/aws/infra/scheduler.js +31 -0
- package/dist/aws/infra/scheduler.js.map +1 -0
- package/{aws → dist/aws}/infra/security-rule.d.ts +0 -0
- package/dist/aws/infra/security-rule.js +39 -0
- package/dist/aws/infra/security-rule.js.map +1 -0
- package/{aws → dist/aws}/infra/sqs-integration.d.ts +0 -0
- package/dist/aws/infra/sqs-integration.js +93 -0
- package/dist/aws/infra/sqs-integration.js.map +1 -0
- package/{aws → dist/aws}/infra/sqs-queue.d.ts +0 -0
- package/dist/aws/infra/sqs-queue.js +130 -0
- package/dist/aws/infra/sqs-queue.js.map +1 -0
- package/{aws → dist/aws}/infra/stack/lambda-configs.d.ts +5 -5
- package/dist/aws/infra/stack/lambda-configs.js +105 -0
- package/dist/aws/infra/stack/lambda-configs.js.map +1 -0
- package/{aws → dist/aws}/infra/stack/monitoredfunction.d.ts +1 -1
- package/dist/aws/infra/stack/monitoredfunction.js +143 -0
- package/dist/aws/infra/stack/monitoredfunction.js.map +1 -0
- package/{aws → dist/aws}/infra/stack/rest_apis.d.ts +0 -0
- package/dist/aws/infra/stack/rest_apis.js +185 -0
- package/dist/aws/infra/stack/rest_apis.js.map +1 -0
- package/{aws → dist/aws}/infra/stack/stack-checking-aspect.d.ts +0 -0
- package/dist/aws/infra/stack/stack-checking-aspect.js +174 -0
- package/dist/aws/infra/stack/stack-checking-aspect.js.map +1 -0
- package/{aws → dist/aws}/infra/stack/stack.d.ts +5 -4
- package/dist/aws/infra/stack/stack.js +67 -0
- package/dist/aws/infra/stack/stack.js.map +1 -0
- package/{aws → dist/aws}/infra/stack/subscription.d.ts +3 -3
- package/dist/aws/infra/stack/subscription.js +42 -0
- package/dist/aws/infra/stack/subscription.js.map +1 -0
- package/{aws → dist/aws}/infra/usage-plans.d.ts +0 -0
- package/dist/aws/infra/usage-plans.js +42 -0
- package/dist/aws/infra/usage-plans.js.map +1 -0
- package/{aws → dist/aws}/runtime/apikey.d.ts +0 -0
- package/dist/aws/runtime/apikey.js +13 -0
- package/dist/aws/runtime/apikey.js.map +1 -0
- package/{aws → dist/aws}/runtime/digitraffic-integration-response.d.ts +0 -0
- package/dist/aws/runtime/digitraffic-integration-response.js +26 -0
- package/dist/aws/runtime/digitraffic-integration-response.js.map +1 -0
- package/{aws → dist/aws}/runtime/environment.d.ts +0 -0
- package/dist/aws/runtime/environment.js +12 -0
- package/dist/aws/runtime/environment.js.map +1 -0
- package/{aws → dist/aws}/runtime/messaging.d.ts +0 -0
- package/dist/aws/runtime/messaging.js +31 -0
- package/dist/aws/runtime/messaging.js.map +1 -0
- package/{aws → dist/aws}/runtime/s3.d.ts +0 -0
- package/dist/aws/runtime/s3.js +30 -0
- package/dist/aws/runtime/s3.js.map +1 -0
- package/{aws → dist/aws}/runtime/secrets/dbsecret.d.ts +0 -0
- package/dist/aws/runtime/secrets/dbsecret.js +96 -0
- package/dist/aws/runtime/secrets/dbsecret.js.map +1 -0
- package/{aws → dist/aws}/runtime/secrets/proxy-holder.d.ts +0 -0
- package/dist/aws/runtime/secrets/proxy-holder.js +27 -0
- package/dist/aws/runtime/secrets/proxy-holder.js.map +1 -0
- package/{aws → dist/aws}/runtime/secrets/rds-holder.d.ts +0 -0
- package/dist/aws/runtime/secrets/rds-holder.js +27 -0
- package/dist/aws/runtime/secrets/rds-holder.js.map +1 -0
- package/{aws → dist/aws}/runtime/secrets/secret-holder.d.ts +0 -0
- package/dist/aws/runtime/secrets/secret-holder.js +76 -0
- package/dist/aws/runtime/secrets/secret-holder.js.map +1 -0
- package/{aws → dist/aws}/runtime/secrets/secret.d.ts +0 -0
- package/dist/aws/runtime/secrets/secret.js +43 -0
- package/dist/aws/runtime/secrets/secret.js.map +1 -0
- package/{aws → dist/aws}/types/errors.d.ts +4 -0
- package/dist/aws/types/errors.js +16 -0
- package/dist/aws/types/errors.js.map +1 -0
- package/{aws → dist/aws}/types/lambda-response.d.ts +4 -3
- package/dist/aws/types/lambda-response.js +33 -0
- package/dist/aws/types/lambda-response.js.map +1 -0
- package/{aws → dist/aws}/types/mediatypes.d.ts +1 -1
- package/dist/aws/types/mediatypes.js +16 -0
- package/dist/aws/types/mediatypes.js.map +1 -0
- package/{aws → dist/aws}/types/model-with-reference.d.ts +0 -0
- package/dist/aws/types/model-with-reference.js +3 -0
- package/dist/aws/types/model-with-reference.js.map +1 -0
- package/{aws → dist/aws}/types/proxytypes.d.ts +0 -0
- package/dist/aws/types/proxytypes.js +3 -0
- package/dist/aws/types/proxytypes.js.map +1 -0
- package/{aws → dist/aws}/types/tags.d.ts +0 -0
- package/dist/aws/types/tags.js +7 -0
- package/dist/aws/types/tags.js.map +1 -0
- package/{database → dist/database}/cached.d.ts +0 -0
- package/dist/database/cached.js +32 -0
- package/dist/database/cached.js.map +1 -0
- package/{database → dist/database}/database.d.ts +0 -0
- package/dist/database/database.js +70 -0
- package/dist/database/database.js.map +1 -0
- package/{database → dist/database}/last-updated.d.ts +0 -0
- package/dist/database/last-updated.js +54 -0
- package/dist/database/last-updated.js.map +1 -0
- package/{database → dist/database}/models.d.ts +0 -0
- package/dist/database/models.js +3 -0
- package/dist/database/models.js.map +1 -0
- package/{marine → dist/marine}/id_utils.d.ts +0 -0
- package/dist/marine/id_utils.js +33 -0
- package/dist/marine/id_utils.js.map +1 -0
- package/{marine → dist/marine}/rtz.d.ts +0 -0
- package/dist/marine/rtz.js +3 -0
- package/dist/marine/rtz.js.map +1 -0
- package/{test → dist/test}/asserter.d.ts +0 -0
- package/dist/test/asserter.js +45 -0
- package/dist/test/asserter.js.map +1 -0
- package/{test → dist/test}/db-testutils.d.ts +0 -0
- package/dist/test/db-testutils.js +31 -0
- package/dist/test/db-testutils.js.map +1 -0
- package/{test → dist/test}/httpserver.d.ts +2 -1
- package/dist/test/httpserver.js +74 -0
- package/dist/test/httpserver.js.map +1 -0
- package/{test → dist/test}/secret.d.ts +0 -0
- package/dist/test/secret.js +25 -0
- package/dist/test/secret.js.map +1 -0
- package/{test → dist/test}/secrets-manager.d.ts +0 -0
- package/dist/test/secrets-manager.js +59 -0
- package/dist/test/secrets-manager.js.map +1 -0
- package/{test → dist/test}/testutils.d.ts +0 -0
- package/dist/test/testutils.js +44 -0
- package/dist/test/testutils.js.map +1 -0
- package/dist/types/either.d.ts +9 -0
- package/dist/types/either.js +3 -0
- package/dist/types/either.js.map +1 -0
- package/{types → dist/types}/input-error.d.ts +0 -0
- package/dist/types/input-error.js +7 -0
- package/dist/types/input-error.js.map +1 -0
- package/{types → dist/types}/language.d.ts +0 -0
- package/dist/types/language.js +10 -0
- package/dist/types/language.js.map +1 -0
- package/{types → dist/types}/traffictype.d.ts +0 -0
- package/dist/types/traffictype.js +13 -0
- package/dist/types/traffictype.js.map +1 -0
- package/{types → dist/types}/validator.d.ts +0 -0
- package/dist/types/validator.js +14 -0
- package/dist/types/validator.js.map +1 -0
- package/{utils → dist/utils}/api-model.d.ts +0 -0
- package/dist/utils/api-model.js +129 -0
- package/dist/utils/api-model.js.map +1 -0
- package/{utils → dist/utils}/base64.d.ts +0 -0
- package/dist/utils/base64.js +21 -0
- package/dist/utils/base64.js.map +1 -0
- package/{utils → dist/utils}/date-utils.d.ts +0 -0
- package/dist/utils/date-utils.js +34 -0
- package/dist/utils/date-utils.js.map +1 -0
- package/{utils → dist/utils}/geojson-types.d.ts +0 -0
- package/dist/utils/geojson-types.js +18 -0
- package/dist/utils/geojson-types.js.map +1 -0
- package/{utils → dist/utils}/geometry.d.ts +0 -0
- package/dist/utils/geometry.js +164 -0
- package/dist/utils/geometry.js.map +1 -0
- package/{utils → dist/utils}/retry.d.ts +0 -0
- package/dist/utils/retry.js +50 -0
- package/dist/utils/retry.js.map +1 -0
- package/{utils → dist/utils}/slack.d.ts +0 -0
- package/dist/utils/slack.js +25 -0
- package/dist/utils/slack.js.map +1 -0
- package/{utils → dist/utils}/utils.d.ts +16 -0
- package/dist/utils/utils.js +75 -0
- package/dist/utils/utils.js.map +1 -0
- package/package.json +12 -10
- package/src/@types/geojson-validation/index.d.ts +4 -0
- package/src/aws/infra/api/integration.ts +73 -0
- package/src/aws/infra/api/response.ts +67 -0
- package/src/aws/infra/api/responses.ts +124 -0
- package/src/aws/infra/api/static-integration.ts +62 -0
- package/src/aws/infra/canaries/canary-alarm.ts +31 -0
- package/src/aws/infra/canaries/canary-keys.ts +3 -0
- package/src/aws/infra/canaries/canary-parameters.ts +19 -0
- package/src/aws/infra/canaries/canary-role.ts +47 -0
- package/src/aws/infra/canaries/canary.ts +46 -0
- package/src/aws/infra/canaries/database-canary.ts +98 -0
- package/src/aws/infra/canaries/database-checker.ts +155 -0
- package/src/aws/infra/canaries/url-canary.ts +74 -0
- package/src/aws/infra/canaries/url-checker.ts +366 -0
- package/src/aws/infra/documentation.ts +124 -0
- package/src/aws/infra/scheduler.ts +59 -0
- package/src/aws/infra/security-rule.ts +38 -0
- package/src/aws/infra/sqs-integration.ts +102 -0
- package/src/aws/infra/sqs-queue.ts +148 -0
- package/src/aws/infra/stack/lambda-configs.ts +207 -0
- package/src/aws/infra/stack/monitoredfunction.ts +342 -0
- package/src/aws/infra/stack/rest_apis.ts +223 -0
- package/src/aws/infra/stack/stack-checking-aspect.ts +279 -0
- package/src/aws/infra/stack/stack.ts +145 -0
- package/src/aws/infra/stack/subscription.ts +58 -0
- package/src/aws/infra/usage-plans.ts +41 -0
- package/src/aws/runtime/apikey.ts +9 -0
- package/src/aws/runtime/digitraffic-integration-response.ts +28 -0
- package/src/aws/runtime/environment.ts +9 -0
- package/src/aws/runtime/messaging.ts +26 -0
- package/src/aws/runtime/s3.ts +44 -0
- package/src/aws/runtime/secrets/dbsecret.ts +116 -0
- package/src/aws/runtime/secrets/proxy-holder.ts +37 -0
- package/src/aws/runtime/secrets/rds-holder.ts +33 -0
- package/src/aws/runtime/secrets/secret-holder.ts +116 -0
- package/src/aws/runtime/secrets/secret.ts +50 -0
- package/src/aws/types/errors.ts +14 -0
- package/src/aws/types/lambda-response.ts +43 -0
- package/src/aws/types/mediatypes.ts +11 -0
- package/src/aws/types/model-with-reference.ts +8 -0
- package/src/aws/types/proxytypes.ts +27 -0
- package/src/aws/types/tags.ts +3 -0
- package/src/database/cached.ts +35 -0
- package/src/database/database.ts +96 -0
- package/src/database/last-updated.ts +59 -0
- package/src/database/models.ts +7 -0
- package/src/marine/id_utils.ts +30 -0
- package/src/marine/rtz.ts +57 -0
- package/src/test/asserter.ts +48 -0
- package/src/test/db-testutils.ts +44 -0
- package/src/test/httpserver.ts +96 -0
- package/src/test/secret.ts +23 -0
- package/src/test/secrets-manager.ts +34 -0
- package/src/test/testutils.ts +39 -0
- package/src/types/either.ts +3 -0
- package/src/types/input-error.ts +2 -0
- package/src/types/language.ts +3 -0
- package/src/types/traffictype.ts +8 -0
- package/src/types/validator.ts +10 -0
- package/src/utils/api-model.ts +133 -0
- package/src/utils/base64.ts +16 -0
- package/src/utils/date-utils.ts +30 -0
- package/src/utils/geojson-types.ts +22 -0
- package/src/utils/geometry.ts +164 -0
- package/src/utils/retry.ts +49 -0
- package/src/utils/slack.ts +22 -0
- package/src/utils/utils.ts +105 -0
- package/aws/infra/api/integration.js +0 -52
- package/aws/infra/api/response.js +0 -61
- package/aws/infra/api/responses.js +0 -79
- package/aws/infra/api/static-integration.js +0 -54
- package/aws/infra/canaries/canary-alarm.js +0 -26
- package/aws/infra/canaries/canary-parameters.js +0 -3
- package/aws/infra/canaries/canary-role.js +0 -46
- package/aws/infra/canaries/canary.js +0 -32
- package/aws/infra/canaries/database-canary.js +0 -55
- package/aws/infra/canaries/database-checker.js +0 -109
- package/aws/infra/canaries/url-canary.js +0 -46
- package/aws/infra/canaries/url-checker.js +0 -238
- package/aws/infra/documentation.js +0 -95
- package/aws/infra/scheduler.js +0 -31
- package/aws/infra/security-rule.js +0 -39
- package/aws/infra/sqs-integration.js +0 -93
- package/aws/infra/sqs-queue.js +0 -130
- package/aws/infra/stack/lambda-configs.js +0 -93
- package/aws/infra/stack/monitoredfunction.js +0 -135
- package/aws/infra/stack/rest_apis.js +0 -185
- package/aws/infra/stack/stack-checking-aspect.js +0 -174
- package/aws/infra/stack/stack.js +0 -60
- package/aws/infra/stack/subscription.js +0 -41
- package/aws/infra/usage-plans.js +0 -42
- package/aws/runtime/apikey.js +0 -13
- package/aws/runtime/digitraffic-integration-response.js +0 -26
- package/aws/runtime/environment.js +0 -12
- package/aws/runtime/messaging.js +0 -31
- package/aws/runtime/s3.js +0 -30
- package/aws/runtime/secrets/dbsecret.js +0 -96
- package/aws/runtime/secrets/proxy-holder.js +0 -26
- package/aws/runtime/secrets/rds-holder.js +0 -26
- package/aws/runtime/secrets/secret-holder.js +0 -73
- package/aws/runtime/secrets/secret.js +0 -43
- package/aws/types/errors.js +0 -9
- package/aws/types/lambda-response.js +0 -28
- package/aws/types/mediatypes.js +0 -15
- package/aws/types/model-with-reference.js +0 -3
- package/aws/types/proxytypes.js +0 -3
- package/aws/types/tags.js +0 -7
- package/database/cached.js +0 -32
- package/database/database.js +0 -62
- package/database/last-updated.js +0 -54
- package/database/models.js +0 -3
- package/index.d.ts +0 -1
- package/index.js +0 -18
- package/marine/id_utils.js +0 -33
- package/marine/rtz.js +0 -3
- package/test/asserter.js +0 -45
- package/test/db-testutils.js +0 -31
- package/test/httpserver.js +0 -67
- package/test/secret.js +0 -25
- package/test/secrets-manager.js +0 -59
- package/test/testutils.js +0 -44
- package/types/input-error.js +0 -7
- package/types/language.js +0 -10
- package/types/traffictype.js +0 -13
- package/types/validator.js +0 -14
- package/utils/api-model.js +0 -129
- package/utils/base64.js +0 -21
- package/utils/date-utils.js +0 -34
- package/utils/geojson-types.js +0 -18
- package/utils/geometry.js +0 -140
- package/utils/retry.js +0 -50
- package/utils/slack.js +0 -25
- package/utils/utils.js +0 -64
@@ -0,0 +1,155 @@
|
|
1
|
+
import { DTDatabase, inDatabaseReadonly } from "../../../database/database";
|
2
|
+
import { ProxyHolder } from "../../runtime/secrets/proxy-holder";
|
3
|
+
import { RdsHolder } from "../../runtime/secrets/rds-holder";
|
4
|
+
import { getEnvVariable } from "../../../utils/utils";
|
5
|
+
|
6
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
7
|
+
const synthetics = require("Synthetics");
|
8
|
+
|
9
|
+
abstract class DatabaseCheck<T> {
|
10
|
+
readonly name: string;
|
11
|
+
readonly sql: string;
|
12
|
+
failed: boolean;
|
13
|
+
|
14
|
+
protected constructor(name: string, sql: string) {
|
15
|
+
this.name = name;
|
16
|
+
this.sql = sql;
|
17
|
+
this.failed = false;
|
18
|
+
}
|
19
|
+
|
20
|
+
abstract check(value: T): void;
|
21
|
+
}
|
22
|
+
|
23
|
+
// For backwards compatibility disable following rule for BaseResponse.
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
25
|
+
interface BaseResponse {}
|
26
|
+
|
27
|
+
interface CountResponse extends BaseResponse {
|
28
|
+
count: number;
|
29
|
+
}
|
30
|
+
|
31
|
+
class CountDatabaseCheck extends DatabaseCheck<CountResponse> {
|
32
|
+
readonly minCount: number | null;
|
33
|
+
readonly maxCount: number | null;
|
34
|
+
|
35
|
+
constructor(
|
36
|
+
name: string,
|
37
|
+
sql: string,
|
38
|
+
minCount: number | null,
|
39
|
+
maxCount: number | null
|
40
|
+
) {
|
41
|
+
super(name, sql);
|
42
|
+
|
43
|
+
if (minCount == null && maxCount == null) {
|
44
|
+
throw new Error("no max or min given!");
|
45
|
+
}
|
46
|
+
|
47
|
+
this.minCount = minCount;
|
48
|
+
this.maxCount = maxCount;
|
49
|
+
}
|
50
|
+
|
51
|
+
check(value: CountResponse) {
|
52
|
+
if (!value) {
|
53
|
+
this.failed = true;
|
54
|
+
throw new Error("no return value");
|
55
|
+
} else {
|
56
|
+
if ("count" in value) {
|
57
|
+
if (this.minCount && value.count < this.minCount) {
|
58
|
+
this.failed = true;
|
59
|
+
throw new Error(
|
60
|
+
`count was ${value.count}, minimum is ${this.minCount}`
|
61
|
+
);
|
62
|
+
}
|
63
|
+
if (this.maxCount && value.count > this.maxCount) {
|
64
|
+
this.failed = true;
|
65
|
+
throw new Error(
|
66
|
+
`count was ${value.count}, max is ${this.maxCount}`
|
67
|
+
);
|
68
|
+
}
|
69
|
+
} else {
|
70
|
+
this.failed = true;
|
71
|
+
|
72
|
+
console.info("received " + JSON.stringify(value));
|
73
|
+
|
74
|
+
throw new Error("no count available");
|
75
|
+
}
|
76
|
+
}
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
const stepConfig = {
|
81
|
+
continueOnStepFailure: true,
|
82
|
+
screenshotOnStepStart: false,
|
83
|
+
screenshotOnStepSuccess: false,
|
84
|
+
screenshotOnStepFailure: false,
|
85
|
+
};
|
86
|
+
|
87
|
+
export class DatabaseChecker {
|
88
|
+
credentialsFunction: () => Promise<void>;
|
89
|
+
checks: DatabaseCheck<BaseResponse>[];
|
90
|
+
|
91
|
+
private constructor(credentialsFunction: () => Promise<void>) {
|
92
|
+
this.credentialsFunction = credentialsFunction;
|
93
|
+
this.checks = [];
|
94
|
+
|
95
|
+
synthetics.getConfiguration().disableRequestMetrics();
|
96
|
+
|
97
|
+
synthetics.getConfiguration().withFailedCanaryMetric(true);
|
98
|
+
}
|
99
|
+
|
100
|
+
static createForProxy() {
|
101
|
+
return new DatabaseChecker(() =>
|
102
|
+
new ProxyHolder(getEnvVariable("SECRET_ID")).setCredentials()
|
103
|
+
);
|
104
|
+
}
|
105
|
+
|
106
|
+
static createForRds() {
|
107
|
+
return new DatabaseChecker(() =>
|
108
|
+
new RdsHolder(getEnvVariable("SECRET_ID")).setCredentials()
|
109
|
+
);
|
110
|
+
}
|
111
|
+
|
112
|
+
one(name: string, sql: string) {
|
113
|
+
this.checks.push(new CountDatabaseCheck(name, sql, 1, 1));
|
114
|
+
|
115
|
+
return this;
|
116
|
+
}
|
117
|
+
|
118
|
+
empty(name: string, sql: string) {
|
119
|
+
this.checks.push(new CountDatabaseCheck(name, sql, null, 0));
|
120
|
+
|
121
|
+
return this;
|
122
|
+
}
|
123
|
+
|
124
|
+
notEmpty(name: string, sql: string) {
|
125
|
+
this.checks.push(new CountDatabaseCheck(name, sql, 1, null));
|
126
|
+
|
127
|
+
return this;
|
128
|
+
}
|
129
|
+
|
130
|
+
async expect() {
|
131
|
+
if (!this.checks.length) {
|
132
|
+
throw new Error("No checks");
|
133
|
+
}
|
134
|
+
|
135
|
+
await this.credentialsFunction();
|
136
|
+
await inDatabaseReadonly(async (db: DTDatabase) => {
|
137
|
+
for (const check of this.checks) {
|
138
|
+
console.info("canary checking sql " + check.sql);
|
139
|
+
|
140
|
+
const value = await db.oneOrNone(check.sql);
|
141
|
+
const checkFunction = () => {
|
142
|
+
check.check(value);
|
143
|
+
};
|
144
|
+
|
145
|
+
synthetics.executeStep(check.name, checkFunction, stepConfig);
|
146
|
+
}
|
147
|
+
});
|
148
|
+
|
149
|
+
if (this.checks.some((check) => check.failed)) {
|
150
|
+
throw new Error("Failed");
|
151
|
+
}
|
152
|
+
|
153
|
+
return "OK";
|
154
|
+
}
|
155
|
+
}
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import { Construct } from "constructs";
|
2
|
+
import { CanaryParameters } from "./canary-parameters";
|
3
|
+
import { Role } from "aws-cdk-lib/aws-iam";
|
4
|
+
import { DigitrafficCanary } from "./canary";
|
5
|
+
import { ISecret } from "aws-cdk-lib/aws-secretsmanager";
|
6
|
+
import { DigitrafficStack } from "../stack/stack";
|
7
|
+
import { LambdaEnvironment } from "../stack/lambda-configs";
|
8
|
+
import { DigitrafficRestApi } from "../stack/rest_apis";
|
9
|
+
import { ENV_API_KEY, ENV_HOSTNAME, ENV_SECRET } from "./canary-keys";
|
10
|
+
|
11
|
+
export interface UrlCanaryParameters extends CanaryParameters {
|
12
|
+
readonly hostname: string;
|
13
|
+
readonly apiKeyId?: string;
|
14
|
+
}
|
15
|
+
|
16
|
+
export class UrlCanary extends DigitrafficCanary {
|
17
|
+
constructor(
|
18
|
+
stack: Construct,
|
19
|
+
role: Role,
|
20
|
+
params: UrlCanaryParameters,
|
21
|
+
secret?: ISecret
|
22
|
+
) {
|
23
|
+
const canaryName = `${params.name}-url`;
|
24
|
+
const environmentVariables: LambdaEnvironment = {};
|
25
|
+
environmentVariables[ENV_HOSTNAME] = params.hostname;
|
26
|
+
|
27
|
+
if (params.secret) {
|
28
|
+
environmentVariables[ENV_SECRET] = params.secret;
|
29
|
+
}
|
30
|
+
|
31
|
+
if (params.apiKeyId) {
|
32
|
+
environmentVariables[ENV_API_KEY] = params.apiKeyId;
|
33
|
+
}
|
34
|
+
|
35
|
+
if (secret) {
|
36
|
+
secret.grantRead(role);
|
37
|
+
}
|
38
|
+
|
39
|
+
// the handler code is defined at the actual project using this
|
40
|
+
super(stack, canaryName, role, params, environmentVariables);
|
41
|
+
}
|
42
|
+
|
43
|
+
static create(
|
44
|
+
stack: DigitrafficStack,
|
45
|
+
role: Role,
|
46
|
+
publicApi: DigitrafficRestApi,
|
47
|
+
params: Partial<UrlCanaryParameters>
|
48
|
+
): UrlCanary {
|
49
|
+
return new UrlCanary(stack, role, {
|
50
|
+
...{
|
51
|
+
handler: `${params.name}.handler`,
|
52
|
+
hostname: publicApi.hostname(),
|
53
|
+
apiKeyId: this.getApiKey(publicApi),
|
54
|
+
},
|
55
|
+
...params,
|
56
|
+
} as UrlCanaryParameters);
|
57
|
+
}
|
58
|
+
|
59
|
+
static getApiKey(publicApi: DigitrafficRestApi): string | undefined {
|
60
|
+
const apiKeys = publicApi.apiKeyIds;
|
61
|
+
|
62
|
+
if (apiKeys.length > 1) {
|
63
|
+
console.info("rest api has more than one api key");
|
64
|
+
}
|
65
|
+
|
66
|
+
if (apiKeys.length === 0) {
|
67
|
+
console.info("rest api has no api keys");
|
68
|
+
return undefined;
|
69
|
+
}
|
70
|
+
|
71
|
+
// always use first api key
|
72
|
+
return publicApi.apiKeyIds[0];
|
73
|
+
}
|
74
|
+
}
|
@@ -0,0 +1,366 @@
|
|
1
|
+
import { IncomingMessage, RequestOptions } from "http";
|
2
|
+
import { Asserter } from "../../../test/asserter";
|
3
|
+
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
5
|
+
const synthetics = require("Synthetics");
|
6
|
+
import zlib = require("zlib");
|
7
|
+
import { MediaType } from "../../types/mediatypes";
|
8
|
+
import { getApiKeyFromAPIGateway } from "../../runtime/apikey";
|
9
|
+
import { FeatureCollection } from "geojson";
|
10
|
+
import { isValidGeoJson } from "../../../utils/geometry";
|
11
|
+
import { getEnvVariable } from "../../../utils/utils";
|
12
|
+
import { ENV_API_KEY, ENV_HOSTNAME } from "./canary-keys";
|
13
|
+
|
14
|
+
export const API_KEY_HEADER = "x-api-key";
|
15
|
+
|
16
|
+
const baseHeaders = {
|
17
|
+
"Digitraffic-User": "internal-digitraffic-canary",
|
18
|
+
"Accept-Encoding": "gzip",
|
19
|
+
Accept: "*/*",
|
20
|
+
} as Record<string, string>;
|
21
|
+
|
22
|
+
type CheckerFunction = (Res: IncomingMessage) => void;
|
23
|
+
type JsonCheckerFunction<T> = (
|
24
|
+
json: T,
|
25
|
+
body: string,
|
26
|
+
message: IncomingMessage
|
27
|
+
) => void;
|
28
|
+
|
29
|
+
export class UrlChecker {
|
30
|
+
private readonly requestOptions: RequestOptions;
|
31
|
+
|
32
|
+
constructor(hostname: string, apiKey?: string) {
|
33
|
+
const headers = { ...baseHeaders };
|
34
|
+
|
35
|
+
if (apiKey) {
|
36
|
+
headers[API_KEY_HEADER] = apiKey;
|
37
|
+
}
|
38
|
+
|
39
|
+
this.requestOptions = {
|
40
|
+
hostname,
|
41
|
+
method: "GET",
|
42
|
+
protocol: "https:",
|
43
|
+
headers,
|
44
|
+
};
|
45
|
+
|
46
|
+
synthetics.getConfiguration().disableRequestMetrics();
|
47
|
+
|
48
|
+
synthetics
|
49
|
+
.getConfiguration()
|
50
|
+
.withIncludeRequestBody(false)
|
51
|
+
.withIncludeRequestHeaders(false)
|
52
|
+
.withIncludeResponseBody(false)
|
53
|
+
.withIncludeResponseHeaders(false)
|
54
|
+
.withFailedCanaryMetric(true);
|
55
|
+
}
|
56
|
+
|
57
|
+
static create(hostname: string, apiKeyId: string): Promise<UrlChecker> {
|
58
|
+
return getApiKeyFromAPIGateway(apiKeyId).then((apiKey) => {
|
59
|
+
return new UrlChecker(hostname, apiKey.value);
|
60
|
+
});
|
61
|
+
}
|
62
|
+
|
63
|
+
static createV2(): Promise<UrlChecker> {
|
64
|
+
return this.create(
|
65
|
+
getEnvVariable(ENV_HOSTNAME),
|
66
|
+
getEnvVariable(ENV_API_KEY)
|
67
|
+
);
|
68
|
+
}
|
69
|
+
|
70
|
+
expectStatus<T>(
|
71
|
+
statusCode: number,
|
72
|
+
url: string,
|
73
|
+
callback: JsonCheckerFunction<T>
|
74
|
+
): Promise<void> {
|
75
|
+
const requestOptions = {
|
76
|
+
...this.requestOptions,
|
77
|
+
...{
|
78
|
+
path: url,
|
79
|
+
},
|
80
|
+
};
|
81
|
+
|
82
|
+
return synthetics.executeHttpStep(
|
83
|
+
`Verify ${statusCode} for ${url.replace(/auth=.*/, "")}`,
|
84
|
+
requestOptions,
|
85
|
+
callback
|
86
|
+
);
|
87
|
+
}
|
88
|
+
|
89
|
+
expect200<T>(
|
90
|
+
url: string,
|
91
|
+
...callbacks: JsonCheckerFunction<T>[]
|
92
|
+
): Promise<void> {
|
93
|
+
const callback = async (
|
94
|
+
json: T,
|
95
|
+
body: string,
|
96
|
+
res: IncomingMessage
|
97
|
+
) => {
|
98
|
+
await Promise.allSettled(callbacks.map((c) => c(json, body, res)));
|
99
|
+
};
|
100
|
+
|
101
|
+
return this.expectStatus(200, url, callback);
|
102
|
+
}
|
103
|
+
|
104
|
+
expect404(url: string): Promise<void> {
|
105
|
+
const requestOptions = {
|
106
|
+
...this.requestOptions,
|
107
|
+
...{
|
108
|
+
path: url,
|
109
|
+
},
|
110
|
+
};
|
111
|
+
|
112
|
+
return synthetics.executeHttpStep(
|
113
|
+
`Verify 404 for ${url}`,
|
114
|
+
requestOptions,
|
115
|
+
validateStatusCodeAndContentType(404, MediaType.TEXT_PLAIN)
|
116
|
+
);
|
117
|
+
}
|
118
|
+
|
119
|
+
expect400(url: string): Promise<void> {
|
120
|
+
const requestOptions = {
|
121
|
+
...this.requestOptions,
|
122
|
+
...{
|
123
|
+
path: url,
|
124
|
+
},
|
125
|
+
};
|
126
|
+
|
127
|
+
return synthetics.executeHttpStep(
|
128
|
+
`Verify 400 for ${url}`,
|
129
|
+
requestOptions,
|
130
|
+
validateStatusCodeAndContentType(400, MediaType.TEXT_PLAIN)
|
131
|
+
);
|
132
|
+
}
|
133
|
+
|
134
|
+
expect403WithoutApiKey(url: string, mediaType?: MediaType): Promise<void> {
|
135
|
+
if (
|
136
|
+
!this.requestOptions.headers ||
|
137
|
+
!this.requestOptions.headers[API_KEY_HEADER]
|
138
|
+
) {
|
139
|
+
console.error("No api key defined");
|
140
|
+
}
|
141
|
+
|
142
|
+
const requestOptions = {
|
143
|
+
...this.requestOptions,
|
144
|
+
...{
|
145
|
+
path: url,
|
146
|
+
headers: baseHeaders,
|
147
|
+
},
|
148
|
+
};
|
149
|
+
|
150
|
+
return synthetics.executeHttpStep(
|
151
|
+
`Verify 403 for ${url}`,
|
152
|
+
requestOptions,
|
153
|
+
validateStatusCodeAndContentType(
|
154
|
+
403,
|
155
|
+
mediaType || MediaType.APPLICATION_JSON
|
156
|
+
)
|
157
|
+
);
|
158
|
+
}
|
159
|
+
|
160
|
+
done(): string {
|
161
|
+
return "Canary successful";
|
162
|
+
}
|
163
|
+
}
|
164
|
+
|
165
|
+
async function getResponseBody(response: IncomingMessage): Promise<string> {
|
166
|
+
const body = await getBodyFromResponse(response);
|
167
|
+
|
168
|
+
if (response.headers["content-encoding"] === "gzip") {
|
169
|
+
try {
|
170
|
+
return zlib.gunzipSync(body).toString();
|
171
|
+
} catch (e) {
|
172
|
+
console.info("error " + JSON.stringify(e));
|
173
|
+
}
|
174
|
+
}
|
175
|
+
|
176
|
+
return body.toString();
|
177
|
+
}
|
178
|
+
|
179
|
+
function getBodyFromResponse(response: IncomingMessage): Promise<string> {
|
180
|
+
return new Promise((resolve: (value: string) => void) => {
|
181
|
+
const buffers: Buffer[] = [];
|
182
|
+
|
183
|
+
response.on("data", (data: Buffer) => {
|
184
|
+
buffers.push(data);
|
185
|
+
});
|
186
|
+
|
187
|
+
response.on("end", () => {
|
188
|
+
resolve(Buffer.concat(buffers).toString());
|
189
|
+
});
|
190
|
+
});
|
191
|
+
}
|
192
|
+
|
193
|
+
/**
|
194
|
+
* Returns function, that validates that the status code and content-type from response are the given values
|
195
|
+
* @param statusCode
|
196
|
+
* @param contentType
|
197
|
+
*/
|
198
|
+
function validateStatusCodeAndContentType(
|
199
|
+
statusCode: number,
|
200
|
+
contentType: MediaType
|
201
|
+
): (Res: IncomingMessage) => Promise<void> {
|
202
|
+
return (res: IncomingMessage) => {
|
203
|
+
return new Promise((resolve) => {
|
204
|
+
if (res.statusCode !== statusCode) {
|
205
|
+
throw new Error(`${res.statusCode} ${res.statusMessage}`);
|
206
|
+
}
|
207
|
+
|
208
|
+
if (res.headers["content-type"] !== contentType) {
|
209
|
+
throw new Error(
|
210
|
+
"Wrong content-type " + res.headers["content-type"]
|
211
|
+
);
|
212
|
+
}
|
213
|
+
|
214
|
+
resolve();
|
215
|
+
});
|
216
|
+
};
|
217
|
+
}
|
218
|
+
|
219
|
+
// DEPRECATED
|
220
|
+
export class ResponseChecker {
|
221
|
+
private readonly contentType;
|
222
|
+
private checkCors = true;
|
223
|
+
|
224
|
+
constructor(contentType: string) {
|
225
|
+
this.contentType = contentType;
|
226
|
+
}
|
227
|
+
|
228
|
+
static forJson(): ResponseChecker {
|
229
|
+
return new ResponseChecker(MediaType.APPLICATION_JSON);
|
230
|
+
}
|
231
|
+
|
232
|
+
static forCSV(): ResponseChecker {
|
233
|
+
return new ResponseChecker(MediaType.TEXT_CSV);
|
234
|
+
}
|
235
|
+
|
236
|
+
static forGeojson(): ResponseChecker {
|
237
|
+
return new ResponseChecker(MediaType.APPLICATION_GEOJSON);
|
238
|
+
}
|
239
|
+
|
240
|
+
static forJpeg(): ResponseChecker {
|
241
|
+
return new ResponseChecker(MediaType.IMAGE_JPEG);
|
242
|
+
}
|
243
|
+
|
244
|
+
check(): CheckerFunction {
|
245
|
+
return this.responseChecker(() => {
|
246
|
+
// no need to do anything
|
247
|
+
});
|
248
|
+
}
|
249
|
+
|
250
|
+
checkJson<T>(
|
251
|
+
fn: (json: T, body: string, res: IncomingMessage) => void
|
252
|
+
): CheckerFunction {
|
253
|
+
return this.responseChecker((body: string, res: IncomingMessage) => {
|
254
|
+
fn(JSON.parse(body), body, res);
|
255
|
+
});
|
256
|
+
}
|
257
|
+
|
258
|
+
responseChecker(
|
259
|
+
fn: (body: string, res: IncomingMessage) => void
|
260
|
+
): CheckerFunction {
|
261
|
+
return async (res: IncomingMessage): Promise<void> => {
|
262
|
+
if (!res.statusCode) {
|
263
|
+
throw new Error("statusCode missing");
|
264
|
+
}
|
265
|
+
|
266
|
+
if (res.statusCode < 200 || res.statusCode > 299) {
|
267
|
+
throw new Error(`${res.statusCode} ${res.statusMessage}`);
|
268
|
+
}
|
269
|
+
|
270
|
+
if (this.checkCors && !res.headers["access-control-allow-origin"]) {
|
271
|
+
throw new Error("CORS missing");
|
272
|
+
}
|
273
|
+
|
274
|
+
if (res.headers["content-type"] !== this.contentType) {
|
275
|
+
throw new Error(
|
276
|
+
"Wrong content-type " + res.headers["content-type"]
|
277
|
+
);
|
278
|
+
}
|
279
|
+
|
280
|
+
const body = await getResponseBody(res);
|
281
|
+
|
282
|
+
fn(body, res);
|
283
|
+
};
|
284
|
+
}
|
285
|
+
}
|
286
|
+
|
287
|
+
export class ContentChecker {
|
288
|
+
static checkJson<T>(
|
289
|
+
fn: (json: T, body: string, res: IncomingMessage) => void
|
290
|
+
): CheckerFunction {
|
291
|
+
return async (res: IncomingMessage): Promise<void> => {
|
292
|
+
const body = await getResponseBody(res);
|
293
|
+
|
294
|
+
fn(JSON.parse(body), body, res);
|
295
|
+
};
|
296
|
+
}
|
297
|
+
|
298
|
+
static checkResponse(
|
299
|
+
fn: (body: string, res: IncomingMessage) => void
|
300
|
+
): CheckerFunction {
|
301
|
+
return async (res: IncomingMessage): Promise<void> => {
|
302
|
+
const body = await getResponseBody(res);
|
303
|
+
|
304
|
+
fn(body, res);
|
305
|
+
};
|
306
|
+
}
|
307
|
+
}
|
308
|
+
|
309
|
+
export class ContentTypeChecker {
|
310
|
+
static checkContentType(contentType: MediaType) {
|
311
|
+
return (res: IncomingMessage) => {
|
312
|
+
if (!res.statusCode) {
|
313
|
+
throw new Error("statusCode missing");
|
314
|
+
}
|
315
|
+
|
316
|
+
if (res.statusCode < 200 || res.statusCode > 299) {
|
317
|
+
throw new Error(`${res.statusCode} ${res.statusMessage}`);
|
318
|
+
}
|
319
|
+
|
320
|
+
if (!res.headers["access-control-allow-origin"]) {
|
321
|
+
throw new Error("CORS missing");
|
322
|
+
}
|
323
|
+
|
324
|
+
if (res.headers["content-type"] !== contentType) {
|
325
|
+
throw new Error(
|
326
|
+
"Wrong content-type " + res.headers["content-type"]
|
327
|
+
);
|
328
|
+
}
|
329
|
+
};
|
330
|
+
}
|
331
|
+
}
|
332
|
+
|
333
|
+
export class GeoJsonChecker {
|
334
|
+
static validFeatureCollection(
|
335
|
+
fn?: (json: FeatureCollection) => void
|
336
|
+
): CheckerFunction {
|
337
|
+
return ResponseChecker.forGeojson().checkJson(
|
338
|
+
(json: FeatureCollection) => {
|
339
|
+
Asserter.assertEquals(json.type, "FeatureCollection");
|
340
|
+
Asserter.assertTrue(isValidGeoJson(json));
|
341
|
+
|
342
|
+
if (fn) {
|
343
|
+
fn(json);
|
344
|
+
}
|
345
|
+
}
|
346
|
+
);
|
347
|
+
}
|
348
|
+
}
|
349
|
+
|
350
|
+
export class HeaderChecker {
|
351
|
+
static checkHeaderExists(headerName: string): CheckerFunction {
|
352
|
+
return (res: IncomingMessage) => {
|
353
|
+
if (!res.headers[headerName]) {
|
354
|
+
throw new Error("Missing header: " + headerName);
|
355
|
+
}
|
356
|
+
};
|
357
|
+
}
|
358
|
+
|
359
|
+
static checkHeaderMissing(headerName: string): CheckerFunction {
|
360
|
+
return (res: IncomingMessage) => {
|
361
|
+
if (res.headers[headerName]) {
|
362
|
+
throw new Error("Header should not exist: " + headerName);
|
363
|
+
}
|
364
|
+
};
|
365
|
+
}
|
366
|
+
}
|