dcl-ops-lib 9.7.0 → 9.9.0
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/README.md +7 -0
- package/StaticWebsite.d.ts +9 -0
- package/buildStatic.js +13 -3
- package/createFargateTask.d.ts +37 -16
- package/createFargateTask.js +68 -16
- package/package.json +3 -5
package/README.md
CHANGED
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
Used to compile pulumi projects
|
|
4
4
|
|
|
5
|
+
## Releases
|
|
6
|
+
|
|
7
|
+
Published to npm as `dcl-ops-lib` by GitHub Actions (`.github/workflows/release.yml`)
|
|
8
|
+
via semantic-release, using npm OIDC trusted publishing:
|
|
9
|
+
|
|
10
|
+
- push to `master` → stable release on the `latest` dist-tag
|
|
11
|
+
- push to `next` → prerelease on the `next` dist-tag
|
|
5
12
|
|
|
6
13
|
# License
|
|
7
14
|
Published under Apache-2.0
|
package/StaticWebsite.d.ts
CHANGED
|
@@ -33,4 +33,13 @@ export type StaticWebsite = {
|
|
|
33
33
|
responseHeadersPolicyId?: Input<string>;
|
|
34
34
|
objectOwnership?: string;
|
|
35
35
|
overrideContentBucketACL?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Tags applied to the content bucket, logs bucket and CloudFront distribution.
|
|
38
|
+
* Optional: when omitted, no tags are set by buildStatic (existing behavior).
|
|
39
|
+
*
|
|
40
|
+
* When provided, each resource receives a default `Name` derived from the domain
|
|
41
|
+
* (content bucket & distribution: `<domain>`, logs bucket: `<domain>-logs`); a
|
|
42
|
+
* `Name` supplied here overrides that default.
|
|
43
|
+
*/
|
|
44
|
+
tags?: Record<string, Input<string>>;
|
|
36
45
|
};
|
package/buildStatic.js
CHANGED
|
@@ -20,6 +20,13 @@ function buildStatic(staticSite) {
|
|
|
20
20
|
additionalDomains: staticSite.additionalDomains ? staticSite.additionalDomains : [],
|
|
21
21
|
};
|
|
22
22
|
const slug = staticSite.domain.replace(/\./g, "-") + "-";
|
|
23
|
+
// Tags for each resource. When the caller opts into tagging we default a per-resource
|
|
24
|
+
// `Name` derived from the domain (caller-provided `Name` wins). When `tags` is omitted
|
|
25
|
+
// the value stays `undefined`, preserving the original untagged behavior.
|
|
26
|
+
const makeTags = (name) => staticSite.tags && { Name: name, ...staticSite.tags };
|
|
27
|
+
const contentBucketTags = makeTags(staticSite.domain);
|
|
28
|
+
const logsBucketTags = makeTags(`${staticSite.domain}-logs`);
|
|
29
|
+
const cdnTags = makeTags(staticSite.domain);
|
|
23
30
|
// contentBucket is the S3 bucket that the website's contents will be stored in.
|
|
24
31
|
const bucketInfo = {
|
|
25
32
|
acl: staticSite.overrideContentBucketACL ? staticSite.overrideContentBucketACL : "public-read",
|
|
@@ -29,7 +36,8 @@ function buildStatic(staticSite) {
|
|
|
29
36
|
indexDocument: "index.html",
|
|
30
37
|
errorDocument: staticSite.defaultPath ?? "404.html",
|
|
31
38
|
},
|
|
32
|
-
forceDestroy: staticSite.destroy === true
|
|
39
|
+
forceDestroy: staticSite.destroy === true,
|
|
40
|
+
tags: contentBucketTags,
|
|
33
41
|
};
|
|
34
42
|
if (staticSite.corsRules !== undefined) {
|
|
35
43
|
Object.assign(bucketInfo, { corsRules: staticSite.corsRules });
|
|
@@ -48,7 +56,8 @@ function buildStatic(staticSite) {
|
|
|
48
56
|
// logsBucket is an S3 bucket that will contain the CDN's request logs.
|
|
49
57
|
const logsBucket = new aws.s3.Bucket(slug + "logs", {
|
|
50
58
|
acl: "private",
|
|
51
|
-
forceDestroy: staticSite.destroy === true
|
|
59
|
+
forceDestroy: staticSite.destroy === true,
|
|
60
|
+
tags: logsBucketTags,
|
|
52
61
|
}, {
|
|
53
62
|
protect,
|
|
54
63
|
});
|
|
@@ -96,7 +105,7 @@ function buildStatic(staticSite) {
|
|
|
96
105
|
// "All" is the most broad distribution, and also the most expensive.
|
|
97
106
|
// "100" is the least broad, and also the least expensive.
|
|
98
107
|
priceClass: staticSite.priceClass || "PriceClass_100",
|
|
99
|
-
// You can customize error responses. When CloudFront
|
|
108
|
+
// You can customize error responses. When CloudFront receives an error from the origin (e.g. S3 or some other
|
|
100
109
|
// web service) it can return a different error code, and return the response for a different resource.
|
|
101
110
|
customErrorResponses: [{ errorCode: 404, responseCode: 404, responsePagePath: "/404.html" }],
|
|
102
111
|
restrictions: {
|
|
@@ -113,6 +122,7 @@ function buildStatic(staticSite) {
|
|
|
113
122
|
includeCookies: false,
|
|
114
123
|
prefix: `${config.targetDomain}/`,
|
|
115
124
|
},
|
|
125
|
+
tags: cdnTags,
|
|
116
126
|
};
|
|
117
127
|
const cdn = new aws.cloudfront.Distribution(slug + "cdn", distributionArgs);
|
|
118
128
|
// Creates a new Route53 DNS record pointing the domain to the CloudFront distribution.
|
package/createFargateTask.d.ts
CHANGED
|
@@ -76,14 +76,7 @@ export type FargateTaskOptions = {
|
|
|
76
76
|
appAutoscaling?: {
|
|
77
77
|
maxCapacity: number;
|
|
78
78
|
minCapacity?: number;
|
|
79
|
-
policy?:
|
|
80
|
-
metricName: string;
|
|
81
|
-
targetValue: number;
|
|
82
|
-
metricDimensionValue: pulumi.Output<string>;
|
|
83
|
-
statistic: "Average" | "Minimum" | "Maximum";
|
|
84
|
-
scaleOutCooldown: number;
|
|
85
|
-
scaleInCooldown: number;
|
|
86
|
-
}[];
|
|
79
|
+
policy?: AppAutoscalingPolicy[];
|
|
87
80
|
scheduleAction?: {
|
|
88
81
|
minCapacity: number;
|
|
89
82
|
maxCapacity: number;
|
|
@@ -99,6 +92,41 @@ export type FargateTaskOptions = {
|
|
|
99
92
|
};
|
|
100
93
|
enableExecuteCommand?: boolean;
|
|
101
94
|
};
|
|
95
|
+
/**
|
|
96
|
+
* One ECS Service Application-Auto-Scaling target-tracking policy.
|
|
97
|
+
*
|
|
98
|
+
* Tracks `metricName` (today only `ApproximateNumberOfMessagesVisible` is
|
|
99
|
+
* understood as an SQS queue depth — anything else falls through with no
|
|
100
|
+
* `customizedMetricSpecification` set) against `targetValue`. Required
|
|
101
|
+
* cooldowns are enforced by AWS.
|
|
102
|
+
*
|
|
103
|
+
* Choose ONE of:
|
|
104
|
+
* - `metricDimensionValue`: a single SQS queue URL. The policy tracks that
|
|
105
|
+
* queue's depth directly.
|
|
106
|
+
* - `metricDimensionValues`: 2+ SQS queue URLs. The policy uses CloudWatch
|
|
107
|
+
* metric math to track the SUM of their depths under one signal — useful
|
|
108
|
+
* when several queues feed the same worker pool and the desired pod count
|
|
109
|
+
* must reflect total pending work, not the max of any one queue. (AWS's
|
|
110
|
+
* default with N parallel target-tracking policies is max-of-all, which
|
|
111
|
+
* undercounts when multiple queues have load simultaneously.)
|
|
112
|
+
*
|
|
113
|
+
* Setting both fields, or neither, throws at apply time.
|
|
114
|
+
*/
|
|
115
|
+
export type AppAutoscalingPolicy = {
|
|
116
|
+
metricName: string;
|
|
117
|
+
targetValue: number;
|
|
118
|
+
/** Single-queue form. Mutually exclusive with `metricDimensionValues`. */
|
|
119
|
+
metricDimensionValue?: pulumi.Output<string>;
|
|
120
|
+
/**
|
|
121
|
+
* Multi-queue (sum) form. Mutually exclusive with `metricDimensionValue`.
|
|
122
|
+
* Must contain ≥1 entry; with a single entry, prefer `metricDimensionValue`
|
|
123
|
+
* for clarity.
|
|
124
|
+
*/
|
|
125
|
+
metricDimensionValues?: pulumi.Output<string>[];
|
|
126
|
+
statistic: "Average" | "Minimum" | "Maximum";
|
|
127
|
+
scaleOutCooldown: number;
|
|
128
|
+
scaleInCooldown: number;
|
|
129
|
+
};
|
|
102
130
|
/**
|
|
103
131
|
*
|
|
104
132
|
* @param serviceName A name for this service. For example, "builder-api"
|
|
@@ -152,14 +180,7 @@ export type InternalServiceOptions = {
|
|
|
152
180
|
appAutoscaling?: {
|
|
153
181
|
maxCapacity: number;
|
|
154
182
|
minCapacity?: number;
|
|
155
|
-
policy?:
|
|
156
|
-
metricName: string;
|
|
157
|
-
targetValue: number;
|
|
158
|
-
metricDimensionValue: pulumi.Output<string>;
|
|
159
|
-
statistic: "Average" | "Minimum" | "Maximum";
|
|
160
|
-
scaleOutCooldown: number;
|
|
161
|
-
scaleInCooldown: number;
|
|
162
|
-
}[];
|
|
183
|
+
policy?: AppAutoscalingPolicy[];
|
|
163
184
|
scheduleAction?: {
|
|
164
185
|
maxCapacity: number;
|
|
165
186
|
minCapacity: number;
|
package/createFargateTask.js
CHANGED
|
@@ -430,26 +430,78 @@ function setAutoscaling(service, serviceName, config) {
|
|
|
430
430
|
scalableDimension: "ecs:service:DesiredCount",
|
|
431
431
|
serviceNamespace: "ecs",
|
|
432
432
|
});
|
|
433
|
+
// The dcl-ops-lib SQS queue convention is to pass `queue.id` (the queue's
|
|
434
|
+
// URL, e.g., https://sqs.us-east-1.amazonaws.com/.../my-queue) as the
|
|
435
|
+
// metric dimension value. CloudWatch wants just the queue NAME ("my-queue")
|
|
436
|
+
// in the dimension, so we trim everything up to and including the last `/`.
|
|
437
|
+
const extractQueueName = (queueUrl) => queueUrl.apply((value) => value.split("/").pop());
|
|
433
438
|
if (config.appAutoscaling.policy) {
|
|
434
439
|
config.appAutoscaling.policy.forEach((item, index) => {
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
]
|
|
446
|
-
|
|
447
|
-
unit: "Count",
|
|
448
|
-
};
|
|
440
|
+
// Validate the singular/plural choice. Done per-item so the user sees
|
|
441
|
+
// the failure on the offending policy entry rather than a vague top-
|
|
442
|
+
// level error after Pulumi has already started planning resources.
|
|
443
|
+
const hasSingle = item.metricDimensionValue !== undefined;
|
|
444
|
+
const hasMulti = item.metricDimensionValues !== undefined &&
|
|
445
|
+
item.metricDimensionValues.length > 0;
|
|
446
|
+
if (hasSingle && hasMulti) {
|
|
447
|
+
throw new Error(`appAutoscaling.policy[${index}] sets both metricDimensionValue and metricDimensionValues; pick one.`);
|
|
448
|
+
}
|
|
449
|
+
if (!hasSingle && !hasMulti) {
|
|
450
|
+
throw new Error(`appAutoscaling.policy[${index}] must set either metricDimensionValue or metricDimensionValues (non-empty).`);
|
|
451
|
+
}
|
|
449
452
|
let TTS_CustomizedMetricSpecification = undefined;
|
|
450
453
|
if (item.metricName === "ApproximateNumberOfMessagesVisible") {
|
|
451
|
-
|
|
452
|
-
|
|
454
|
+
if (hasMulti) {
|
|
455
|
+
// Metric-math form: SUM the queue depths into one signal. Each
|
|
456
|
+
// queue contributes a `mN` metric stat with returnData=false, and
|
|
457
|
+
// a final `e0` expression `m0 + m1 + ...` is the value the scaling
|
|
458
|
+
// target tracks. AWS evaluates the expression at policy time.
|
|
459
|
+
const dims = item.metricDimensionValues;
|
|
460
|
+
const metricStats = dims.map((queueUrl, i) => ({
|
|
461
|
+
id: `m${i}`,
|
|
462
|
+
metricStat: {
|
|
463
|
+
metric: {
|
|
464
|
+
metricName: item.metricName,
|
|
465
|
+
namespace: "AWS/SQS",
|
|
466
|
+
dimensions: [
|
|
467
|
+
{
|
|
468
|
+
name: "QueueName",
|
|
469
|
+
value: extractQueueName(queueUrl),
|
|
470
|
+
},
|
|
471
|
+
],
|
|
472
|
+
},
|
|
473
|
+
stat: item.statistic,
|
|
474
|
+
unit: "Count",
|
|
475
|
+
},
|
|
476
|
+
returnData: false,
|
|
477
|
+
}));
|
|
478
|
+
const expression = dims.map((_, i) => `m${i}`).join(" + ");
|
|
479
|
+
TTS_CustomizedMetricSpecification = {
|
|
480
|
+
metrics: [
|
|
481
|
+
...metricStats,
|
|
482
|
+
{
|
|
483
|
+
id: "e0",
|
|
484
|
+
expression,
|
|
485
|
+
returnData: true,
|
|
486
|
+
},
|
|
487
|
+
],
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
else {
|
|
491
|
+
// Single-queue form (existing behavior, byte-identical output).
|
|
492
|
+
TTS_CustomizedMetricSpecification = {
|
|
493
|
+
metricName: item.metricName,
|
|
494
|
+
namespace: "AWS/SQS",
|
|
495
|
+
dimensions: [
|
|
496
|
+
{
|
|
497
|
+
name: "QueueName",
|
|
498
|
+
value: extractQueueName(item.metricDimensionValue),
|
|
499
|
+
},
|
|
500
|
+
],
|
|
501
|
+
statistic: item.statistic,
|
|
502
|
+
unit: "Count",
|
|
503
|
+
};
|
|
504
|
+
}
|
|
453
505
|
}
|
|
454
506
|
return new aws.appautoscaling.Policy(`ecs-autoscaling-policy-${(0, stack_1.getStackScopedName)(serviceName)}-${index.toString()}`, // distinct policies by id
|
|
455
507
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dcl-ops-lib",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.9.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"build": "tsc && cp bin/* . && node test.js",
|
|
6
6
|
"test": "tsc -p tsconfig.test.json && ENVIRONMENT=dev node bin-test/rateLimiting.test.js",
|
|
@@ -21,14 +21,12 @@
|
|
|
21
21
|
"name": "next",
|
|
22
22
|
"prerelease": true
|
|
23
23
|
}
|
|
24
|
-
]
|
|
25
|
-
"extends": "@semantic-release/gitlab-config"
|
|
24
|
+
]
|
|
26
25
|
},
|
|
27
26
|
"devDependencies": {
|
|
28
|
-
"@semantic-release/gitlab-config": "^14.0.1",
|
|
29
27
|
"@types/mime": "^3.0.4",
|
|
30
28
|
"@types/node": "20.9.3",
|
|
31
|
-
"semantic-release": "^
|
|
29
|
+
"semantic-release": "^25.0.5",
|
|
32
30
|
"typescript": "5.3.2"
|
|
33
31
|
},
|
|
34
32
|
"dependencies": {
|