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(codeguruprofiler): ProfilingGroup #7895

Merged
merged 10 commits into from
May 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion packages/@aws-cdk/aws-codeguruprofiler/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,26 @@
---
<!--END STABILITY BANNER-->

This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project.
Amazon CodeGuru Profiler collects runtime performance data from your live applications, and provides recommendations that can help you fine-tune your application performance.

### Installation

Import to your project:

```ts
import * as codeguruprofiler from '@aws-cdk/aws-codeguruprofiler';
```

### Basic usage

Here's how to setup a profiling group and give your compute role permissions to publish to the profiling group to the profiling agent can publish profiling information:

```ts
// The execution role of your application that publishes to the ProfilingGroup via CodeGuru Profiler Profiling Agent. (the following is merely an example)
const publishAppRole = new Role(stack, 'PublishAppRole', {
SeekerWing marked this conversation as resolved.
Show resolved Hide resolved
assumedBy: new AccountRootPrincipal(),
});

const profilingGroup = new ProfilingGroup(stack, 'MyProfilingGroup');
profilingGroup.grantPublish(publishAppRole);
```
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-codeguruprofiler/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// AWS::CodeGuruProfiler CloudFormation Resources:
export * from './codeguruprofiler.generated';
export * from './profiling-group';
180 changes: 180 additions & 0 deletions packages/@aws-cdk/aws-codeguruprofiler/lib/profiling-group.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
import { Grant, IGrantable } from '@aws-cdk/aws-iam';
import { Construct, IResource, Lazy, Resource, Stack } from '@aws-cdk/core';
import { CfnProfilingGroup } from './codeguruprofiler.generated';

/**
* IResource represents a Profiling Group.
*/
export interface IProfilingGroup extends IResource {

/**
* A name for the profiling group.
*
* @attribute
*/
readonly profilingGroupName: string;
Copy link
Contributor

Choose a reason for hiding this comment

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

Can this be omitted? Can we produce a sensible default 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.

i've changed the approach to the following, not an expert by any means, let me know your thoughts.

physicalName: props.profilingGroupName || Lazy.stringValue({ produce: () => this.node.uniqueId })


/**
* Grant access to publish profiling information to the Profiling Group to the given identity.
*
* This will grant the following permissions:
*
* - codeguru-profiler:ConfigureAgent
* - codeguru-profiler:PostAgentProfile
*
* @param grantee Principal to grant publish rights to
*/
grantPublish(grantee: IGrantable): Grant;

/**
* Grant access to read profiling information from the Profiling Group to the given identity.
*
* This will grant the following permissions:
*
* - codeguru-profiler:GetProfile
* - codeguru-profiler:DescribeProfilingGroup
*
* @param grantee Principal to grant read rights to
*/
grantRead(grantee: IGrantable): Grant;

}

abstract class ProfilingGroupBase extends Resource implements IProfilingGroup {

public abstract readonly profilingGroupName: string;

public abstract readonly profilingGroupArn: string;

/**
* Grant access to publish profiling information to the Profiling Group to the given identity.
*
* This will grant the following permissions:
*
* - codeguru-profiler:ConfigureAgent
* - codeguru-profiler:PostAgentProfile
*
* @param grantee Principal to grant publish rights to
*/
public grantPublish(grantee: IGrantable) {
// https://docs.aws.amazon.com/codeguru/latest/profiler-ug/security-iam.html#security-iam-access-control
return Grant.addToPrincipal({
grantee,
actions: ['codeguru-profiler:ConfigureAgent', 'codeguru-profiler:PostAgentProfile'],
resourceArns: [this.profilingGroupArn],
});
}

/**
* Grant access to read profiling information from the Profiling Group to the given identity.
*
* This will grant the following permissions:
*
* - codeguru-profiler:GetProfile
* - codeguru-profiler:DescribeProfilingGroup
*
* @param grantee Principal to grant read rights to
*/
public grantRead(grantee: IGrantable) {
// https://docs.aws.amazon.com/codeguru/latest/profiler-ug/security-iam.html#security-iam-access-control
return Grant.addToPrincipal({
grantee,
actions: ['codeguru-profiler:GetProfile', 'codeguru-profiler:DescribeProfilingGroup'],
resourceArns: [this.profilingGroupArn],
});
}

}

/**
* Properties for creating a new Profiling Group.
*/
export interface ProfilingGroupProps {

/**
* A name for the profiling group.
* @default - automatically generated name.
*/
readonly profilingGroupName?: string;

}

/**
* A new Profiling Group.
*/
export class ProfilingGroup extends ProfilingGroupBase {

/**
* Import an existing Profiling Group provided a Profiling Group Name.
*
* @param scope The parent creating construct
* @param id The construct's name
* @param profilingGroupName Profiling Group Name
*/
public static fromProfilingGroupName(scope: Construct, id: string, profilingGroupName: string): IProfilingGroup {
const stack = Stack.of(scope);

return this.fromProfilingGroupArn(scope, id, stack.formatArn({
service: 'codeguru-profiler',
resource: 'profilingGroup',
resourceName: profilingGroupName,
}));
}

/**
* Import an existing Profiling Group provided an ARN.
*
* @param scope The parent creating construct
* @param id The construct's name
* @param profilingGroupArn Profiling Group ARN
*/
public static fromProfilingGroupArn(scope: Construct, id: string, profilingGroupArn: string): IProfilingGroup {
class Import extends ProfilingGroupBase {
public readonly profilingGroupName = Stack.of(scope).parseArn(profilingGroupArn).resource;
public readonly profilingGroupArn = profilingGroupArn;
}

return new Import(scope, id);
}

/**
* The name of the Profiling Group.
*
* @attribute
*/
public readonly profilingGroupName: string;

/**
* The ARN of the Profiling Group.
*
* @attribute
*/
public readonly profilingGroupArn: string;

eladb marked this conversation as resolved.
Show resolved Hide resolved
constructor(scope: Construct, id: string, props: ProfilingGroupProps = {}) {
super(scope, id, {
physicalName: props.profilingGroupName ?? Lazy.stringValue({ produce: () => this.generateUniqueId() }),
});

const profilingGroup = new CfnProfilingGroup(this, 'ProfilingGroup', {
profilingGroupName: this.physicalName,
});

this.profilingGroupName = this.getResourceNameAttribute(profilingGroup.ref);

this.profilingGroupArn = this.getResourceArnAttribute(profilingGroup.attrArn, {
service: 'codeguru-profiler',
resource: 'profilingGroup',
resourceName: this.physicalName,
});
}

private generateUniqueId(): string {
const name = this.node.uniqueId;
if (name.length > 240) {
return name.substring(0, 120) + name.substring(name.length - 120);
}
return name;
}

}
6 changes: 5 additions & 1 deletion packages/@aws-cdk/aws-codeguruprofiler/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,18 @@
"devDependencies": {
"@aws-cdk/assert": "0.0.0",
"cdk-build-tools": "0.0.0",
"cdk-integ-tools": "0.0.0",
"cfn2ts": "0.0.0",
"pkglint": "0.0.0"
},
"dependencies": {
"@aws-cdk/aws-iam": "0.0.0",
"@aws-cdk/core": "0.0.0"
},
"peerDependencies": {
"@aws-cdk/core": "0.0.0"
"@aws-cdk/core": "0.0.0",
"@aws-cdk/aws-iam": "0.0.0",
"constructs": "^3.0.2"
},
"engines": {
"node": ">= 10.13.0 <13 || >=13.7.0"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
{
"Resources": {
"MyProfilingGroup829F0507": {
"Type": "AWS::CodeGuruProfiler::ProfilingGroup",
"Properties": {
"ProfilingGroupName": "ProfilerGroupIntegrationTestMyProfilingGroup81DA69A3"
}
},
"PublishAppRole9FEBD682": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
}
}
}
],
"Version": "2012-10-17"
}
}
},
"PublishAppRoleDefaultPolicyCA1E15C3": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"codeguru-profiler:ConfigureAgent",
"codeguru-profiler:PostAgentProfile"
],
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": [
"MyProfilingGroup829F0507",
"Arn"
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "PublishAppRoleDefaultPolicyCA1E15C3",
"Roles": [
{
"Ref": "PublishAppRole9FEBD682"
}
]
}
},
"ReadAppRole52FE6317": {
"Type": "AWS::IAM::Role",
"Properties": {
"AssumeRolePolicyDocument": {
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": {
"Fn::Join": [
"",
[
"arn:",
{
"Ref": "AWS::Partition"
},
":iam::",
{
"Ref": "AWS::AccountId"
},
":root"
]
]
}
}
}
],
"Version": "2012-10-17"
}
}
},
"ReadAppRoleDefaultPolicy4BB8955C": {
"Type": "AWS::IAM::Policy",
"Properties": {
"PolicyDocument": {
"Statement": [
{
"Action": [
"codeguru-profiler:GetProfile",
"codeguru-profiler:DescribeProfilingGroup"
],
"Effect": "Allow",
"Resource": {
"Fn::GetAtt": [
"MyProfilingGroup829F0507",
"Arn"
]
}
}
],
"Version": "2012-10-17"
},
"PolicyName": "ReadAppRoleDefaultPolicy4BB8955C",
"Roles": [
{
"Ref": "ReadAppRole52FE6317"
}
]
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { AccountRootPrincipal, Role } from '@aws-cdk/aws-iam';
import { App, Stack, StackProps } from '@aws-cdk/core';
import { ProfilingGroup } from '../lib';

class ProfilerGroupIntegrationTest extends Stack {
constructor(scope: App, id: string, props?: StackProps) {
super(scope, id, props);

const profilingGroup = new ProfilingGroup(this, 'MyProfilingGroup');

const publishAppRole = new Role(this, 'PublishAppRole', {
assumedBy: new AccountRootPrincipal(),
});
profilingGroup.grantPublish(publishAppRole);

const readAppRole = new Role(this, 'ReadAppRole', {
assumedBy: new AccountRootPrincipal(),
});
profilingGroup.grantRead(readAppRole);

}
}

const app = new App();

new ProfilerGroupIntegrationTest(app, 'ProfilerGroupIntegrationTest');

app.synth();
Loading