Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Annotate function triggers with __endpoint property #999

Merged
merged 27 commits into from
Nov 22, 2021

Conversation

taeold
Copy link
Contributor

@taeold taeold commented Oct 27, 2021

In addition to annotating function triggers with __trigger property, we add __endpoint annotation. This property will be used by the to-be-developed functions runtime to generate/declare deployment manifest that the CLI will use to deploy the function.

There are lots of code duplication between the utility functions for annotating the __trigger and __endpoint properties. I didn't try to refactor the common code since I expect that we will favor __endpoint property in the future.

@google-cla google-cla bot added the cla: yes label Oct 27, 2021
@taeold taeold requested review from inlined and colerogers October 27, 2021 22:19
Copy link
Member

@inlined inlined left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. My comments are more about what the contract should actually be. It's possible that this is a hint we should be sending this through API review.

spec/v1/cloud-functions.spec.ts Outdated Show resolved Hide resolved
spec/v2/providers/https.spec.ts Outdated Show resolved Hide resolved
spec/v2/providers/pubsub.spec.ts Outdated Show resolved Hide resolved
src/cloud-functions.ts Outdated Show resolved Hide resolved
src/cloud-functions.ts Outdated Show resolved Hide resolved
src/v2/providers/https.ts Outdated Show resolved Hide resolved
src/v2/providers/https.ts Outdated Show resolved Hide resolved
@taeold taeold changed the base branch from master to dl-container-contract October 29, 2021 16:22
@taeold taeold marked this pull request as ready for review November 8, 2021 22:24
Copy link
Contributor

@colerogers colerogers left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few questions, also do you want to add a CHANGELOG entry for these changes?

},
};
copyIfPresent(endpoint.eventTrigger, opts, 'retry', 'retry');
func.__endpoint = endpoint;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We seem to be alternating between using Object.defineProperty() and directly setting the property in the v2 providers. Would it be beneficial to stick with one format for all the providers?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have mixed feels. We could always use define property because it's safest, but it is a bit arcane and is only needed for endpoint types that rely on firebaseConfig (RTDB and Storage)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've been leaning towards "don't use defineProperty() unless we have to. And we have to use defineProperty() in some cases b/c user code will throw an error if environment variables like FIREBASE_CONFIG does not exist (which we use to define a trigger, like default bucket info).

