123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.addResourcesToBackend = exports.addResourcesToBuild = exports.mergeRequiredAPIs = exports.discoverBackend = exports.discoverBuild = exports.useStrategy = void 0;
- const path = require("path");
- const _ = require("lodash");
- const child_process_1 = require("child_process");
- const error_1 = require("../../../../error");
- const logger_1 = require("../../../../logger");
- const backend = require("../../backend");
- const api = require("../../../../api");
- const proto = require("../../../../gcp/proto");
- const events = require("../../../../functions/events");
- const functional_1 = require("../../../../functional");
- const TRIGGER_PARSER = path.resolve(__dirname, "./triggerParser.js");
- function removeInspectOptions(options) {
- return options.filter((opt) => !opt.startsWith("--inspect"));
- }
- function parseTriggers(projectId, sourceDir, configValues, envs) {
- return new Promise((resolve, reject) => {
- const env = Object.assign({}, envs);
- env.GCLOUD_PROJECT = projectId;
- if (!_.isEmpty(configValues)) {
- env.CLOUD_RUNTIME_CONFIG = JSON.stringify(configValues);
- }
- const execArgv = removeInspectOptions(process.execArgv);
- if (env.NODE_OPTIONS) {
- env.NODE_OPTIONS = removeInspectOptions(env.NODE_OPTIONS.split(" ")).join(" ");
- }
- const parser = (0, child_process_1.fork)(TRIGGER_PARSER, [sourceDir], {
- silent: true,
- env: env,
- execArgv: execArgv,
- });
- parser.on("message", (message) => {
- if (message.triggers) {
- resolve(message.triggers);
- }
- else if (message.error) {
- reject(new error_1.FirebaseError(message.error, { exit: 1 }));
- }
- });
- parser.on("exit", (code) => {
- if (code !== 0) {
- reject(new error_1.FirebaseError("There was an unknown problem while trying to parse function triggers.", { exit: 2 }));
- }
- });
- });
- }
- function useStrategy() {
- return Promise.resolve(true);
- }
- exports.useStrategy = useStrategy;
- async function discoverBuild(projectId, sourceDir, runtime, configValues, envs) {
- const triggerAnnotations = await parseTriggers(projectId, sourceDir, configValues, envs);
- const want = {
- requiredAPIs: [],
- endpoints: {},
- params: [],
- };
- for (const annotation of triggerAnnotations) {
- addResourcesToBuild(projectId, runtime, annotation, want);
- }
- return want;
- }
- exports.discoverBuild = discoverBuild;
- async function discoverBackend(projectId, sourceDir, runtime, configValues, envs) {
- const triggerAnnotations = await parseTriggers(projectId, sourceDir, configValues, envs);
- const want = Object.assign(Object.assign({}, backend.empty()), { environmentVariables: envs });
- for (const annotation of triggerAnnotations) {
- addResourcesToBackend(projectId, runtime, annotation, want);
- }
- return want;
- }
- exports.discoverBackend = discoverBackend;
- function mergeRequiredAPIs(backend) {
- const apiToReasons = {};
- for (const { api, reason } of backend.requiredAPIs) {
- const reasons = apiToReasons[api] || new Set();
- if (reason) {
- reasons.add(reason);
- }
- apiToReasons[api] = reasons;
- }
- const merged = [];
- for (const [api, reasons] of Object.entries(apiToReasons)) {
- merged.push({ api, reason: Array.from(reasons).join(" ") });
- }
- backend.requiredAPIs = merged;
- }
- exports.mergeRequiredAPIs = mergeRequiredAPIs;
- function addResourcesToBuild(projectId, runtime, annotation, want) {
- var _a, _b;
- Object.freeze(annotation);
- const toSeconds = (0, functional_1.nullsafeVisitor)(proto.secondsFromDuration);
- const regions = annotation.regions || [api.functionsDefaultRegion];
- let triggered;
- const triggerCount = +!!annotation.httpsTrigger +
- +!!annotation.eventTrigger +
- +!!annotation.taskQueueTrigger +
- +!!annotation.blockingTrigger;
- if (triggerCount !== 1) {
- throw new error_1.FirebaseError("Unexpected annotation generated by the Firebase Functions SDK. This should never happen.");
- }
- if (annotation.taskQueueTrigger) {
- want.requiredAPIs.push({
- api: "cloudtasks.googleapis.com",
- reason: "Needed for task queue functions.",
- });
- triggered = {
- taskQueueTrigger: {},
- };
- proto.copyIfPresent(triggered.taskQueueTrigger, annotation.taskQueueTrigger, "invoker");
- proto.copyIfPresent(triggered.taskQueueTrigger, annotation.taskQueueTrigger, "rateLimits");
- if (annotation.taskQueueTrigger.retryConfig) {
- triggered.taskQueueTrigger.retryConfig = {};
- proto.copyIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxAttempts", "maxDoublings");
- proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "minBackoffSeconds", "minBackoff", toSeconds);
- proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxBackoffSeconds", "maxBackoff", toSeconds);
- proto.convertIfPresent(triggered.taskQueueTrigger.retryConfig, annotation.taskQueueTrigger.retryConfig, "maxRetrySeconds", "maxRetryDuration", toSeconds);
- }
- }
- else if (annotation.httpsTrigger) {
- if ((_a = annotation.labels) === null || _a === void 0 ? void 0 : _a["deployment-callable"]) {
- delete annotation.labels["deployment-callable"];
- triggered = { callableTrigger: {} };
- }
- else {
- const trigger = {};
- if (annotation.failurePolicy) {
- logger_1.logger.warn(`Ignoring retry policy for HTTPS function ${annotation.name}`);
- }
- if (annotation.httpsTrigger.invoker) {
- trigger.invoker = annotation.httpsTrigger.invoker;
- }
- triggered = { httpsTrigger: trigger };
- }
- }
- else if (annotation.schedule) {
- want.requiredAPIs.push({
- api: "cloudscheduler.googleapis.com",
- reason: "Needed for scheduled functions.",
- });
- triggered = {
- scheduleTrigger: {
- schedule: annotation.schedule.schedule,
- timeZone: (_b = annotation.schedule.timeZone) !== null && _b !== void 0 ? _b : null,
- retryConfig: {},
- },
- };
- if (annotation.schedule.retryConfig) {
- triggered.scheduleTrigger.retryConfig = {};
- proto.copyIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "retryCount", "maxDoublings");
- proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "maxRetrySeconds", "maxRetryDuration", toSeconds);
- proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "minBackoffSeconds", "minBackoffDuration", toSeconds);
- proto.convertIfPresent(triggered.scheduleTrigger.retryConfig, annotation.schedule.retryConfig, "maxBackoffSeconds", "maxBackoffDuration", toSeconds);
- }
- }
- else if (annotation.blockingTrigger) {
- if (events.v1.AUTH_BLOCKING_EVENTS.includes(annotation.blockingTrigger.eventType)) {
- want.requiredAPIs.push({
- api: "identitytoolkit.googleapis.com",
- reason: "Needed for auth blocking functions.",
- });
- }
- triggered = {
- blockingTrigger: {
- eventType: annotation.blockingTrigger.eventType,
- },
- };
- }
- else if (annotation.eventTrigger) {
- triggered = {
- eventTrigger: {
- eventType: annotation.eventTrigger.eventType,
- eventFilters: { resource: annotation.eventTrigger.resource },
- retry: !!annotation.failurePolicy,
- },
- };
- }
- else {
- throw new error_1.FirebaseError("Do not understand Cloud Function annotation without a trigger" +
- JSON.stringify(annotation, null, 2));
- }
- const endpointId = annotation.name;
- const endpoint = Object.assign({ platform: annotation.platform || "gcfv1", region: regions, project: projectId, entryPoint: annotation.entryPoint, runtime: runtime }, triggered);
- proto.renameIfPresent(endpoint, annotation, "serviceAccount", "serviceAccountEmail");
- if (annotation.vpcConnector != null) {
- endpoint.vpc = { connector: annotation.vpcConnector };
- proto.renameIfPresent(endpoint.vpc, annotation, "egressSettings", "vpcConnectorEgressSettings");
- }
- proto.copyIfPresent(endpoint, annotation, "concurrency", "labels", "maxInstances", "minInstances", "availableMemoryMb");
- proto.convertIfPresent(endpoint, annotation, "ingressSettings", (str) => {
- if (str === null) {
- return null;
- }
- if (!backend.AllIngressSettings.includes(str)) {
- throw new Error(`Invalid ingress setting ${str}`);
- }
- return str;
- });
- proto.convertIfPresent(endpoint, annotation, "timeoutSeconds", "timeout", proto.secondsFromDuration);
- if (annotation.secrets) {
- endpoint.secretEnvironmentVariables = annotation.secrets.map((secret) => {
- return {
- secret,
- projectId,
- key: secret,
- };
- });
- }
- want.endpoints[endpointId] = endpoint;
- }
- exports.addResourcesToBuild = addResourcesToBuild;
- function addResourcesToBackend(projectId, runtime, annotation, want) {
- var _a;
- Object.freeze(annotation);
- for (const region of annotation.regions || [api.functionsDefaultRegion]) {
- let triggered;
- const triggerCount = +!!annotation.httpsTrigger +
- +!!annotation.eventTrigger +
- +!!annotation.taskQueueTrigger +
- +!!annotation.blockingTrigger;
- if (triggerCount !== 1) {
- throw new error_1.FirebaseError("Unexpected annotation generated by the Firebase Functions SDK. This should never happen.");
- }
- if (annotation.taskQueueTrigger) {
- triggered = { taskQueueTrigger: annotation.taskQueueTrigger };
- want.requiredAPIs.push({
- api: "cloudtasks.googleapis.com",
- reason: "Needed for task queue functions.",
- });
- }
- else if (annotation.httpsTrigger) {
- if ((_a = annotation.labels) === null || _a === void 0 ? void 0 : _a["deployment-callable"]) {
- delete annotation.labels["deployment-callable"];
- triggered = { callableTrigger: {} };
- }
- else {
- const trigger = {};
- if (annotation.failurePolicy) {
- logger_1.logger.warn(`Ignoring retry policy for HTTPS function ${annotation.name}`);
- }
- proto.copyIfPresent(trigger, annotation.httpsTrigger, "invoker");
- triggered = { httpsTrigger: trigger };
- }
- }
- else if (annotation.schedule) {
- want.requiredAPIs.push({
- api: "cloudscheduler.googleapis.com",
- reason: "Needed for scheduled functions.",
- });
- triggered = { scheduleTrigger: annotation.schedule };
- }
- else if (annotation.blockingTrigger) {
- if (events.v1.AUTH_BLOCKING_EVENTS.includes(annotation.blockingTrigger.eventType)) {
- want.requiredAPIs.push({
- api: "identitytoolkit.googleapis.com",
- reason: "Needed for auth blocking functions.",
- });
- }
- triggered = {
- blockingTrigger: {
- eventType: annotation.blockingTrigger.eventType,
- options: annotation.blockingTrigger.options,
- },
- };
- }
- else {
- triggered = {
- eventTrigger: {
- eventType: annotation.eventTrigger.eventType,
- eventFilters: { resource: annotation.eventTrigger.resource },
- retry: !!annotation.failurePolicy,
- },
- };
- if (annotation.platform === "gcfv2") {
- if (annotation.eventTrigger.eventType === events.v2.PUBSUB_PUBLISH_EVENT) {
- triggered.eventTrigger.eventFilters = { topic: annotation.eventTrigger.resource };
- }
- if (events.v2.STORAGE_EVENTS.find((event) => { var _a; return event === (((_a = annotation.eventTrigger) === null || _a === void 0 ? void 0 : _a.eventType) || ""); })) {
- triggered.eventTrigger.eventFilters = { bucket: annotation.eventTrigger.resource };
- }
- }
- }
- const endpoint = Object.assign({ platform: annotation.platform || "gcfv1", id: annotation.name, region: region, project: projectId, entryPoint: annotation.entryPoint, runtime: runtime }, triggered);
- if (annotation.vpcConnector != null) {
- let maybeId = annotation.vpcConnector;
- if (maybeId && !maybeId.includes("/")) {
- maybeId = `projects/${projectId}/locations/${region}/connectors/${maybeId}`;
- }
- endpoint.vpc = { connector: maybeId };
- proto.renameIfPresent(endpoint.vpc, annotation, "egressSettings", "vpcConnectorEgressSettings");
- }
- if (annotation.secrets) {
- const secretEnvs = [];
- for (const secret of annotation.secrets) {
- const secretEnv = {
- secret,
- projectId,
- key: secret,
- };
- secretEnvs.push(secretEnv);
- }
- endpoint.secretEnvironmentVariables = secretEnvs;
- }
- proto.copyIfPresent(endpoint, annotation, "concurrency", "labels", "maxInstances", "minInstances");
- proto.renameIfPresent(endpoint, annotation, "serviceAccount", "serviceAccountEmail");
- proto.convertIfPresent(endpoint, annotation, "ingressSettings", (ingress) => {
- if (ingress == null) {
- return null;
- }
- if (!backend.AllIngressSettings.includes(ingress)) {
- throw new error_1.FirebaseError(`Invalid ingress setting ${ingress}`);
- }
- return ingress;
- });
- proto.convertIfPresent(endpoint, annotation, "availableMemoryMb", (mem) => {
- if (mem === null) {
- return null;
- }
- if (!backend.isValidMemoryOption(mem)) {
- throw new error_1.FirebaseError(`This version of firebase-tools does not know about the memory option ${mem}. Is an upgrade necessary?`);
- }
- return mem;
- });
- proto.convertIfPresent(endpoint, annotation, "timeoutSeconds", "timeout", proto.secondsFromDuration);
- want.endpoints[region] = want.endpoints[region] || {};
- want.endpoints[region][endpoint.id] = endpoint;
- mergeRequiredAPIs(want);
- }
- }
- exports.addResourcesToBackend = addResourcesToBackend;
|