relight-cli 0.1.0 → 0.2.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 +77 -34
- package/package.json +12 -4
- package/src/cli.js +305 -1
- package/src/commands/apps.js +128 -0
- package/src/commands/auth.js +75 -4
- package/src/commands/config.js +282 -0
- package/src/commands/cost.js +593 -0
- package/src/commands/db.js +531 -0
- package/src/commands/deploy.js +298 -0
- package/src/commands/doctor.js +41 -9
- package/src/commands/domains.js +223 -0
- package/src/commands/logs.js +111 -0
- package/src/commands/open.js +42 -0
- package/src/commands/ps.js +121 -0
- package/src/commands/scale.js +132 -0
- package/src/lib/clouds/aws.js +309 -35
- package/src/lib/clouds/cf.js +401 -2
- package/src/lib/clouds/gcp.js +234 -3
- package/src/lib/clouds/slicervm.js +139 -0
- package/src/lib/config.js +40 -0
- package/src/lib/docker.js +34 -0
- package/src/lib/link.js +20 -5
- package/src/lib/providers/aws/app.js +481 -0
- package/src/lib/providers/aws/db.js +513 -0
- package/src/lib/providers/aws/dns.js +232 -0
- package/src/lib/providers/aws/registry.js +59 -0
- package/src/lib/providers/cf/app.js +596 -0
- package/src/lib/providers/cf/bundle.js +70 -0
- package/src/lib/providers/cf/db.js +279 -0
- package/src/lib/providers/cf/dns.js +148 -0
- package/src/lib/providers/cf/registry.js +17 -0
- package/src/lib/providers/gcp/app.js +429 -0
- package/src/lib/providers/gcp/db.js +457 -0
- package/src/lib/providers/gcp/dns.js +166 -0
- package/src/lib/providers/gcp/registry.js +30 -0
- package/src/lib/providers/resolve.js +49 -0
- package/src/lib/providers/slicervm/app.js +396 -0
- package/src/lib/providers/slicervm/db.js +33 -0
- package/src/lib/providers/slicervm/dns.js +58 -0
- package/src/lib/providers/slicervm/registry.js +7 -0
- package/worker-template/package.json +10 -0
- package/worker-template/src/index.js +260 -0
package/src/lib/clouds/cf.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
var CF_API = "https://api.cloudflare.com/client/v4";
|
|
2
|
+
var CF_REGISTRY = "registry.cloudflare.com";
|
|
3
|
+
|
|
4
|
+
export { CF_REGISTRY };
|
|
2
5
|
|
|
3
6
|
export var TOKEN_URL =
|
|
4
7
|
"https://dash.cloudflare.com/profile/api-tokens?" +
|
|
@@ -13,12 +16,16 @@ export var TOKEN_URL =
|
|
|
13
16
|
) +
|
|
14
17
|
"&name=relight-cli";
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
// --- CF API base ---
|
|
20
|
+
|
|
21
|
+
export async function cfApi(method, path, body, apiToken, contentType) {
|
|
17
22
|
var headers = {
|
|
18
23
|
Authorization: `Bearer ${apiToken}`,
|
|
19
24
|
};
|
|
20
25
|
|
|
21
|
-
if (
|
|
26
|
+
if (contentType) {
|
|
27
|
+
headers["Content-Type"] = contentType;
|
|
28
|
+
} else if (body && typeof body === "object") {
|
|
22
29
|
headers["Content-Type"] = "application/json";
|
|
23
30
|
body = JSON.stringify(body);
|
|
24
31
|
}
|
|
@@ -41,6 +48,32 @@ export async function cfApi(method, path, body, apiToken) {
|
|
|
41
48
|
return res.text();
|
|
42
49
|
}
|
|
43
50
|
|
|
51
|
+
// --- CF GraphQL Analytics API ---
|
|
52
|
+
|
|
53
|
+
export async function cfGraphQL(apiToken, query, variables) {
|
|
54
|
+
var res = await fetch("https://api.cloudflare.com/client/v4/graphql", {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: {
|
|
57
|
+
Authorization: `Bearer ${apiToken}`,
|
|
58
|
+
"Content-Type": "application/json",
|
|
59
|
+
},
|
|
60
|
+
body: JSON.stringify({ query, variables }),
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
if (!res.ok) {
|
|
64
|
+
var text = await res.text();
|
|
65
|
+
throw new Error(`CF GraphQL: ${res.status} ${text}`);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
var json = await res.json();
|
|
69
|
+
if (json.errors && json.errors.length > 0) {
|
|
70
|
+
throw new Error(`CF GraphQL: ${json.errors.map((e) => e.message).join(", ")}`);
|
|
71
|
+
}
|
|
72
|
+
return json.data;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// --- Auth verification ---
|
|
76
|
+
|
|
44
77
|
export async function verifyToken(apiToken) {
|
|
45
78
|
return cfApi("GET", "/user/tokens/verify", null, apiToken);
|
|
46
79
|
}
|
|
@@ -50,6 +83,299 @@ export async function listAccounts(apiToken) {
|
|
|
50
83
|
return res.result || [];
|
|
51
84
|
}
|
|
52
85
|
|
|
86
|
+
// --- Registry ---
|
|
87
|
+
|
|
88
|
+
export async function getRegistryCredentials(accountId, apiToken) {
|
|
89
|
+
var res = await cfApi(
|
|
90
|
+
"POST",
|
|
91
|
+
`/accounts/${accountId}/containers/registries/${CF_REGISTRY}/credentials`,
|
|
92
|
+
{ permissions: ["push", "pull"], expiration_minutes: 15 },
|
|
93
|
+
apiToken
|
|
94
|
+
);
|
|
95
|
+
return res.result;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// --- Worker scripts ---
|
|
99
|
+
|
|
100
|
+
export async function uploadWorker(accountId, apiToken, scriptName, code, metadata) {
|
|
101
|
+
var form = new FormData();
|
|
102
|
+
form.append(
|
|
103
|
+
"metadata",
|
|
104
|
+
new Blob([JSON.stringify(metadata)], { type: "application/json" })
|
|
105
|
+
);
|
|
106
|
+
form.append(
|
|
107
|
+
"index.js",
|
|
108
|
+
new Blob([code], { type: "application/javascript+module" }),
|
|
109
|
+
"index.js"
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
var res = await fetch(
|
|
113
|
+
`${CF_API}/accounts/${accountId}/workers/scripts/${scriptName}`,
|
|
114
|
+
{
|
|
115
|
+
method: "PUT",
|
|
116
|
+
headers: { Authorization: `Bearer ${apiToken}` },
|
|
117
|
+
body: form,
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
if (!res.ok) {
|
|
122
|
+
var text = await res.text();
|
|
123
|
+
throw new Error(`Worker upload failed: ${res.status} ${text}`);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return res.json();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export async function deleteWorker(accountId, apiToken, scriptName) {
|
|
130
|
+
return cfApi(
|
|
131
|
+
"DELETE",
|
|
132
|
+
`/accounts/${accountId}/workers/scripts/${scriptName}`,
|
|
133
|
+
null,
|
|
134
|
+
apiToken
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export async function patchWorkerSettings(accountId, apiToken, scriptName, settings) {
|
|
139
|
+
var form = new FormData();
|
|
140
|
+
form.append(
|
|
141
|
+
"settings",
|
|
142
|
+
new Blob([JSON.stringify(settings)], { type: "application/json" })
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
var res = await fetch(
|
|
146
|
+
`${CF_API}/accounts/${accountId}/workers/scripts/${scriptName}/settings`,
|
|
147
|
+
{
|
|
148
|
+
method: "PATCH",
|
|
149
|
+
headers: { Authorization: `Bearer ${apiToken}` },
|
|
150
|
+
body: form,
|
|
151
|
+
}
|
|
152
|
+
);
|
|
153
|
+
|
|
154
|
+
if (!res.ok) {
|
|
155
|
+
var text = await res.text();
|
|
156
|
+
throw new Error(`Settings update failed: ${res.status} ${text}`);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return res.json();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export async function listWorkerScripts(accountId, apiToken) {
|
|
163
|
+
var res = await cfApi(
|
|
164
|
+
"GET",
|
|
165
|
+
`/accounts/${accountId}/workers/scripts`,
|
|
166
|
+
null,
|
|
167
|
+
apiToken
|
|
168
|
+
);
|
|
169
|
+
return res.result || [];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function getWorkerSettings(accountId, apiToken, scriptName) {
|
|
173
|
+
var res = await cfApi(
|
|
174
|
+
"GET",
|
|
175
|
+
`/accounts/${accountId}/workers/scripts/${scriptName}/settings`,
|
|
176
|
+
null,
|
|
177
|
+
apiToken
|
|
178
|
+
);
|
|
179
|
+
return res.result;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// --- Container applications ---
|
|
183
|
+
|
|
184
|
+
export async function getDONamespaceId(accountId, apiToken, scriptName, className) {
|
|
185
|
+
var res = await cfApi(
|
|
186
|
+
"GET",
|
|
187
|
+
`/accounts/${accountId}/workers/durable_objects/namespaces`,
|
|
188
|
+
null,
|
|
189
|
+
apiToken
|
|
190
|
+
);
|
|
191
|
+
var namespaces = res.result || [];
|
|
192
|
+
var ns = namespaces.find(
|
|
193
|
+
(n) => n.script === scriptName && n.class === className
|
|
194
|
+
);
|
|
195
|
+
return ns ? ns.id : null;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function listContainerApps(accountId, apiToken) {
|
|
199
|
+
var res = await cfApi(
|
|
200
|
+
"GET",
|
|
201
|
+
`/accounts/${accountId}/containers/applications`,
|
|
202
|
+
null,
|
|
203
|
+
apiToken
|
|
204
|
+
);
|
|
205
|
+
return res.result || [];
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export async function findContainerApp(accountId, apiToken, name) {
|
|
209
|
+
var apps = await listContainerApps(accountId, apiToken);
|
|
210
|
+
return apps.find((a) => a.name === name) || null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export async function createContainerApp(accountId, apiToken, app) {
|
|
214
|
+
var res = await cfApi(
|
|
215
|
+
"POST",
|
|
216
|
+
`/accounts/${accountId}/containers/applications`,
|
|
217
|
+
app,
|
|
218
|
+
apiToken
|
|
219
|
+
);
|
|
220
|
+
return res.result;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export async function deleteContainerApp(accountId, apiToken, appId) {
|
|
224
|
+
return cfApi(
|
|
225
|
+
"DELETE",
|
|
226
|
+
`/accounts/${accountId}/containers/applications/${appId}`,
|
|
227
|
+
null,
|
|
228
|
+
apiToken
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export async function modifyContainerApp(accountId, apiToken, appId, changes) {
|
|
233
|
+
var res = await cfApi(
|
|
234
|
+
"PATCH",
|
|
235
|
+
`/accounts/${accountId}/containers/applications/${appId}`,
|
|
236
|
+
changes,
|
|
237
|
+
apiToken
|
|
238
|
+
);
|
|
239
|
+
return res.result;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export async function createRollout(accountId, apiToken, appId, rollout) {
|
|
243
|
+
var res = await cfApi(
|
|
244
|
+
"POST",
|
|
245
|
+
`/accounts/${accountId}/containers/applications/${appId}/rollouts`,
|
|
246
|
+
rollout,
|
|
247
|
+
apiToken
|
|
248
|
+
);
|
|
249
|
+
return res.result;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// --- Tail/logs ---
|
|
253
|
+
|
|
254
|
+
export async function createTail(accountId, apiToken, scriptName) {
|
|
255
|
+
var res = await cfApi(
|
|
256
|
+
"POST",
|
|
257
|
+
`/accounts/${accountId}/workers/scripts/${scriptName}/tails`,
|
|
258
|
+
{},
|
|
259
|
+
apiToken
|
|
260
|
+
);
|
|
261
|
+
return res.result;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export async function deleteTail(accountId, apiToken, scriptName, tailId) {
|
|
265
|
+
return cfApi(
|
|
266
|
+
"DELETE",
|
|
267
|
+
`/accounts/${accountId}/workers/scripts/${scriptName}/tails/${tailId}`,
|
|
268
|
+
null,
|
|
269
|
+
apiToken
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// --- Zones ---
|
|
274
|
+
|
|
275
|
+
export async function listZones(accountId, apiToken) {
|
|
276
|
+
var all = [];
|
|
277
|
+
var page = 1;
|
|
278
|
+
while (true) {
|
|
279
|
+
var res = await cfApi(
|
|
280
|
+
"GET",
|
|
281
|
+
`/zones?account.id=${accountId}&per_page=50&status=active&page=${page}`,
|
|
282
|
+
null,
|
|
283
|
+
apiToken
|
|
284
|
+
);
|
|
285
|
+
var zones = res.result || [];
|
|
286
|
+
all.push(...zones);
|
|
287
|
+
if (zones.length < 50) break;
|
|
288
|
+
page++;
|
|
289
|
+
}
|
|
290
|
+
return all;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export function findZoneForHostname(zones, hostname) {
|
|
294
|
+
var match = null;
|
|
295
|
+
for (var zone of zones) {
|
|
296
|
+
if (hostname === zone.name || hostname.endsWith("." + zone.name)) {
|
|
297
|
+
if (!match || zone.name.length > match.name.length) {
|
|
298
|
+
match = zone;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return match;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// --- DNS records ---
|
|
306
|
+
|
|
307
|
+
export async function listDnsRecords(accountId, apiToken, zoneId, params) {
|
|
308
|
+
var qs = new URLSearchParams(params || {}).toString();
|
|
309
|
+
var path = `/zones/${zoneId}/dns_records${qs ? "?" + qs : ""}`;
|
|
310
|
+
var res = await cfApi("GET", path, null, apiToken);
|
|
311
|
+
return res.result || [];
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export async function createDnsRecord(accountId, apiToken, zoneId, record) {
|
|
315
|
+
return cfApi(
|
|
316
|
+
"POST",
|
|
317
|
+
`/zones/${zoneId}/dns_records`,
|
|
318
|
+
record,
|
|
319
|
+
apiToken
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export async function deleteDnsRecord(accountId, apiToken, zoneId, recordId) {
|
|
324
|
+
return cfApi(
|
|
325
|
+
"DELETE",
|
|
326
|
+
`/zones/${zoneId}/dns_records/${recordId}`,
|
|
327
|
+
null,
|
|
328
|
+
apiToken
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
// --- Workers custom domains ---
|
|
333
|
+
|
|
334
|
+
export async function addWorkerDomain(accountId, apiToken, scriptName, hostname, zoneId) {
|
|
335
|
+
return cfApi(
|
|
336
|
+
"PUT",
|
|
337
|
+
`/accounts/${accountId}/workers/domains`,
|
|
338
|
+
{
|
|
339
|
+
hostname,
|
|
340
|
+
zone_id: zoneId,
|
|
341
|
+
service: scriptName,
|
|
342
|
+
environment: "production",
|
|
343
|
+
},
|
|
344
|
+
apiToken
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
export async function removeWorkerDomain(accountId, apiToken, hostname) {
|
|
349
|
+
var res = await cfApi(
|
|
350
|
+
"GET",
|
|
351
|
+
`/accounts/${accountId}/workers/domains`,
|
|
352
|
+
null,
|
|
353
|
+
apiToken
|
|
354
|
+
);
|
|
355
|
+
var domains = res.result || [];
|
|
356
|
+
var domain = domains.find((d) => d.hostname === hostname);
|
|
357
|
+
if (!domain) return;
|
|
358
|
+
|
|
359
|
+
return cfApi(
|
|
360
|
+
"DELETE",
|
|
361
|
+
`/accounts/${accountId}/workers/domains/${domain.id}`,
|
|
362
|
+
null,
|
|
363
|
+
apiToken
|
|
364
|
+
);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export async function listWorkerDomainsForService(accountId, apiToken, scriptName) {
|
|
368
|
+
var res = await cfApi(
|
|
369
|
+
"GET",
|
|
370
|
+
`/accounts/${accountId}/workers/domains`,
|
|
371
|
+
null,
|
|
372
|
+
apiToken
|
|
373
|
+
);
|
|
374
|
+
return (res.result || []).filter((d) => d.service === scriptName);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// --- Workers subdomain ---
|
|
378
|
+
|
|
53
379
|
export async function getWorkersSubdomain(accountId, apiToken) {
|
|
54
380
|
try {
|
|
55
381
|
var res = await cfApi(
|
|
@@ -63,3 +389,76 @@ export async function getWorkersSubdomain(accountId, apiToken) {
|
|
|
63
389
|
return null;
|
|
64
390
|
}
|
|
65
391
|
}
|
|
392
|
+
|
|
393
|
+
export async function enableWorkerSubdomain(accountId, apiToken, scriptName) {
|
|
394
|
+
return cfApi(
|
|
395
|
+
"POST",
|
|
396
|
+
`/accounts/${accountId}/workers/services/${scriptName}/environments/production/subdomain`,
|
|
397
|
+
{ enabled: true },
|
|
398
|
+
apiToken
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// --- D1 databases ---
|
|
403
|
+
|
|
404
|
+
export async function createD1Database(accountId, apiToken, name, { locationHint, jurisdiction } = {}) {
|
|
405
|
+
var body = { name };
|
|
406
|
+
if (jurisdiction) body.jurisdiction = jurisdiction;
|
|
407
|
+
else if (locationHint) body.primary_location_hint = locationHint;
|
|
408
|
+
var res = await cfApi(
|
|
409
|
+
"POST",
|
|
410
|
+
`/accounts/${accountId}/d1/database`,
|
|
411
|
+
body,
|
|
412
|
+
apiToken
|
|
413
|
+
);
|
|
414
|
+
return res.result;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export async function deleteD1Database(accountId, apiToken, dbId) {
|
|
418
|
+
return cfApi(
|
|
419
|
+
"DELETE",
|
|
420
|
+
`/accounts/${accountId}/d1/database/${dbId}`,
|
|
421
|
+
null,
|
|
422
|
+
apiToken
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
export async function getD1Database(accountId, apiToken, dbId) {
|
|
427
|
+
var res = await cfApi(
|
|
428
|
+
"GET",
|
|
429
|
+
`/accounts/${accountId}/d1/database/${dbId}`,
|
|
430
|
+
null,
|
|
431
|
+
apiToken
|
|
432
|
+
);
|
|
433
|
+
return res.result;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export async function queryD1(accountId, apiToken, dbId, sql, params) {
|
|
437
|
+
var body = { sql };
|
|
438
|
+
if (params) body.params = params;
|
|
439
|
+
var res = await cfApi(
|
|
440
|
+
"POST",
|
|
441
|
+
`/accounts/${accountId}/d1/database/${dbId}/query`,
|
|
442
|
+
body,
|
|
443
|
+
apiToken
|
|
444
|
+
);
|
|
445
|
+
return res.result;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
export async function exportD1(accountId, apiToken, dbId, body) {
|
|
449
|
+
return cfApi(
|
|
450
|
+
"POST",
|
|
451
|
+
`/accounts/${accountId}/d1/database/${dbId}/export`,
|
|
452
|
+
body,
|
|
453
|
+
apiToken
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export async function importD1(accountId, apiToken, dbId, body) {
|
|
458
|
+
return cfApi(
|
|
459
|
+
"POST",
|
|
460
|
+
`/accounts/${accountId}/d1/database/${dbId}/import`,
|
|
461
|
+
body,
|
|
462
|
+
apiToken
|
|
463
|
+
);
|
|
464
|
+
}
|
package/src/lib/clouds/gcp.js
CHANGED
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { createSign } from "crypto";
|
|
2
2
|
import { readFileSync } from "fs";
|
|
3
3
|
|
|
4
|
-
var RUN_API = "https://run.googleapis.com/v2";
|
|
4
|
+
export var RUN_API = "https://run.googleapis.com/v2";
|
|
5
5
|
var CRM_API = "https://cloudresourcemanager.googleapis.com/v1";
|
|
6
6
|
var TOKEN_URI = "https://oauth2.googleapis.com/token";
|
|
7
7
|
var SCOPE = "https://www.googleapis.com/auth/cloud-platform";
|
|
8
8
|
|
|
9
|
+
export var AR_API = "https://artifactregistry.googleapis.com/v1";
|
|
10
|
+
export var SQLADMIN_API = "https://sqladmin.googleapis.com/v1";
|
|
11
|
+
export var DNS_API = "https://dns.googleapis.com/dns/v1";
|
|
12
|
+
export var LOGGING_API = "https://logging.googleapis.com/v2";
|
|
13
|
+
export var MONITORING_API = "https://monitoring.googleapis.com/v3";
|
|
14
|
+
|
|
9
15
|
// --- Service account key file ---
|
|
10
16
|
|
|
11
17
|
export function readKeyFile(path) {
|
|
@@ -25,7 +31,7 @@ export function readKeyFile(path) {
|
|
|
25
31
|
};
|
|
26
32
|
}
|
|
27
33
|
|
|
28
|
-
// --- JWT
|
|
34
|
+
// --- JWT -> access token ---
|
|
29
35
|
|
|
30
36
|
export async function mintAccessToken(clientEmail, privateKey) {
|
|
31
37
|
var now = Math.floor(Date.now() / 1000);
|
|
@@ -95,10 +101,51 @@ export async function gcpApi(method, url, body, token) {
|
|
|
95
101
|
return res.json();
|
|
96
102
|
}
|
|
97
103
|
|
|
104
|
+
// --- LRO polling ---
|
|
105
|
+
|
|
106
|
+
export async function waitForOperation(token, operationName, apiBase) {
|
|
107
|
+
var url = apiBase
|
|
108
|
+
? `${apiBase}/${operationName}`
|
|
109
|
+
: `https://run.googleapis.com/v2/${operationName}`;
|
|
110
|
+
while (true) {
|
|
111
|
+
var op = await gcpApi("GET", url, null, token);
|
|
112
|
+
if (op.done) {
|
|
113
|
+
if (op.error) {
|
|
114
|
+
throw new Error(`Operation failed: ${op.error.message || JSON.stringify(op.error)}`);
|
|
115
|
+
}
|
|
116
|
+
return op.response || op;
|
|
117
|
+
}
|
|
118
|
+
await new Promise((r) => setTimeout(r, 2000));
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export async function waitForSqlOperation(token, project, opName) {
|
|
123
|
+
while (true) {
|
|
124
|
+
var op = await gcpApi(
|
|
125
|
+
"GET",
|
|
126
|
+
`${SQLADMIN_API}/projects/${project}/operations/${opName}`,
|
|
127
|
+
null,
|
|
128
|
+
token
|
|
129
|
+
);
|
|
130
|
+
if (op.status === "DONE") {
|
|
131
|
+
if (op.error) {
|
|
132
|
+
var msgs = (op.error.errors || []).map((e) => e.message).join(", ");
|
|
133
|
+
throw new Error(`SQL operation failed: ${msgs || JSON.stringify(op.error)}`);
|
|
134
|
+
}
|
|
135
|
+
return op;
|
|
136
|
+
}
|
|
137
|
+
await new Promise((r) => setTimeout(r, 3000));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// --- Project verification ---
|
|
142
|
+
|
|
98
143
|
export async function verifyProject(token, project) {
|
|
99
144
|
return gcpApi("GET", `${CRM_API}/projects/${project}`, null, token);
|
|
100
145
|
}
|
|
101
146
|
|
|
147
|
+
// --- Cloud Run ---
|
|
148
|
+
|
|
102
149
|
export async function listRegions(token, project) {
|
|
103
150
|
var res = await gcpApi(
|
|
104
151
|
"GET",
|
|
@@ -117,4 +164,188 @@ export async function listServices(token, project, region) {
|
|
|
117
164
|
token
|
|
118
165
|
);
|
|
119
166
|
return res.services || [];
|
|
120
|
-
}
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export async function listAllServices(token, project) {
|
|
170
|
+
var res = await gcpApi(
|
|
171
|
+
"GET",
|
|
172
|
+
`${RUN_API}/projects/${project}/locations/-/services`,
|
|
173
|
+
null,
|
|
174
|
+
token
|
|
175
|
+
);
|
|
176
|
+
return res.services || [];
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export async function getService(token, serviceName) {
|
|
180
|
+
return gcpApi("GET", `${RUN_API}/${serviceName}`, null, token);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export async function createService(token, project, region, serviceId, body) {
|
|
184
|
+
var op = await gcpApi(
|
|
185
|
+
"POST",
|
|
186
|
+
`${RUN_API}/projects/${project}/locations/${region}/services?serviceId=${serviceId}`,
|
|
187
|
+
body,
|
|
188
|
+
token
|
|
189
|
+
);
|
|
190
|
+
return waitForOperation(token, op.name);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export async function updateService(token, serviceName, body) {
|
|
194
|
+
var op = await gcpApi("PATCH", `${RUN_API}/${serviceName}`, body, token);
|
|
195
|
+
return waitForOperation(token, op.name);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function deleteService(token, serviceName) {
|
|
199
|
+
var op = await gcpApi("DELETE", `${RUN_API}/${serviceName}`, null, token);
|
|
200
|
+
return waitForOperation(token, op.name);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export async function setIamPolicy(token, serviceName, policy) {
|
|
204
|
+
return gcpApi(
|
|
205
|
+
"POST",
|
|
206
|
+
`${RUN_API}/${serviceName}:setIamPolicy`,
|
|
207
|
+
{ policy },
|
|
208
|
+
token
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// --- Artifact Registry ---
|
|
213
|
+
|
|
214
|
+
export async function getRepository(token, project, location, repoName) {
|
|
215
|
+
return gcpApi(
|
|
216
|
+
"GET",
|
|
217
|
+
`${AR_API}/projects/${project}/locations/${location}/repositories/${repoName}`,
|
|
218
|
+
null,
|
|
219
|
+
token
|
|
220
|
+
);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export async function createRepository(token, project, location, repoName) {
|
|
224
|
+
var op = await gcpApi(
|
|
225
|
+
"POST",
|
|
226
|
+
`${AR_API}/projects/${project}/locations/${location}/repositories?repositoryId=${repoName}`,
|
|
227
|
+
{ format: "DOCKER" },
|
|
228
|
+
token
|
|
229
|
+
);
|
|
230
|
+
if (op.done) return op.response || op;
|
|
231
|
+
return waitForOperation(token, op.name, AR_API);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// --- Cloud SQL ---
|
|
235
|
+
|
|
236
|
+
export async function createSqlInstance(token, project, body) {
|
|
237
|
+
var op = await gcpApi(
|
|
238
|
+
"POST",
|
|
239
|
+
`${SQLADMIN_API}/projects/${project}/instances`,
|
|
240
|
+
body,
|
|
241
|
+
token
|
|
242
|
+
);
|
|
243
|
+
return waitForSqlOperation(token, project, op.name);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export async function getSqlInstance(token, project, instanceName) {
|
|
247
|
+
return gcpApi(
|
|
248
|
+
"GET",
|
|
249
|
+
`${SQLADMIN_API}/projects/${project}/instances/${instanceName}`,
|
|
250
|
+
null,
|
|
251
|
+
token
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
export async function deleteSqlInstance(token, project, instanceName) {
|
|
256
|
+
var op = await gcpApi(
|
|
257
|
+
"DELETE",
|
|
258
|
+
`${SQLADMIN_API}/projects/${project}/instances/${instanceName}`,
|
|
259
|
+
null,
|
|
260
|
+
token
|
|
261
|
+
);
|
|
262
|
+
return waitForSqlOperation(token, project, op.name);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export async function createSqlDatabase(token, project, instanceName, dbName) {
|
|
266
|
+
var op = await gcpApi(
|
|
267
|
+
"POST",
|
|
268
|
+
`${SQLADMIN_API}/projects/${project}/instances/${instanceName}/databases`,
|
|
269
|
+
{ name: dbName },
|
|
270
|
+
token
|
|
271
|
+
);
|
|
272
|
+
return waitForSqlOperation(token, project, op.name);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export async function deleteSqlDatabase(token, project, instanceName, dbName) {
|
|
276
|
+
var op = await gcpApi(
|
|
277
|
+
"DELETE",
|
|
278
|
+
`${SQLADMIN_API}/projects/${project}/instances/${instanceName}/databases/${dbName}`,
|
|
279
|
+
null,
|
|
280
|
+
token
|
|
281
|
+
);
|
|
282
|
+
return waitForSqlOperation(token, project, op.name);
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
export async function createSqlUser(token, project, instanceName, userName, password) {
|
|
286
|
+
var op = await gcpApi(
|
|
287
|
+
"POST",
|
|
288
|
+
`${SQLADMIN_API}/projects/${project}/instances/${instanceName}/users`,
|
|
289
|
+
{ name: userName, password },
|
|
290
|
+
token
|
|
291
|
+
);
|
|
292
|
+
return waitForSqlOperation(token, project, op.name);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
export async function updateSqlUser(token, project, instanceName, userName, password) {
|
|
296
|
+
var op = await gcpApi(
|
|
297
|
+
"PUT",
|
|
298
|
+
`${SQLADMIN_API}/projects/${project}/instances/${instanceName}/users?name=${encodeURIComponent(userName)}`,
|
|
299
|
+
{ name: userName, password },
|
|
300
|
+
token
|
|
301
|
+
);
|
|
302
|
+
return waitForSqlOperation(token, project, op.name);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// --- Cloud DNS ---
|
|
306
|
+
|
|
307
|
+
export async function listManagedZones(token, project) {
|
|
308
|
+
var res = await gcpApi(
|
|
309
|
+
"GET",
|
|
310
|
+
`${DNS_API}/projects/${project}/managedZones`,
|
|
311
|
+
null,
|
|
312
|
+
token
|
|
313
|
+
);
|
|
314
|
+
return res.managedZones || [];
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
export async function createDnsChange(token, project, zoneName, change) {
|
|
318
|
+
return gcpApi(
|
|
319
|
+
"POST",
|
|
320
|
+
`${DNS_API}/projects/${project}/managedZones/${zoneName}/changes`,
|
|
321
|
+
change,
|
|
322
|
+
token
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
export async function listResourceRecordSets(token, project, zoneName) {
|
|
327
|
+
var res = await gcpApi(
|
|
328
|
+
"GET",
|
|
329
|
+
`${DNS_API}/projects/${project}/managedZones/${zoneName}/rrsets`,
|
|
330
|
+
null,
|
|
331
|
+
token
|
|
332
|
+
);
|
|
333
|
+
return res.rrsets || [];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// --- Cloud Logging ---
|
|
337
|
+
|
|
338
|
+
export async function listLogEntries(token, body) {
|
|
339
|
+
return gcpApi("POST", `${LOGGING_API}/entries:list`, body, token);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// --- Cloud Monitoring ---
|
|
343
|
+
|
|
344
|
+
export async function queryTimeSeries(token, project, body) {
|
|
345
|
+
return gcpApi(
|
|
346
|
+
"POST",
|
|
347
|
+
`${MONITORING_API}/projects/${project}/timeSeries:query`,
|
|
348
|
+
body,
|
|
349
|
+
token
|
|
350
|
+
);
|
|
351
|
+
}
|