UNPKG

firebase-tools

Version:
156 lines (155 loc) 8.01 kB
"use strict"; 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;