Skip to content

Commit

Permalink
Create new endpoint type definition (#3731)
Browse files Browse the repository at this point in the history
* Create new endpoint type definition

* Fix build breaks

* Remove HttpsTrigger.allowInsecure

* Formatter

* Add type discrimiation functions and fix break
  • Loading branch information
inlined committed Sep 3, 2021
1 parent 013c3c2 commit 98058cc
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 39 deletions.
109 changes: 84 additions & 25 deletions src/deploy/functions/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import * as runtimes from "./runtimes";
import { FirebaseError } from "../../error";
import { Context } from "./args";
import { previews } from "../../previews";
import { backendFromV1Alpha1 } from "./runtimes/discovery/v1alpha1";

/** Retry settings for a ScheduleSpec. */
export interface ScheduleRetryConfig {
Expand All @@ -26,27 +27,40 @@ export interface PubSubSpec {
targetService: TargetIds;
}

/** API agnostic version of a CloudScheduler Job */
export interface ScheduleSpec {
id: string;
project: string;
export interface ScheduleTrigger {
// Note: schedule is missing in the existingBackend because we
// don't actually spend the API call looking up the schedule;
// we just infer identifiers from function labels.
schedule?: string;
timeZone?: string;
retryConfig?: ScheduleRetryConfig;
}

/** API agnostic version of a CloudScheduler Job */
export interface ScheduleSpec extends ScheduleTrigger {
id: string;
project: string;
transport: "pubsub" | "https";

// What we're actually planning to invoke with this schedule
targetService: TargetIds;
}

/** Something that has a ScheduleTrigger */
export interface ScheduleTriggered {
scheduleTrigger: ScheduleTrigger;
}

/** API agnostic version of a Cloud Function's HTTPs trigger. */
export interface HttpsTrigger {
invoker?: string[];
}

/** Something that has an HTTPS trigger */
export interface HttpsTriggered {
httpsTrigger: HttpsTrigger;
}

/** Well known keys in the eventFilter attribute of an event trigger */
export type EventFilterKey = "resource";

Expand Down Expand Up @@ -91,6 +105,11 @@ export interface EventTrigger {
serviceAccountEmail?: string;
}

/** Something that has an EventTrigger */
export interface EventTriggered {
eventTrigger: EventTrigger;
}

/** Type deduction helper for a function trigger. */
export function isEventTrigger(trigger: HttpsTrigger | EventTrigger): trigger is EventTrigger {
return "eventType" in trigger;
Expand Down Expand Up @@ -155,15 +174,7 @@ export interface TargetIds {
project: string;
}

export type FunctionsPlatform = "gcfv1" | "gcfv2";

/** An API agnostic definition of a Cloud Function. */
export interface FunctionSpec extends TargetIds {
platform: FunctionsPlatform;
entryPoint: string;
trigger: HttpsTrigger | EventTrigger;
runtime: runtimes.Runtime | runtimes.DeprecatedRuntime;

export interface ServiceConfiguration {
concurrency?: number;
labels?: Record<string, string>;
environmentVariables?: Record<string, string>;
Expand All @@ -175,14 +186,64 @@ export interface FunctionSpec extends TargetIds {
vpcConnectorEgressSettings?: VpcEgressSettings;
ingressSettings?: IngressSettings;
serviceAccountEmail?: "default" | string;
}

// Output only:
/** An API agnostic definition of a Cloud Function. */
export type FunctionSpec = TargetIds &
ServiceConfiguration & {
entryPoint: string;
platform: FunctionsPlatform;
runtime: runtimes.Runtime | runtimes.DeprecatedRuntime;
trigger: EventTrigger | HttpsTrigger;

// Output only

// URI is available on GCFv1 for HTTPS triggers and
// on GCFv2 always
uri?: string;
sourceUploadUrl?: string;
};

export type FunctionsPlatform = "gcfv1" | "gcfv2";

type Triggered = HttpsTriggered | EventTriggered | ScheduleTriggered;

/** Whether something has an HttpsTrigger */
export function isHttpsTriggered(triggered: Triggered): triggered is HttpsTriggered {
return {}.hasOwnProperty.call(triggered, "httpsTrigger");
}

/** Whether something has an EventTrigger */
export function isEventTriggered(triggered: Triggered): triggered is EventTriggered {
return {}.hasOwnProperty.call(triggered, "eventTrigger");
}

// present for v1 functions with HTTP triggers and v2 functions always.
uri?: string;
sourceUploadUrl?: string;
/** Whether something has a ScheduleTrigger */
export function isScheduleTriggered(triggered: Triggered): triggered is ScheduleTriggered {
return {}.hasOwnProperty.call(triggered, "scheduleTrigger");
}

/**
* An endpoint that serves traffic to a stack of services.
* For now, this is always a Cloud Function. Future iterations may use complex
* type unions to enforce that _either_ the Stack is all Functions or the
* stack is all Services.
*/
export type Endpoint = TargetIds &
ServiceConfiguration &
Triggered & {
entryPoint: string;
platform: FunctionsPlatform;
runtime: runtimes.Runtime | runtimes.DeprecatedRuntime;

// Output only

// URI is available on GCFv1 for HTTPS triggers and
// on GCFv2 always
uri?: string;
sourceUploadUrl?: string;
};

/** An API agnostic definition of an entire deployment a customer has or wants. */
export interface Backend {
/**
Expand All @@ -195,6 +256,7 @@ export interface Backend {
schedules: ScheduleSpec[];
topics: PubSubSpec[];
environmentVariables: EnvironmentVariables;
endpoints: Endpoint[];
}

/**
Expand All @@ -205,6 +267,7 @@ export interface Backend {
export function empty(): Backend {
return {
requiredAPIs: {},
endpoints: [],
cloudFunctions: [],
schedules: [],
topics: [],
Expand Down Expand Up @@ -259,7 +322,7 @@ export const sameFunctionName = (func: TargetIds) => (test: TargetIds): boolean
* Gets the formal resource name for a Cloud Scheduler job.
* @param appEngineLocation Must be the region where the customer has enabled App Engine.
*/
export function scheduleName(schedule: ScheduleSpec, appEngineLocation: string) {
export function scheduleName(schedule: ScheduleSpec, appEngineLocation: string): string {
return `projects/${schedule.project}/locations/${appEngineLocation}/jobs/${schedule.id}`;
}

Expand All @@ -268,7 +331,7 @@ export function scheduleName(schedule: ScheduleSpec, appEngineLocation: string)
* @param topic Something that implements project/id. This is intentionally vauge so
* that a schedule can be passed and the topic name generated.
*/
export function topicName(topic: { project: string; id: string }) {
export function topicName(topic: { project: string; id: string }): string {
return `projects/${topic.project}/topics/${topic.id}`;
}

Expand All @@ -282,7 +345,7 @@ export function topicName(topic: { project: string; id: string }) {
* If you change this pattern, Firebase console will stop displaying schedule descriptions
* and schedules created under the old pattern will no longer be cleaned up correctly
*/
export function scheduleIdForFunction(cloudFunction: TargetIds) {
export function scheduleIdForFunction(cloudFunction: TargetIds): string {
return `firebase-schedule-${cloudFunction.id}-${cloudFunction.region}`;
}

Expand Down Expand Up @@ -323,11 +386,7 @@ async function loadExistingBackend(ctx: Context & PrivateContextFields): Promise
// Note: is it worth deducing the APIs that must have been enabled for this backend to work?
// it could reduce redundant API calls for enabling the APIs.
ctx.existingBackend = {
requiredAPIs: {},
cloudFunctions: [],
schedules: [],
topics: [],
environmentVariables: {},
...empty(),
};
ctx.unreachableRegions = {
gcfV1: [],
Expand Down
2 changes: 2 additions & 0 deletions src/deploy/functions/runtimes/discovery/v1alpha1.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ function tryValidate(typed: backend.Backend) {
// Use a helper type to help guide code complete when writing this function
assertKeyTypes("", typed, {
requiredAPIs: "object",
endpoints: "array",
cloudFunctions: "array",
topics: "array",
schedules: "array",
Expand Down Expand Up @@ -129,6 +130,7 @@ function fillDefaults(
want.environmentVariables = want.environmentVariables || {};
want.schedules = want.schedules || [];
want.topics = want.topics || [];
want.endpoints = want.endpoints || [];

for (const cloudFunction of want.cloudFunctions) {
if (!cloudFunction.project) {
Expand Down
21 changes: 7 additions & 14 deletions src/test/deploy/functions/deploymentPlanner.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,18 +211,16 @@ describe("deploymentPlanner", () => {
const topic2 = topic(r2f1);

const want: backend.Backend = {
requiredAPIs: {},
...backend.empty(),
cloudFunctions: [r1f1, r1f2, r2f1],
schedules: [r1sched1, r1sched2, r2sched1],
topics: [topic1, topic2],
environmentVariables: {},
};
const have: backend.Backend = {
requiredAPIs: {},
...backend.empty(),
cloudFunctions: [r1f1, r2f1],
schedules: [r1sched1],
topics: [topic1],
environmentVariables: {},
};
const filters: string[][] = [];

Expand Down Expand Up @@ -324,20 +322,17 @@ describe("deploymentPlanner", () => {
const topic1 = topic(f1);
const topic2 = topic(f2);

// Deployment plan: deleete f1 and the schedule from f2
// Deployment plan: delete f1 and the schedule from f2
const want: backend.Backend = {
requiredAPIs: {},
...backend.empty(),
cloudFunctions: [f2],
schedules: [],
topics: [topic2],
environmentVariables: {},
};
const have: backend.Backend = {
requiredAPIs: {},
...backend.empty(),
cloudFunctions: [f1, f2],
schedules: [schedule1, schedule2],
topics: [topic1, topic2],
environmentVariables: {},
};
const filters: string[][] = [];

Expand Down Expand Up @@ -384,19 +379,17 @@ describe("deploymentPlanner", () => {
const group2topic2 = topic(group2func2);

const want: backend.Backend = {
requiredAPIs: {},
...backend.empty(),
cloudFunctions: [group1func1, group1func2, group2func1],
schedules: [group1schedule1, group2schedule1],
topics: [group1topic1, group2topic1],
environmentVariables: {},
};

const have: backend.Backend = {
requiredAPIs: {},
...backend.empty(),
cloudFunctions: [group1func1, group1func3, group1func4, group2func2],
schedules: [group1schedule1, group1schedule3, group2schedule2],
topics: [group1topic1, group1topic3, group2topic2],
environmentVariables: {},
};

const filters = [["group"]];
Expand Down

0 comments on commit 98058cc

Please sign in to comment.