firebase-tools
Version:
Command-Line Interface for Firebase
156 lines (155 loc) • 8.01 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUpdateReason = exports.cloudSQLBeingCreated = exports.setupCloudSql = void 0;
const clc = require("colorette");
const cloudSqlAdminClient = require("../gcp/cloudsql/cloudsqladmin");
const logger_1 = require("../logger");
const checkIam_1 = require("./checkIam");
const freeTrial_1 = require("./freeTrial");
const utils_1 = require("../utils");
const track_1 = require("../track");
const utils = require("../utils");
const cloudbilling_1 = require("../gcp/cloudbilling");
const GOOGLE_ML_INTEGRATION_ROLE = "roles/aiplatform.user";
async function setupCloudSql(args) {
var _a;
const { projectId, instanceId, requireGoogleMlIntegration, dryRun } = args;
const startTime = Date.now();
const stats = { action: "get" };
let success = false;
try {
await upsertInstance(stats, Object.assign({}, args));
success = true;
}
finally {
if (!dryRun) {
void (0, track_1.trackGA4)("dataconnect_cloud_sql", {
source: args.source,
action: success ? stats.action : `${stats.action}_error`,
location: args.location,
enable_google_ml_integration: args.requireGoogleMlIntegration.toString(),
database_version: ((_a = stats.databaseVersion) === null || _a === void 0 ? void 0 : _a.toLowerCase()) || "unknown",
dataconnect_label: stats.dataconnectLabel || "unknown",
}, Date.now() - startTime);
}
}
if (requireGoogleMlIntegration && !dryRun) {
await (0, checkIam_1.grantRolesToCloudSqlServiceAccount)(projectId, instanceId, [GOOGLE_ML_INTEGRATION_ROLE]);
}
}
exports.setupCloudSql = setupCloudSql;
async function upsertInstance(stats, args) {
var _a, _b;
const { projectId, instanceId, requireGoogleMlIntegration, dryRun } = args;
try {
const existingInstance = await cloudSqlAdminClient.getInstance(projectId, instanceId);
utils.logLabeledBullet("dataconnect", `Found existing Cloud SQL instance ${clc.bold(instanceId)}.`);
stats.databaseVersion = existingInstance.databaseVersion;
stats.dataconnectLabel =
((_b = (_a = existingInstance.settings) === null || _a === void 0 ? void 0 : _a.userLabels) === null || _b === void 0 ? void 0 : _b["firebase-data-connect"]) || "absent";
const why = getUpdateReason(existingInstance, requireGoogleMlIntegration);
if (why) {
if (dryRun) {
utils.logLabeledBullet("dataconnect", `Cloud SQL instance ${clc.bold(instanceId)} settings are not compatible with Firebase Data Connect. ` +
`It will be updated on your next deploy.` +
why);
}
else {
utils.logLabeledBullet("dataconnect", `Cloud SQL instance ${clc.bold(instanceId)} settings are not compatible with Firebase Data Connect. ` +
why);
stats.action = "update";
await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.updateInstanceForDataConnect(existingInstance, requireGoogleMlIntegration), "Updating your Cloud SQL instance...");
}
}
await upsertDatabase(Object.assign({}, args));
}
catch (err) {
if (err.status !== 404) {
throw err;
}
stats.action = "create";
stats.databaseVersion = cloudSqlAdminClient.DEFAULT_DATABASE_VERSION;
const freeTrialUsed = await (0, freeTrial_1.checkFreeTrialInstanceUsed)(projectId);
stats.dataconnectLabel = freeTrialUsed ? "nt" : "ft";
await createInstance(Object.assign(Object.assign({}, args), { freeTrialLabel: stats.dataconnectLabel }));
}
}
async function createInstance(args) {
const { projectId, location, instanceId, requireGoogleMlIntegration, dryRun, freeTrialLabel } = args;
if (dryRun) {
utils.logLabeledBullet("dataconnect", `Cloud SQL Instance ${clc.bold(instanceId)} not found. It will be created on your next deploy.`);
}
else {
await cloudSqlAdminClient.createInstance({
projectId,
location,
instanceId,
enableGoogleMlIntegration: requireGoogleMlIntegration,
freeTrialLabel,
});
utils.logLabeledBullet("dataconnect", cloudSQLBeingCreated(projectId, instanceId, freeTrialLabel === "ft", await (0, cloudbilling_1.checkBillingEnabled)(projectId)));
}
}
function cloudSQLBeingCreated(projectId, instanceId, isFreeTrial, billingEnabled) {
return (`Cloud SQL Instance ${clc.bold(instanceId)} is being created.` +
(isFreeTrial
? `\nThis instance is provided under the terms of the Data Connect no-cost trial ${(0, freeTrial_1.freeTrialTermsLink)()}`
: "") +
`\n
Meanwhile, your data are saved in a temporary database and will be migrated once complete.` +
(isFreeTrial && !billingEnabled
? `
Your free trial instance won't show in google cloud console until a billing account is added.
However, you can still use the gcloud cli to monitor your database instance:\n\n\te.g. gcloud sql instances list --project ${projectId}\n`
: `
Monitor its progress at\n\n\t${cloudSqlAdminClient.instanceConsoleLink(projectId, instanceId)}\n`));
}
exports.cloudSQLBeingCreated = cloudSQLBeingCreated;
async function upsertDatabase(args) {
const { projectId, instanceId, databaseId, dryRun } = args;
try {
await cloudSqlAdminClient.getDatabase(projectId, instanceId, databaseId);
utils.logLabeledBullet("dataconnect", `Found existing Postgres Database ${databaseId}.`);
}
catch (err) {
if (err.status !== 404) {
logger_1.logger.debug(`Unexpected error from Cloud SQL: ${err}`);
utils.logLabeledWarning("dataconnect", `Postgres Database ${databaseId} is not accessible.`);
return;
}
if (dryRun) {
utils.logLabeledBullet("dataconnect", `Postgres Database ${databaseId} not found. It will be created on your next deploy.`);
}
else {
await cloudSqlAdminClient.createDatabase(projectId, instanceId, databaseId);
utils.logLabeledBullet("dataconnect", `Postgres Database ${databaseId} created.`);
}
}
}
function getUpdateReason(instance, requireGoogleMlIntegration) {
var _a, _b, _c, _d, _e, _f;
let reason = "";
const settings = instance.settings;
if (!((_a = settings.ipConfiguration) === null || _a === void 0 ? void 0 : _a.ipv4Enabled)) {
utils.logLabeledWarning("dataconnect", `Cloud SQL instance ${clc.bold(instance.name)} does not have a public IP.
${clc.bold("firebase dataconnect:sql:migrate")} will only work within its VPC (e.g. GCE, GKE).`);
if (((_b = settings.ipConfiguration) === null || _b === void 0 ? void 0 : _b.privateNetwork) &&
!((_c = settings.ipConfiguration) === null || _c === void 0 ? void 0 : _c.enablePrivatePathForGoogleCloudServices)) {
reason += "\n - to enable Private Path for Google Cloud Services.";
}
}
if (requireGoogleMlIntegration) {
if (!settings.enableGoogleMlIntegration) {
reason += "\n - to enable Google ML integration.";
}
if (!((_d = settings.databaseFlags) === null || _d === void 0 ? void 0 : _d.some((f) => f.name === "cloudsql.enable_google_ml_integration" && f.value === "on"))) {
reason += "\n - to enable Google ML integration database flag.";
}
}
const isIamEnabled = (_f = (_e = settings.databaseFlags) === null || _e === void 0 ? void 0 : _e.some((f) => f.name === "cloudsql.iam_authentication" && f.value === "on")) !== null && _f !== void 0 ? _f : false;
if (!isIamEnabled) {
reason += "\n - to enable IAM authentication database flag.";
}
return reason;
}
exports.getUpdateReason = getUpdateReason;