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

feat(ecs-service-extensions): Publish Extension #16326

Merged
merged 17 commits into from
Sep 17, 2021

Conversation

upparekh
Copy link
Contributor

@upparekh upparekh commented Sep 1, 2021


This PR adds a new service extension, PublisherExtension. This extension can be added to a service to allow it to publish events to SNS Topics. (This PR when paired with #16049 can be used to set up the pub/ sub architecture pattern)

It sets up publish permissions for the service to be able to publish events to the topics provided. The user can also provide a list of accounts that will be given permissions to subscribe to the given topics.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license

@gitpod-io
Copy link

gitpod-io bot commented Sep 1, 2021

@upparekh upparekh self-assigned this Sep 1, 2021
@upparekh upparekh added the @aws-cdk-containers/ecs-service-extensions Related to ecs-service-extensions package label Sep 1, 2021
@upparekh upparekh force-pushed the upparekh/publish-service-extension branch 2 times, most recently from 25a6359 to df0d027 Compare September 1, 2021 21:54
@bvtujo bvtujo added the pr/do-not-merge This PR should not be merged at this time. label Sep 3, 2021
@bvtujo
Copy link
Contributor

bvtujo commented Sep 3, 2021

Looks really good! Just had some docs nits that you can address or not as you want. Feel free to remove the label and get it merged.

@mergify mergify bot dismissed bvtujo’s stale review September 3, 2021 17:50

Pull request has been modified.

@upparekh upparekh removed the pr/do-not-merge This PR should not be merged at this time. label Sep 3, 2021
Comment on lines 15 to 21
export interface IPublisher {
publish(taskDefinition: ecs.TaskDefinition): void;

envVarKey(): string;

envVarValue(): string;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This interface doesn't look quite right to me...It's difficult to related envVarKey and envVarValue with IPublisher

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes I agree, these aren't related to the actual 'publish' functionality that we want to provide the users. But if these aren't added to the interface, we will end up doing instanceof type checks later in the code and we wanted to avoid such logic and find the most common interface. That's why envVarKey and envVarValue were added to the interface itself.

Comment on lines 64 to 75
public publish(taskDefinition: ecs.TaskDefinition) {
this.topic.grantPublish(taskDefinition.taskRole);
}

public envVarKey(): string {
return this.topic.node.id;
}

public envVarValue(): string {
return this.topic.topicArn;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

hmm these function only contain one line logic. I wonder if we want this extension since it doesn't seem to bring a lot of convenience for users. Could you remind me how users are going to publish to a topic without this extension, so that we can better evaluate the value of bring this extra public extension 🙏

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 extension helps set up the publish permissions for SNS Topics and optionally restrict subscribe permissions to particular accounts. The simplest use case for setting up the publish permissions can be done by calling topic.grantPublish(taskDefinition.taskRole) .

This extension might seem to be more useful after we add more IPublisher resources perhaps? (like publishing to an EventBus)

Comment on lines 11 to 18
/**
* An interface that will be implemented by all the resources that can be published events to.
*/
export interface IPublisher {
publish(taskDefinition: ecs.TaskDefinition): void;

environmentVar(): { [key: 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.

You know I think this is a neat interface, but it doesn't have to do much with being a publisher. For example, adding a DynamoDB table as an extension could be done by implementing this interface as well.

I see @iamhopaul123 's point (#16326 (comment)), what do you think of renaming this extension and interface like this?

export interface Injectable {
   environmentVariables(): { [key: string]: string };
}

export interface GrantInjectable extends Injectable {
   grant(taskDefinition: ecs.TaskDefinition): void;
}

SNS topics can implement this interface, S3 buckets, or DynamoDB tables for example.
In the future, to add RDS for example as an injected we can create another interface ConnectInjectable.

Copy link
Contributor

Choose a reason for hiding this comment

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

The name of of the extension will be: InjecterExtension.

and it will take as input injectables: []Injectable
Then we can loop through each injectable and do this:

for (const injectable of injectables) {
  if (injectable as GrantInjectable).grant !== undefined {
     injectable.grant(taskDef)
  }
  merge(this.environment, injectable.environmentVariables())
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Let me know what y'all think!

Copy link
Contributor

Choose a reason for hiding this comment

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

That makes a lot of sense to me! I think overall the concern here is: when we design a new interface, we need to think it as an interface instead of a concrete class.

Copy link
Contributor Author

@upparekh upparekh Sep 15, 2021

Choose a reason for hiding this comment

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

SNS topics can implement this interface, S3 buckets, or DynamoDB tables for example.
In the future, to add RDS for example as an injected we can create another interface ConnectInjectable.

This sounds super cool ❤️

Copy link
Contributor

@efekarakus efekarakus left a comment

Choose a reason for hiding this comment

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

Looks great! Just some doc recommendations and a small request for the env variables 🚀

@@ -19,7 +19,8 @@ The `Service` construct provided by this module can be extended with optional `S
- [AWS AppMesh](https://aws.amazon.com/app-mesh/) for adding your application to a service mesh
- [Application Load Balancer](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/introduction.html), for exposing your service to the public
- [AWS FireLens](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_firelens.html), for filtering and routing application logs
- Queue to allow your service to consume messages from an SQS Queue which is populated by one or more SNS Topics that it is subscribed to
- [Injecter Extension](#injecter-extension), for allowing your service to publish events to resources like SNS Topics
Copy link
Contributor

Choose a reason for hiding this comment

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

nit:

Suggested change
- [Injecter Extension](#injecter-extension), for allowing your service to publish events to resources like SNS Topics
- [Injecter Extension](#injecter-extension), for allowing your service to connect to other AWS services by granting permission and injecting environment variables.

@@ -322,9 +323,26 @@ const environment = Environment.fromEnvironmentAttributes(stack, 'Environment',

```

## Injecter Extension

This service extension accepts a list of `Injectable` resources that the service can publish events or write data to and sets up the corresponding permissions for the service.
Copy link
Contributor

Choose a reason for hiding this comment

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

I wanna avoid saying publish events specifically in the first sentence. The Injectable interface can be implemented by various resource. But we can give an example with InjectableTopic.

Suggested change
This service extension accepts a list of `Injectable` resources that the service can publish events or write data to and sets up the corresponding permissions for the service.
This service extension accepts a list of `Injectable` resources that grants access to the resources and adds the necessary environment variables to the tasks part of the service.
For example, an `InjectableTopic` is an SNS topic that grants permission to the task role and adds the topic name as an environment variable to the task definition.

feel free to change the wording!


The following example adds the `InjecterExtension` to a `Publisher` Service which can publish events to an SNS Topic and adds the `QueueExtension` to a `Worker` Service which can poll its `eventsQueue` to consume messages populated by the topic.

```ts
Copy link
Contributor

Choose a reason for hiding this comment

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

Awesome example! 🤩


for (const injectable of this.props.injectables) {
for (const [key, val] of Object.entries(injectable.environmentVariables())) {
this.environment[`${service.id.toUpperCase()}_${key}`] = val;
Copy link
Contributor

Choose a reason for hiding this comment

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

so will this create an environment variable like:

PUBLISHER_MYTOPIC_TOPIC_ARN

Was there a reason why you prefered to prefix with the service.id? I think customers that implement the Injectable interface might expect their environment variable to appear as is 💭

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it creates PUBLISHER_MYTOPIC_TOPIC_ARN .

The service.id was added as a prefix to distinguish between topics in cases of collision, when two topics with same name are created in different services.

Copy link
Contributor

Choose a reason for hiding this comment

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

gotcha, I think since this works a bit different than copi where users create their own topics, I think we should pass the env var as is!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense!

efekarakus
efekarakus previously approved these changes Sep 16, 2021
@mergify
Copy link
Contributor

mergify bot commented Sep 16, 2021

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@upparekh upparekh force-pushed the upparekh/publish-service-extension branch from 6dac16d to 8e92b07 Compare September 17, 2021 00:18
@mergify mergify bot dismissed efekarakus’s stale review September 17, 2021 00:19

Pull request has been modified.

@mergify
Copy link
Contributor

mergify bot commented Sep 17, 2021

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@aws-cdk-automation
Copy link
Collaborator

AWS CodeBuild CI Report

  • CodeBuild project: AutoBuildProject89A8053A-LhjRyN9kxr8o
  • Commit ID: e76126c
  • Result: SUCCEEDED
  • Build Logs (available for 30 days)

Powered by github-codebuild-logs, available on the AWS Serverless Application Repository

@mergify mergify bot merged commit c6c5941 into aws:master Sep 17, 2021
@mergify
Copy link
Contributor

mergify bot commented Sep 17, 2021

Thank you for contributing! Your pull request will be updated from master and then merged automatically (do not update manually, and be sure to allow changes to be pushed to your fork).

@upparekh upparekh deleted the upparekh/publish-service-extension branch September 17, 2021 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
@aws-cdk-containers/ecs-service-extensions Related to ecs-service-extensions package
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants