@depup/artillery 2.0.30-depup.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 +63 -0
- package/bin/run +29 -0
- package/bin/run.cmd +3 -0
- package/changes.json +138 -0
- package/console-reporter.js +1 -0
- package/lib/artillery-global.js +33 -0
- package/lib/cli/banner.js +8 -0
- package/lib/cli/common-flags.js +80 -0
- package/lib/cli/hooks/version.js +20 -0
- package/lib/cmds/dino.js +109 -0
- package/lib/cmds/quick.js +122 -0
- package/lib/cmds/report.js +34 -0
- package/lib/cmds/run-aci.js +91 -0
- package/lib/cmds/run-fargate.js +192 -0
- package/lib/cmds/run-lambda.js +96 -0
- package/lib/cmds/run.js +671 -0
- package/lib/console-capture.js +92 -0
- package/lib/console-reporter.js +438 -0
- package/lib/create-bom/built-in-plugins.js +12 -0
- package/lib/create-bom/create-bom.js +301 -0
- package/lib/dispatcher.js +9 -0
- package/lib/dist.js +222 -0
- package/lib/index.js +5 -0
- package/lib/launch-platform.js +439 -0
- package/lib/load-plugins.js +113 -0
- package/lib/platform/aws/aws-cloudwatch.js +106 -0
- package/lib/platform/aws/aws-create-sqs-queue.js +58 -0
- package/lib/platform/aws/aws-ensure-s3-bucket-exists.js +78 -0
- package/lib/platform/aws/aws-get-account-id.js +26 -0
- package/lib/platform/aws/aws-get-bucket-region.js +18 -0
- package/lib/platform/aws/aws-get-credentials.js +28 -0
- package/lib/platform/aws/aws-get-default-region.js +26 -0
- package/lib/platform/aws/aws-whoami.js +15 -0
- package/lib/platform/aws/constants.js +7 -0
- package/lib/platform/aws/iam-cf-templates/aws-iam-fargate-cf-template.yml +219 -0
- package/lib/platform/aws/iam-cf-templates/aws-iam-lambda-cf-template.yml +125 -0
- package/lib/platform/aws/iam-cf-templates/gh-oidc-fargate.yml +241 -0
- package/lib/platform/aws/iam-cf-templates/gh-oidc-lambda.yml +153 -0
- package/lib/platform/aws-ecs/ecs.js +247 -0
- package/lib/platform/aws-ecs/legacy/aws-util.js +134 -0
- package/lib/platform/aws-ecs/legacy/bom.js +528 -0
- package/lib/platform/aws-ecs/legacy/constants.js +27 -0
- package/lib/platform/aws-ecs/legacy/create-s3-client.js +24 -0
- package/lib/platform/aws-ecs/legacy/create-test.js +247 -0
- package/lib/platform/aws-ecs/legacy/errors.js +34 -0
- package/lib/platform/aws-ecs/legacy/find-public-subnets.js +149 -0
- package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-inspect-script/index.js +27 -0
- package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-sqs-reporter/azure-aqs.js +80 -0
- package/lib/platform/aws-ecs/legacy/plugins/artillery-plugin-sqs-reporter/index.js +202 -0
- package/lib/platform/aws-ecs/legacy/plugins.js +16 -0
- package/lib/platform/aws-ecs/legacy/run-cluster.js +1994 -0
- package/lib/platform/aws-ecs/legacy/sqs-reporter.js +401 -0
- package/lib/platform/aws-ecs/legacy/tags.js +22 -0
- package/lib/platform/aws-ecs/legacy/test-run-status.js +9 -0
- package/lib/platform/aws-ecs/legacy/time.js +67 -0
- package/lib/platform/aws-ecs/legacy/util.js +97 -0
- package/lib/platform/aws-ecs/worker/Dockerfile +64 -0
- package/lib/platform/aws-ecs/worker/helpers.sh +80 -0
- package/lib/platform/aws-ecs/worker/loadgen-worker +656 -0
- package/lib/platform/aws-lambda/dependencies.js +130 -0
- package/lib/platform/aws-lambda/index.js +734 -0
- package/lib/platform/aws-lambda/lambda-handler/a9-handler-dependencies.js +73 -0
- package/lib/platform/aws-lambda/lambda-handler/a9-handler-helpers.js +43 -0
- package/lib/platform/aws-lambda/lambda-handler/a9-handler-index.js +235 -0
- package/lib/platform/aws-lambda/lambda-handler/package.json +15 -0
- package/lib/platform/aws-lambda/prices.js +29 -0
- package/lib/platform/az/aci.js +694 -0
- package/lib/platform/az/aqs-queue-consumer.js +88 -0
- package/lib/platform/az/regions.js +52 -0
- package/lib/platform/cloud/api.js +72 -0
- package/lib/platform/cloud/cloud.js +448 -0
- package/lib/platform/cloud/http-client.js +19 -0
- package/lib/platform/local/artillery-worker-local.js +154 -0
- package/lib/platform/local/index.js +174 -0
- package/lib/platform/local/worker.js +261 -0
- package/lib/platform/worker-states.js +13 -0
- package/lib/queue-consumer/index.js +56 -0
- package/lib/stash.js +41 -0
- package/lib/telemetry.js +78 -0
- package/lib/util/await-on-ee.js +24 -0
- package/lib/util/generate-id.js +9 -0
- package/lib/util/parse-tag-string.js +21 -0
- package/lib/util/prepare-test-execution-plan.js +216 -0
- package/lib/util/sleep.js +7 -0
- package/lib/util/validate-script.js +132 -0
- package/lib/util.js +294 -0
- package/lib/utils-config.js +31 -0
- package/package.json +323 -0
- package/types.d.ts +317 -0
- package/util.js +1 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
const A = require('async');
|
|
4
|
+
const debug = require('debug')('commands:create-test');
|
|
5
|
+
|
|
6
|
+
const { getBucketName } = require('./util');
|
|
7
|
+
const createS3Client = require('./create-s3-client');
|
|
8
|
+
|
|
9
|
+
const path = require('node:path');
|
|
10
|
+
|
|
11
|
+
const fs = require('node:fs');
|
|
12
|
+
|
|
13
|
+
const { createBOM, prettyPrint } = require('./bom');
|
|
14
|
+
|
|
15
|
+
const { PutObjectCommand } = require('@aws-sdk/client-s3');
|
|
16
|
+
|
|
17
|
+
function tryCreateTest(scriptPath, options) {
|
|
18
|
+
createTest(scriptPath, options);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async function createTest(scriptPath, options, callback) {
|
|
22
|
+
const absoluteScriptPath = path.resolve(process.cwd(), scriptPath);
|
|
23
|
+
|
|
24
|
+
const contextPath = options.context
|
|
25
|
+
? path.resolve(options.context)
|
|
26
|
+
: path.dirname(absoluteScriptPath);
|
|
27
|
+
|
|
28
|
+
debug('script:', absoluteScriptPath);
|
|
29
|
+
debug('root:', contextPath);
|
|
30
|
+
|
|
31
|
+
const context = {
|
|
32
|
+
contextDir: contextPath,
|
|
33
|
+
scriptPath: absoluteScriptPath,
|
|
34
|
+
originalScriptPath: scriptPath,
|
|
35
|
+
name: options.name, // test name, eg simple-bom or aht_$UUID
|
|
36
|
+
manifestPath: options.manifestPath,
|
|
37
|
+
packageJsonPath: options.packageJsonPath,
|
|
38
|
+
flags: options.flags
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (typeof options.config === 'string') {
|
|
42
|
+
const absoluteConfigPath = path.resolve(process.cwd(), options.config);
|
|
43
|
+
context.configPath = absoluteConfigPath;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (options.customSyncClient) {
|
|
47
|
+
context.customSyncClient = options.customSyncClient;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
A.waterfall(
|
|
52
|
+
[
|
|
53
|
+
A.constant(context),
|
|
54
|
+
async (context) => {
|
|
55
|
+
if (!context.customSyncClient) {
|
|
56
|
+
context.s3Bucket = await getBucketName();
|
|
57
|
+
return context;
|
|
58
|
+
} else {
|
|
59
|
+
context.s3Bucket = 'S3_BUCKET_ARGUMENT_NOT_USED_ON_AZURE';
|
|
60
|
+
return context;
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
prepareManifest,
|
|
64
|
+
printManifest,
|
|
65
|
+
syncS3,
|
|
66
|
+
writeTestMetadata
|
|
67
|
+
],
|
|
68
|
+
(err, context) => {
|
|
69
|
+
if (err) {
|
|
70
|
+
console.log(err);
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (callback) {
|
|
75
|
+
callback(err, context);
|
|
76
|
+
} else if (err) {
|
|
77
|
+
reject(err);
|
|
78
|
+
} else {
|
|
79
|
+
resolve(context);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function prepareManifest(context, callback) {
|
|
87
|
+
let fileToAnalyse = context.scriptPath;
|
|
88
|
+
const extraFiles = [];
|
|
89
|
+
if (context.configPath) {
|
|
90
|
+
debug('context has been provided; extraFiles =', extraFiles);
|
|
91
|
+
fileToAnalyse = context.configPath;
|
|
92
|
+
extraFiles.push(context.scriptPath);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
createBOM(
|
|
96
|
+
fileToAnalyse,
|
|
97
|
+
extraFiles,
|
|
98
|
+
{
|
|
99
|
+
packageJsonPath: context.packageJsonPath,
|
|
100
|
+
flags: context.flags,
|
|
101
|
+
scenarioPath: context.scriptPath
|
|
102
|
+
},
|
|
103
|
+
(err, bom) => {
|
|
104
|
+
debug(err);
|
|
105
|
+
debug(bom);
|
|
106
|
+
context.manifest = bom;
|
|
107
|
+
return callback(err, context);
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function printManifest(context, callback) {
|
|
113
|
+
prettyPrint(context.manifest);
|
|
114
|
+
return callback(null, context);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function syncS3(context) {
|
|
118
|
+
let s3;
|
|
119
|
+
if (context.customSyncClient) {
|
|
120
|
+
s3 = context.customSyncClient;
|
|
121
|
+
} else {
|
|
122
|
+
s3 = createS3Client();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const prefix = `tests/${context.name}`;
|
|
126
|
+
|
|
127
|
+
context.s3Prefix = prefix;
|
|
128
|
+
|
|
129
|
+
debug('Will try syncing to:', context.s3Bucket);
|
|
130
|
+
|
|
131
|
+
debug('Manifest: ', context.manifest);
|
|
132
|
+
|
|
133
|
+
// Iterate through manifest, for each element: has orig (local source) and noPrefix (S3
|
|
134
|
+
// destination) properties
|
|
135
|
+
return new Promise((resolve, reject) => {
|
|
136
|
+
A.eachLimit(
|
|
137
|
+
context.manifest.files,
|
|
138
|
+
3,
|
|
139
|
+
async (item, eachDone) => {
|
|
140
|
+
// If we can't read the file, it may have been specified with a
|
|
141
|
+
// template in its name, e.g. a payload file like:
|
|
142
|
+
// {{ $environment }}-users.csv
|
|
143
|
+
// If so, ignore it, hope config.includeFiles was used, and let
|
|
144
|
+
// "artillery run" in the worker deal with it.
|
|
145
|
+
let body;
|
|
146
|
+
try {
|
|
147
|
+
body = fs.readFileSync(item.orig);
|
|
148
|
+
} catch (fsErr) {
|
|
149
|
+
debug(fsErr);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (!body) {
|
|
153
|
+
return eachDone(null, context);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Filter bundled packages from package.json before upload
|
|
157
|
+
if (item.noPrefix === 'package.json') {
|
|
158
|
+
const pkg = JSON.parse(body.toString());
|
|
159
|
+
const filterBundled = (deps) => {
|
|
160
|
+
if (!deps) return deps;
|
|
161
|
+
const filtered = {};
|
|
162
|
+
for (const [name, version] of Object.entries(deps)) {
|
|
163
|
+
if (
|
|
164
|
+
name !== 'artillery' &&
|
|
165
|
+
name !== 'playwright' &&
|
|
166
|
+
!name.startsWith('@playwright/')
|
|
167
|
+
) {
|
|
168
|
+
filtered[name] = version;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return filtered;
|
|
172
|
+
};
|
|
173
|
+
pkg.dependencies = filterBundled(pkg.dependencies);
|
|
174
|
+
pkg.devDependencies = filterBundled(pkg.devDependencies);
|
|
175
|
+
body = Buffer.from(JSON.stringify(pkg, null, 2));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const key = `${context.s3Prefix}/${item.noPrefixPosix}`;
|
|
179
|
+
await s3.send(
|
|
180
|
+
new PutObjectCommand({
|
|
181
|
+
Bucket: context.s3Bucket,
|
|
182
|
+
Key: key,
|
|
183
|
+
Body: body
|
|
184
|
+
})
|
|
185
|
+
);
|
|
186
|
+
},
|
|
187
|
+
(err) => {
|
|
188
|
+
if (err) {
|
|
189
|
+
reject(err);
|
|
190
|
+
} else {
|
|
191
|
+
resolve(context);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
);
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// create just overwrites an existing test for now
|
|
199
|
+
async function writeTestMetadata(context) {
|
|
200
|
+
const metadata = {
|
|
201
|
+
createdOn: Date.now(),
|
|
202
|
+
name: context.name,
|
|
203
|
+
modules: context.manifest.modules
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
// Here we need to provide config information (if given) -- so that the worker knows how to load it
|
|
207
|
+
if (context.configPath) {
|
|
208
|
+
const res = context.manifest.files.filter((o) => {
|
|
209
|
+
return o.orig === context.configPath;
|
|
210
|
+
});
|
|
211
|
+
const newConfigPath = res[0].noPrefixPosix; // if we have been given a config, we must have an entry
|
|
212
|
+
metadata.configPath = newConfigPath;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const newScriptPath = context.manifest.files.filter((o) => {
|
|
216
|
+
return o.orig === context.scriptPath;
|
|
217
|
+
})[0].noPrefixPosix;
|
|
218
|
+
metadata.scriptPath = newScriptPath;
|
|
219
|
+
|
|
220
|
+
debug('metadata', metadata);
|
|
221
|
+
|
|
222
|
+
let s3 = null;
|
|
223
|
+
if (context.customSyncClient) {
|
|
224
|
+
s3 = context.customSyncClient;
|
|
225
|
+
} else {
|
|
226
|
+
s3 = createS3Client();
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const key = `${context.s3Prefix}/metadata.json`; // TODO: Rename to something less likely to clash
|
|
230
|
+
debug('metadata location:', `${context.s3Bucket}/${key}`);
|
|
231
|
+
await s3.send(
|
|
232
|
+
new PutObjectCommand({
|
|
233
|
+
Body: JSON.stringify(metadata),
|
|
234
|
+
Bucket: context.s3Bucket,
|
|
235
|
+
Key: key
|
|
236
|
+
})
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
return context;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
module.exports = {
|
|
243
|
+
tryCreateTest,
|
|
244
|
+
createTest,
|
|
245
|
+
syncS3,
|
|
246
|
+
prepareManifest
|
|
247
|
+
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
class TestNotFoundError extends Error {
|
|
2
|
+
constructor(message) {
|
|
3
|
+
super(message);
|
|
4
|
+
this.name = 'TestNotFoundError';
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
class NoAvailableQueueError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'NoAvailableQueueError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
class ClientServerVersionMismatchError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'ClientServerMismatchError';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class ConsoleOutputSerializeError extends Error {
|
|
23
|
+
constructor(message) {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = 'OutputSerializeError';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = {
|
|
30
|
+
TestNotFoundError,
|
|
31
|
+
NoAvailableQueueError,
|
|
32
|
+
ClientServerVersionMismatchError,
|
|
33
|
+
ConsoleOutputSerializeError
|
|
34
|
+
};
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
const assert = require('node:assert').strict;
|
|
2
|
+
const {
|
|
3
|
+
EC2Client,
|
|
4
|
+
DescribeRouteTablesCommand,
|
|
5
|
+
DescribeVpcsCommand,
|
|
6
|
+
DescribeSubnetsCommand
|
|
7
|
+
} = require('@aws-sdk/client-ec2');
|
|
8
|
+
|
|
9
|
+
class VPCSubnetFinder {
|
|
10
|
+
constructor(opts) {
|
|
11
|
+
this.ec2 = new EC2Client(opts);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async getRouteTables(vpcId) {
|
|
15
|
+
const rts = await this.ec2.send(
|
|
16
|
+
new DescribeRouteTablesCommand({
|
|
17
|
+
Filters: [
|
|
18
|
+
{
|
|
19
|
+
Name: 'vpc-id',
|
|
20
|
+
Values: [vpcId]
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return rts.RouteTables;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
async findDefaultVpc() {
|
|
30
|
+
const vpcRes = await this.ec2.send(
|
|
31
|
+
new DescribeVpcsCommand({
|
|
32
|
+
Filters: [
|
|
33
|
+
{
|
|
34
|
+
Name: 'isDefault',
|
|
35
|
+
Values: ['true']
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
})
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
assert.ok(vpcRes.Vpcs.length <= 1);
|
|
42
|
+
|
|
43
|
+
if (vpcRes.Vpcs.length !== 1) {
|
|
44
|
+
return null;
|
|
45
|
+
} else {
|
|
46
|
+
return vpcRes.Vpcs[0].VpcId;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async getSubnets(vpcId) {
|
|
51
|
+
const subRes = await this.ec2.send(
|
|
52
|
+
new DescribeSubnetsCommand({
|
|
53
|
+
Filters: [
|
|
54
|
+
{
|
|
55
|
+
Name: 'vpc-id',
|
|
56
|
+
Values: [vpcId]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
})
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
return subRes.Subnets;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
isSubnetPublic(routeTables, subnetId) {
|
|
66
|
+
//
|
|
67
|
+
// Inspect associations of each route table (of a specific VPC). A route
|
|
68
|
+
// table record has an Associations field, which is a list of association
|
|
69
|
+
// objects. There are two types of those:
|
|
70
|
+
//
|
|
71
|
+
// 1. An implicit association, which is indicated by field Main set to
|
|
72
|
+
// true and no explicit subnet id.
|
|
73
|
+
// 2. An explicit association, which is indicated by field Main set to
|
|
74
|
+
// false, and a SubnetId field containing a subnet id.
|
|
75
|
+
//
|
|
76
|
+
|
|
77
|
+
// Route table for the subnet - can there only be one?
|
|
78
|
+
let subnetTable = routeTables.filter((rt) => {
|
|
79
|
+
const explicitAssoc = rt.Associations.filter((assoc) => {
|
|
80
|
+
return assoc.SubnetId && assoc.SubnetId === subnetId;
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
assert.ok(explicitAssoc.length <= 1);
|
|
84
|
+
|
|
85
|
+
return explicitAssoc.length === 1;
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
if (subnetTable.length === 0) {
|
|
89
|
+
// There is no explicit association for this subnet so it will be implicitly
|
|
90
|
+
// associated with the VPC's main routing table.
|
|
91
|
+
subnetTable = routeTables.filter((rt) => {
|
|
92
|
+
const implicitAssoc = rt.Associations.filter((assoc) => {
|
|
93
|
+
return assoc.Main === true;
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
assert.ok(implicitAssoc.length <= 1);
|
|
97
|
+
|
|
98
|
+
return implicitAssoc.length === 1;
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (subnetTable.length !== 1) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Could not locate routing table for subnet: subnet id: ${subnetId}`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const igwRoutes = subnetTable[0].Routes.filter((route) => {
|
|
109
|
+
// NOTE: there may be no IGW attached to route
|
|
110
|
+
return route.GatewayId?.startsWith('igw-');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
return igwRoutes.length > 0;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// TODO: Distinguish between there being no default VPC,
|
|
117
|
+
// or being given an invalid VPC ID, and no public subnets
|
|
118
|
+
// existing in a VPC that definitely exists.
|
|
119
|
+
async findPublicSubnets(vpcId) {
|
|
120
|
+
if (!vpcId) {
|
|
121
|
+
vpcId = await this.findDefaultVpc();
|
|
122
|
+
}
|
|
123
|
+
const rts = await this.getRouteTables(vpcId);
|
|
124
|
+
const subnets = await this.getSubnets(vpcId);
|
|
125
|
+
|
|
126
|
+
const publicSubnets = subnets.filter((subnet) => {
|
|
127
|
+
return this.isSubnetPublic(rts, subnet.SubnetId);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
return publicSubnets;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function main() {
|
|
135
|
+
const f = new VPCSubnetFinder({ region: process.env.REGION });
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const publicSubnets = await f.findPublicSubnets(process.env.VPC_ID);
|
|
139
|
+
console.log(publicSubnets.map((s) => s.SubnetId).join('\n'));
|
|
140
|
+
} catch (err) {
|
|
141
|
+
console.log(err);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (require.main === module) {
|
|
146
|
+
main();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = { VPCSubnetFinder };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
module.exports.Plugin = ArtilleryInspectScriptPlugin;
|
|
8
|
+
|
|
9
|
+
const { btoa } = require('../../util');
|
|
10
|
+
|
|
11
|
+
function ArtilleryInspectScriptPlugin(script, events) {
|
|
12
|
+
this.script = script;
|
|
13
|
+
this.events = events;
|
|
14
|
+
|
|
15
|
+
const checksConfig = script.config?.ensure || script.config?.plugins?.ensure;
|
|
16
|
+
|
|
17
|
+
if (checksConfig) {
|
|
18
|
+
console.log(
|
|
19
|
+
`inspect-script.config.ensure=${btoa(JSON.stringify(checksConfig))}`
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
ArtilleryInspectScriptPlugin.prototype.cleanup = (done) => {
|
|
26
|
+
done(null);
|
|
27
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Copyright (c) Artillery Software Inc.
|
|
2
|
+
// SPDX-License-Identifier: BUSL-1.1
|
|
3
|
+
//
|
|
4
|
+
// Non-evaluation use of Artillery on Azure requires a commercial license
|
|
5
|
+
|
|
6
|
+
const { QueueClient } = require('@azure/storage-queue');
|
|
7
|
+
const { BlobServiceClient } = require('@azure/storage-blob');
|
|
8
|
+
const { DefaultAzureCredential } = require('@azure/identity');
|
|
9
|
+
const { randomUUID } = require('node:crypto');
|
|
10
|
+
|
|
11
|
+
function getAQS() {
|
|
12
|
+
return new QueueClient(
|
|
13
|
+
process.env.AZURE_STORAGE_QUEUE_URL,
|
|
14
|
+
new DefaultAzureCredential()
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
// Azure Queue Storage has a 64KB message limit
|
|
19
|
+
// Use 60KB threshold to leave margin for encoding overhead
|
|
20
|
+
const AQS_SIZE_LIMIT = 60 * 1024;
|
|
21
|
+
|
|
22
|
+
let blobContainerClient = null;
|
|
23
|
+
|
|
24
|
+
function getBlobClient() {
|
|
25
|
+
if (!blobContainerClient) {
|
|
26
|
+
const storageAccount = process.env.AZURE_STORAGE_ACCOUNT;
|
|
27
|
+
const containerName = process.env.AZURE_STORAGE_BLOB_CONTAINER;
|
|
28
|
+
if (!storageAccount || !containerName) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
'AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_BLOB_CONTAINER must be set'
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const blobServiceClient = new BlobServiceClient(
|
|
34
|
+
`https://${storageAccount}.blob.core.windows.net`,
|
|
35
|
+
new DefaultAzureCredential()
|
|
36
|
+
);
|
|
37
|
+
blobContainerClient = blobServiceClient.getContainerClient(containerName);
|
|
38
|
+
}
|
|
39
|
+
return blobContainerClient;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async function sendMessage(queue, body, tags) {
|
|
43
|
+
const payload = JSON.stringify({
|
|
44
|
+
payload: body,
|
|
45
|
+
attributes: tags.reduce((acc, tag) => {
|
|
46
|
+
acc[tag.key] = tag.value;
|
|
47
|
+
return acc;
|
|
48
|
+
}, {})
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Check if payload exceeds Azure Queue Storage limit
|
|
52
|
+
if (Buffer.byteLength(payload, 'utf8') > AQS_SIZE_LIMIT) {
|
|
53
|
+
// Upload to blob storage and send reference
|
|
54
|
+
const testId = tags.find((t) => t.key === 'testId')?.value;
|
|
55
|
+
const workerId = tags.find((t) => t.key === 'workerId')?.value;
|
|
56
|
+
const messageId = randomUUID();
|
|
57
|
+
const blobName = `tests/${testId}/overflow/${workerId}/${messageId}.json`;
|
|
58
|
+
|
|
59
|
+
const blobClient = getBlobClient().getBlockBlobClient(blobName);
|
|
60
|
+
await blobClient.upload(payload, Buffer.byteLength(payload, 'utf8'));
|
|
61
|
+
|
|
62
|
+
// Send reference message
|
|
63
|
+
const refPayload = JSON.stringify({
|
|
64
|
+
payload: {
|
|
65
|
+
_overflowRef: blobName,
|
|
66
|
+
event: body.event
|
|
67
|
+
},
|
|
68
|
+
attributes: tags.reduce((acc, tag) => {
|
|
69
|
+
acc[tag.key] = tag.value;
|
|
70
|
+
return acc;
|
|
71
|
+
}, {})
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
return queue.sendMessage(refPayload);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return queue.sendMessage(payload);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = { getAQS, sendMessage };
|