-
Notifications
You must be signed in to change notification settings - Fork 902
/
ensureApiEnabled.ts
134 lines (124 loc) · 4.18 KB
/
ensureApiEnabled.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
import { bold } from "cli-color";
import * as track from "./track";
import { serviceUsageOrigin } from "./api";
import { Client } from "./apiv2";
import * as utils from "./utils";
import { FirebaseError, isBillingError } from "./error";
export const POLL_SETTINGS = {
pollInterval: 10000,
pollsBeforeRetry: 12,
};
const apiClient = new Client({
urlPrefix: serviceUsageOrigin,
apiVersion: "v1",
});
/**
* Check if the specified API is enabled.
* @param projectId The project on which to check enablement.
* @param apiName The name of the API e.g. `someapi.googleapis.com`.
* @param prefix The logging prefix to use when printing messages about enablement.
* @param silent Whether or not to print log messages.
*/
export async function check(
projectId: string,
apiName: string,
prefix: string,
silent = false
): Promise<boolean> {
const res = await apiClient.get<{ state: string }>(`/projects/${projectId}/services/${apiName}`);
const isEnabled = res.body.state === "ENABLED";
if (isEnabled && !silent) {
utils.logLabeledSuccess(prefix, `required API ${bold(apiName)} is enabled`);
}
return isEnabled;
}
/**
* Attempt to enable an API on the specified project (just once).
*
* If enabling an API for a customer, prefer `ensure` which will check for the
* API first, which is a seperate permission than enabling.
*
* @param projectId The project in which to enable the API.
* @param apiName The name of the API e.g. `someapi.googleapis.com`.
*/
async function enable(projectId: string, apiName: string): Promise<void> {
try {
await apiClient.post(`/projects/${projectId}/services/${apiName}:enable`);
} catch (err) {
if (isBillingError(err)) {
throw new FirebaseError(`Your project ${bold(
projectId
)} must be on the Blaze (pay-as-you-go) plan to complete this command. Required API ${bold(
apiName
)} can't be enabled until the upgrade is complete. To upgrade, visit the following URL:
https://console.firebase.google.com/project/${projectId}/usage/details`);
}
throw err;
}
}
async function pollCheckEnabled(
projectId: string,
apiName: string,
prefix: string,
silent: boolean,
enablementRetries: number,
pollRetries = 0
): Promise<void> {
if (pollRetries > POLL_SETTINGS.pollsBeforeRetry) {
// eslint-disable-next-line @typescript-eslint/no-use-before-define
return enableApiWithRetries(projectId, apiName, prefix, silent, enablementRetries + 1);
}
await new Promise((resolve) => {
setTimeout(resolve, POLL_SETTINGS.pollInterval);
});
const isEnabled = await check(projectId, apiName, prefix, silent);
if (isEnabled) {
void track("api_enabled", apiName);
return;
}
if (!silent) {
utils.logLabeledBullet(prefix, `waiting for API ${bold(apiName)} to activate...`);
}
return pollCheckEnabled(projectId, apiName, prefix, silent, enablementRetries, pollRetries + 1);
}
async function enableApiWithRetries(
projectId: string,
apiName: string,
prefix: string,
silent: boolean,
enablementRetries = 0
): Promise<void> {
if (enablementRetries > 1) {
throw new FirebaseError(
`Timed out waiting for API ${bold(apiName)} to enable. Please try again in a few minutes.`
);
}
await enable(projectId, apiName);
return pollCheckEnabled(projectId, apiName, prefix, silent, enablementRetries);
}
/**
* Check if an API is enabled on a project, try to enable it if not with polling and retries.
*
* @param projectId The project on which to check enablement.
* @param apiName The name of the API e.g. `someapi.googleapis.com`.
* @param prefix The logging prefix to use when printing messages about enablement.
* @param silent Whether or not to print log messages.
*/
export async function ensure(
projectId: string,
apiName: string,
prefix: string,
silent = false
): Promise<void> {
if (!silent) {
utils.logLabeledBullet(prefix, `ensuring required API ${bold(apiName)} is enabled...`);
}
const isEnabled = await check(projectId, apiName, prefix, silent);
if (isEnabled) {
return;
}
if (!silent) {
utils.logLabeledWarning(prefix, `missing required API ${bold(apiName)}. Enabling now...`);
}
return enableApiWithRetries(projectId, apiName, prefix, silent);
}