@stoker-platform/cli 0.5.104 → 0.5.105
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/lib/package.json
CHANGED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { runChildProcess } from "@stoker-platform/node-client";
|
|
2
|
+
import { retryOperation } from "@stoker-platform/utils";
|
|
3
|
+
const getProjectNumber = async (projectId) => {
|
|
4
|
+
return runChildProcess("gcloud", [
|
|
5
|
+
"projects",
|
|
6
|
+
"describe",
|
|
7
|
+
projectId,
|
|
8
|
+
"--format=value(projectNumber)",
|
|
9
|
+
"--quiet",
|
|
10
|
+
]);
|
|
11
|
+
};
|
|
12
|
+
const ensureApiEnabled = async (projectId, api) => {
|
|
13
|
+
await runChildProcess("gcloud", ["services", "enable", api, `--project=${projectId}`, "--quiet"]);
|
|
14
|
+
};
|
|
15
|
+
const ensureServiceIdentity = async (projectId, service) => {
|
|
16
|
+
await retryOperation(async () => {
|
|
17
|
+
await runChildProcess("gcloud", [
|
|
18
|
+
"beta",
|
|
19
|
+
"services",
|
|
20
|
+
"identity",
|
|
21
|
+
"create",
|
|
22
|
+
`--service=${service}`,
|
|
23
|
+
`--project=${projectId}`,
|
|
24
|
+
"--quiet",
|
|
25
|
+
]);
|
|
26
|
+
}, [], undefined, 5000, 3);
|
|
27
|
+
};
|
|
28
|
+
const ensureIamBinding = async (projectId, member, role) => {
|
|
29
|
+
await retryOperation(async () => {
|
|
30
|
+
await runChildProcess("gcloud", [
|
|
31
|
+
"projects",
|
|
32
|
+
"add-iam-policy-binding",
|
|
33
|
+
projectId,
|
|
34
|
+
"--member",
|
|
35
|
+
member,
|
|
36
|
+
"--role",
|
|
37
|
+
role,
|
|
38
|
+
"--quiet",
|
|
39
|
+
]);
|
|
40
|
+
}, [], undefined, 5000, 3);
|
|
41
|
+
};
|
|
42
|
+
const ensureGcfArtifactsRepo = async (projectId, region) => {
|
|
43
|
+
await retryOperation(async () => {
|
|
44
|
+
const repositories = await runChildProcess("gcloud", [
|
|
45
|
+
"artifacts",
|
|
46
|
+
"repositories",
|
|
47
|
+
"list",
|
|
48
|
+
`--location=${region}`,
|
|
49
|
+
`--project=${projectId}`,
|
|
50
|
+
"--format=value(name)",
|
|
51
|
+
"--quiet",
|
|
52
|
+
]);
|
|
53
|
+
if (!repositories.includes("gcf-artifacts")) {
|
|
54
|
+
await runChildProcess("gcloud", [
|
|
55
|
+
"artifacts",
|
|
56
|
+
"repositories",
|
|
57
|
+
"create",
|
|
58
|
+
"gcf-artifacts",
|
|
59
|
+
"--repository-format=docker",
|
|
60
|
+
`--location=${region}`,
|
|
61
|
+
`--project=${projectId}`,
|
|
62
|
+
"--quiet",
|
|
63
|
+
]);
|
|
64
|
+
}
|
|
65
|
+
}, [], undefined, 5000);
|
|
66
|
+
};
|
|
67
|
+
const waitForEventarcServiceAgent = async (projectId, projectNumber) => {
|
|
68
|
+
const member = `serviceAccount:service-${projectNumber}@gcp-sa-eventarc.iam.gserviceaccount.com`;
|
|
69
|
+
const maxAttempts = 28;
|
|
70
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
71
|
+
const policy = await runChildProcess("gcloud", [
|
|
72
|
+
"projects",
|
|
73
|
+
"get-iam-policy",
|
|
74
|
+
projectId,
|
|
75
|
+
"--format=json",
|
|
76
|
+
"--quiet",
|
|
77
|
+
]);
|
|
78
|
+
const policyJson = JSON.parse(policy);
|
|
79
|
+
const hasRole = policyJson.bindings?.some((binding) => binding.role === "roles/eventarc.serviceAgent" && binding.members?.includes(member));
|
|
80
|
+
if (hasRole)
|
|
81
|
+
return;
|
|
82
|
+
if (attempt < maxAttempts - 1) {
|
|
83
|
+
await new Promise((resolve) => setTimeout(resolve, 15000));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
throw new Error("Eventarc service agent permissions were not propagated in time.");
|
|
87
|
+
};
|
|
88
|
+
export const isFunctionsDeployRetryable = (output) => output.includes("Eventarc Service Agent") ||
|
|
89
|
+
output.includes("HTTP Error: 400") ||
|
|
90
|
+
output.includes("HTTP Error: 429") ||
|
|
91
|
+
output.includes("failed to create function") ||
|
|
92
|
+
output.includes("2nd gen functions");
|
|
93
|
+
export const prepareInitialFunctionsDeploy = async (projectId, region) => {
|
|
94
|
+
const projectNumber = (await getProjectNumber(projectId)).trim();
|
|
95
|
+
await ensureApiEnabled(projectId, "pubsub.googleapis.com");
|
|
96
|
+
await ensureGcfArtifactsRepo(projectId, region);
|
|
97
|
+
for (const service of [
|
|
98
|
+
"eventarc.googleapis.com",
|
|
99
|
+
"cloudfunctions.googleapis.com",
|
|
100
|
+
"pubsub.googleapis.com",
|
|
101
|
+
"run.googleapis.com",
|
|
102
|
+
]) {
|
|
103
|
+
await ensureServiceIdentity(projectId, service);
|
|
104
|
+
}
|
|
105
|
+
await ensureIamBinding(projectId, `serviceAccount:service-${projectNumber}@gcp-sa-eventarc.iam.gserviceaccount.com`, "roles/eventarc.serviceAgent");
|
|
106
|
+
await ensureIamBinding(projectId, `serviceAccount:${projectNumber}-compute@developer.gserviceaccount.com`, "roles/eventarc.eventReceiver");
|
|
107
|
+
await ensureIamBinding(projectId, `serviceAccount:service-${projectNumber}@gcp-sa-pubsub.iam.gserviceaccount.com`, "roles/iam.serviceAccountTokenCreator");
|
|
108
|
+
await waitForEventarcServiceAgent(projectId, projectNumber);
|
|
109
|
+
};
|