eventTrigger: {
eventType: eventType,
eventFilters: {
bucket,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yay! So much easier to add new filters 🎆

@@ -322,9 +333,9 @@ export interface MakeCloudFunctionArgs<EventData> {
dataConstructor?: (raw: Event) => EventData;
eventType: string;
handler?: (data: EventData, context: EventContext) => PromiseLike<any> | any;
labels?: { [key: string]: any };
labels?: Record<string, string>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a risk that some projects might have non-string values here? If so, are we releasing this as a breaking change?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The backend never accepted anything but a string.

Copy link
Contributor Author

@taeold taeold Nov 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So my understanding is - yes this is breaking but uses who used anything other than string would not have succeeded in deploying a function with non-string. This seems okay to do.

legacyEventType?: string;
options?: { [key: string]: any };
options?: DeploymentOptions;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same question as above, what if projects don't have options that fit into DeploymentOptions?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another good point. Fortunately, no one should be calling makeCloudFunction directly, and in our public APIs, we make sure that passed options are typed with DeploymentOption. e.g.

private options: DeploymentOptions

Think we should be okay making this change.

@@ -322,9 +333,9 @@ export interface MakeCloudFunctionArgs<EventData> {
dataConstructor?: (raw: Event) => EventData;
eventType: string;
handler?: (data: EventData, context: EventContext) => PromiseLike<any> | any;
labels?: { [key: string]: any };
labels?: Record<string, string>;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The backend never accepted anything but a string.

src/cloud-functions.ts Outdated Show resolved Hide resolved
options,
'vpc',
'vpcConnectorEgressSettings',
(egressSettings, vpc) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing to me. Is this an edit in place as an optional second parameter? I'm wondering if a more explicit approach will be clearer since now convertIfPresent only works when the calls are in the right order.

Maybe something vaguely like:

const vpc: <whateverthetypeishere> = {};
convertIfPresent(vpc, options, 'connector', 'vpcConnector');
convertIfPresent(vpc, options, 'egressSettings', 'vpcConnectorEgressSettings');
if (Object.keys(vpc).length !== 0) {
  endpoint.vpc = vpc;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair. I agree that the suggested code is simpler!

src/common/manifest.ts Outdated Show resolved Hide resolved
options,
'invoker',
'invoker',
convertInvoker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't convertInvoker turn foo@ into foo@project.gserviceaccount.com and we didn't want that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have that kind of logic for service accounts:

export function serviceAccountFromShorthand(
serviceAccount: string
): string | null {
if (serviceAccount === 'default') {
return null;
} else if (serviceAccount.endsWith('@')) {
if (!process.env.GCLOUD_PROJECT) {
throw new Error(
`Unable to determine email for service account '${serviceAccount}' because process.env.GCLOUD_PROJECT is not set.`
);
}
return `${serviceAccount}${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`;
} else if (serviceAccount.includes('@')) {
return serviceAccount;
} else {
throw new Error(
`Invalid option for serviceAccount: '${serviceAccount}'. Valid options are 'default', a service account email, or '{serviceAccountName}@'`
);
}
}

But not for invoker - we only do light validation checks, e.g. to make sure that invoker option with public or private doesn't conflict, etc.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep the shorthand syntax in the manifest so we can stay project-independent.

src/v2/providers/pubsub.ts Show resolved Hide resolved
},
};
copyIfPresent(endpoint.eventTrigger, opts, 'retry', 'retry');
func.__endpoint = endpoint;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have mixed feels. We could always use define property because it's safest, but it is a bit arcane and is only needed for endpoint types that rely on firebaseConfig (RTDB and Storage)

@taeold taeold merged commit a6c4971 into dl-container-contract Nov 22, 2021
taeold added a commit that referenced this pull request Nov 22, 2021
In addition to annotating function triggers with `__trigger` property, we add `__endpoint` annotation. This property will be used by the to-be-developed functions runtime to generate/declare deployment manifest that the CLI will use to deploy the function.

There are lots of code duplication between the utility functions for annotating the `__trigger` and `__endpoint` properties. I didn't try to refactor the common code since I expect that we will favor `__endpoint` property in the future.
taeold added a commit that referenced this pull request Dec 10, 2021
Follows up #999 to annotate each funuctions with `__endpoint` property.

Highlight of changes:

* Extend unit test coverage for all v1 providers
* Add `__endpoint` annotation to v1 task queue functions
* Add `__requiredAPIs` annotation to task queue and scheduler functions
* Explicitly set `__endpoint` to undefined in the handler namespace
* No SDK-level label setting in the __endpoint annotation.
taeold added a commit that referenced this pull request Jan 19, 2022
* Annotate function triggers with __endpoint property (#999)

In addition to annotating function triggers with `__trigger` property, we add `__endpoint` annotation. This property will be used by the to-be-developed functions runtime to generate/declare deployment manifest that the CLI will use to deploy the function.

There are lots of code duplication between the utility functions for annotating the `__trigger` and `__endpoint` properties. I didn't try to refactor the common code since I expect that we will favor `__endpoint` property in the future.

* Add missing import.

* More of annotate endpoint property for functions (#1009)

Follows up #999 to annotate each funuctions with `__endpoint` property.

Highlight of changes:

* Extend unit test coverage for all v1 providers
* Add `__endpoint` annotation to v1 task queue functions
* Add `__requiredAPIs` annotation to task queue and scheduler functions
* Explicitly set `__endpoint` to undefined in the handler namespace
* No SDK-level label setting in the __endpoint annotation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants