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

Adds new alerting event provider #4258

Merged
merged 14 commits into from Mar 8, 2022
Merged

Adds new alerting event provider #4258

merged 14 commits into from Mar 8, 2022

Conversation

colerogers
Copy link
Contributor

@colerogers colerogers commented Mar 7, 2022

Adds Firebase Alerts as a deployable event provider.

firebase deploy --only functions

note: we cannot deploy until the container contract changes are merged

@colerogers colerogers marked this pull request as ready for review March 7, 2022 16:58
src/deploy/functions/services/firebaseAlerts.ts Outdated Show resolved Hide resolved
src/deploy/functions/triggerRegionHelper.ts Outdated Show resolved Hide resolved
projectId: string,
existingPolicy: iam.Policy
): Promise<Array<iam.Binding>> {
const projectNumber = await getProjectNumber({ projectId });
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd like for us to avoid making extra API call if possible; it adds small amount of delay in our deploy (though I agree that it isn't that much)

It looks like we are the only caller of ensureServiceAgentRoles which ultimately makes call to this function. Can we pass around projectNumber in prepare.ts so subsequent calls to getProjectNumber is properly cached instead of making one-off calls here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Great point, I added this fetch call in prepare and I passed both projectId & projectNumber into requireProjectBindings in the latest commit. I combined them into an object, let me know if you prefer them to be separate params

@colerogers colerogers requested a review from taeold March 8, 2022 01:27
src/deploy/functions/prepare.ts Outdated Show resolved Hide resolved
@@ -148,7 +148,7 @@ export function mergeBindings(policy: iam.Policy, allRequiredBindings: iam.Bindi
* @param have backend that we have currently deployed
*/
export async function ensureServiceAgentRoles(
projectId: string,
project: { projectId: string; projectNumber: string },
Copy link
Contributor

Choose a reason for hiding this comment

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

nit* In theory, having just projectNumber should be sufficient since all GCP API calls accept either projectId or projectNumber. Will leave it up to you to decide whether that would be appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh snap, I didn't realize treated them as interchangeable!!

requiredProjectBindings: ((pId: any, p: any) => Promise<Array<iam.Binding>>) | undefined;
ensureTriggerRegion: (ep: backend.Endpoint & backend.EventTriggered) => Promise<void>;
requiredProjectBindings:
| ((project: Project, policy: iam.Policy) => Promise<Array<iam.Binding>> | Array<iam.Binding>)
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this type got really complicated, what if we instead keep the original type signature and instead have obtainFirebaseAlertsBindings return a promise instead? e.g.

export function obtainFirebaseAlertsBindings(
  project: { projectId: string; projectNumber: string },
  existingPolicy: iam.Policy
): Promise<Array<iam.Binding>> {
  // ...implementation
  return Promise.resolve([pubsubBinding]);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed in the latest commit

requiredProjectBindings:
| ((project: Project, policy: iam.Policy) => Promise<Array<iam.Binding>> | Array<iam.Binding>)
| undefined;
ensureTriggerRegion: (ep: backend.Endpoint & backend.EventTriggered) => Promise<void> | void;
Copy link
Contributor

Choose a reason for hiding this comment

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

Same trick as I mentioned above - what if we "clean" this type up by requiring everything to return a promise - it is easy to make non-promise returning fns to return a promise instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed in the latest commit

src/deploy/functions/triggerRegionHelper.ts Outdated Show resolved Hide resolved
@colerogers colerogers merged commit e9ce087 into master Mar 8, 2022
@colerogers colerogers deleted the colerogers.firealerts branch March 8, 2022 20:11
src/deploy/functions/checkIam.ts Show resolved Hide resolved
* @param projectId project identifier
* @param existingPolicy the project level IAM policy
*/
export function obtainFirebaseAlertsBindings(
Copy link
Member

Choose a reason for hiding this comment

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

Is this really a Firebase Alerts feature or something that all event providers are going to need?

Copy link
Member

Choose a reason for hiding this comment

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

NVM. See below comments. I think we could have had something like:

export function obtainFirebaseAlertBindings(projectNumber) {
  iam.ensureBinding(firebaseAlertRole, firebaseAlertPermission)
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're correct, this is not a Firebase Alerts specific binding. It was yanked in #4324 and I added a noop instead

Comment on lines +18 to +32
const pubsubServiceAgent = `serviceAccount:service-${projectNumber}@gcp-sa-pubsub.iam.gserviceaccount.com`;
let pubsubBinding = existingPolicy.bindings.find(
(b) => b.role === SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE
);
if (!pubsubBinding) {
pubsubBinding = {
role: SERVICE_ACCOUNT_TOKEN_CREATOR_ROLE,
members: [],
};
}
if (!pubsubBinding.members.find((m) => m === pubsubServiceAgent)) {
pubsubBinding.members.push(pubsubServiceAgent);
}
return Promise.resolve([pubsubBinding]);
}
Copy link
Member

Choose a reason for hiding this comment

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

This logic happens over and over and over again in our codebase. Maybe we should have something in gcp/iam.ts that ensures a binding exists or is removed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SGTM, I believe that @taeold was thinking of refactoring our IAM code to look more like the Fabricator code

/** A firebase alerts service object */
export const FirebaseAlertsService: Service = {
name: "firebasealerts",
api: "logging.googleapis.com",
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 really the API for Firebase Alerts?? How is this not a conflict with Cloud Audit Logs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was just a placeholder, I'll update it with the correct API. Additionally, this field is not currently being used in the CLI

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants