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: updated telemetry with tags #37

Merged
merged 2 commits into from
May 9, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 2 additions & 0 deletions src/control-plane/auth/cognito-auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { Runtime, IFunction, LayerVersion } from 'aws-cdk-lib/aws-lambda';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { IAuth } from './auth-interface';
import { addTemplateTag } from '../../utils';

/**
* Properties for the CognitoAuth construct.
Expand Down Expand Up @@ -105,6 +106,7 @@ export class CognitoAuth extends Construct implements IAuth {

constructor(scope: Construct, id: string, props: CognitoAuthProps) {
super(scope, id);
addTemplateTag(this, 'CognitoAuth');

const idpName = 'COGNITO';
const systemAdminRoleName = props.systemAdminRoleName ?? 'SystemAdmin';
Expand Down
3 changes: 2 additions & 1 deletion src/control-plane/billing/billing-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { IFunction } from 'aws-cdk-lib/aws-lambda';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { IBilling, IFunctionTrigger } from './billing-interface';
import { DetailType, IEventManager } from '../../utils';
import { DetailType, IEventManager, addTemplateTag } from '../../utils';

/**
* Encapsulates the list of properties for a BillingProvider.
Expand Down Expand Up @@ -54,6 +54,7 @@ export class BillingProvider extends Construct {
*/
constructor(scope: Construct, id: string, props: BillingProviderProps) {
super(scope, id);
addTemplateTag(this, 'BillingProvider');
tobuck-aws marked this conversation as resolved.
Show resolved Hide resolved

this.createEventTarget(
props.eventManager,
Expand Down
3 changes: 2 additions & 1 deletion src/control-plane/control-plane-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { IAuth } from './auth/auth-interface';
import { Services } from './services';
import { addTemplateTag } from '../utils';

export interface ControlPlaneAPIProps {
readonly services: Services;
Expand All @@ -26,7 +27,7 @@ export class ControlPlaneAPI extends Construct {
public readonly tenantUpdateServiceTarget: targets.ApiGateway;
constructor(scope: Construct, id: string, props: ControlPlaneAPIProps) {
super(scope, id);

addTemplateTag(this, 'ControlPlaneAPI');
tobuck-aws marked this conversation as resolved.
Show resolved Hide resolved
let options: any = {
defaultCorsPreflightOptions: {
allowOrigins: apigateway.Cors.ALL_ORIGINS,
Expand Down
4 changes: 2 additions & 2 deletions src/control-plane/control-plane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Services } from './services';
import { Tables } from './tables';
import { TenantConfigService } from './tenant-config/tenant-config-service';
import { DestroyPolicySetter } from '../cdk-aspect/destroy-policy-setter';
import { setTemplateDesc, DetailType, EventManager, IEventManager } from '../utils';
import { addTemplateTag, DetailType, EventManager, IEventManager } from '../utils';

export interface ControlPlaneProps {
/**
Expand Down Expand Up @@ -55,7 +55,7 @@ export class ControlPlane extends Construct {

constructor(scope: Construct, id: string, props: ControlPlaneProps) {
super(scope, id);
setTemplateDesc(this, 'SaaS Builder Toolkit - CoreApplicationPlane (uksb-1tupboc57)');
addTemplateTag(this, 'ControlPlane');

cdk.Aspects.of(this).add(new DestroyPolicySetter());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import * as s3n from 'aws-cdk-lib/aws-s3-notifications';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { IDataIngestorAggregator } from './ingestor-aggregator-interface';
import { addTemplateTag } from '../../utils';

/**
* Encapsulates the list of properties for a FirehoseAggregator construct.
Expand Down Expand Up @@ -68,6 +69,7 @@ export class FirehoseAggregator extends Construct implements IDataIngestorAggreg

constructor(scope: Construct, id: string, props: FirehoseAggregatorProps) {
super(scope, id);
addTemplateTag(this, 'FirehoseAggregator');

const serviceName = 'FirehoseAggregator';

Expand Down
3 changes: 2 additions & 1 deletion src/control-plane/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Runtime, LayerVersion, Function } from 'aws-cdk-lib/aws-lambda';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { Tables } from './tables';
import { DetailType, IEventManager } from '../utils';
import { DetailType, IEventManager, addTemplateTag } from '../utils';

export interface ServicesProps {
readonly tables: Tables;
Expand All @@ -21,6 +21,7 @@ export class Services extends Construct {

constructor(scope: Construct, id: string, props: ServicesProps) {
super(scope, id);
addTemplateTag(this, 'Services');
tobuck-aws marked this conversation as resolved.
Show resolved Hide resolved

const tenantManagementExecRole = new Role(this, 'tenantManagementExecRole', {
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
Expand Down
3 changes: 2 additions & 1 deletion src/control-plane/tables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

import { Table, AttributeType, ProjectionType } from 'aws-cdk-lib/aws-dynamodb';
import { Construct } from 'constructs';
import { addTemplateTag } from '../utils';

export class Tables extends Construct {
public readonly tenantDetails: Table;
Expand All @@ -14,7 +15,7 @@ export class Tables extends Construct {
public readonly tenantIdColumn: string = 'tenantId';
constructor(scope: Construct, id: string) {
super(scope, id);

addTemplateTag(this, 'Tables');
this.tenantDetails = new Table(this, 'TenantDetails', {
partitionKey: { name: this.tenantIdColumn, type: AttributeType.STRING },
pointInTimeRecovery: true,
Expand Down
2 changes: 2 additions & 0 deletions src/control-plane/tenant-config/tenant-config-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Table } from 'aws-cdk-lib/aws-dynamodb';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { addTemplateTag } from '../../utils';

export interface TenantConfigServiceProps {
readonly tenantDetails: Table;
Expand All @@ -20,6 +21,7 @@ export class TenantConfigService extends Construct {
public readonly tenantConfigServiceLambda: lambda.Function;
constructor(scope: Construct, id: string, props: TenantConfigServiceProps) {
super(scope, id);
addTemplateTag(this, 'TenantConfigService');

// https://docs.powertools.aws.dev/lambda/python/2.31.0/#lambda-layer
const lambdaPowerToolsLayerARN = `arn:aws:lambda:${
Expand Down
2 changes: 2 additions & 0 deletions src/core-app-plane/bash-job-orchestrator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import * as tasks from 'aws-cdk-lib/aws-stepfunctions-tasks';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { BashJobRunner } from './bash-job-runner';
import { addTemplateTag } from '../utils';

/**
* Encapsulates the list of properties for a BashJobOrchestrator.
Expand Down Expand Up @@ -67,6 +68,7 @@ export class BashJobOrchestrator extends Construct {

constructor(scope: Construct, id: string, props: BashJobOrchestratorProps) {
super(scope, id);
addTemplateTag(this, 'BashJobOrchestrator');

const eventSource = props.eventSource;
const detailType = props.detailType;
Expand Down
3 changes: 3 additions & 0 deletions src/core-app-plane/bash-job-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as iam from 'aws-cdk-lib/aws-iam';
import * as kms from 'aws-cdk-lib/aws-kms';
import { NagSuppressions } from 'cdk-nag';
import { Construct } from 'constructs';
import { addTemplateTag } from '../utils';

/**
* Encapsulates the list of properties for a BashJobRunner.
Expand Down Expand Up @@ -75,6 +76,8 @@ export class BashJobRunner extends Construct {

constructor(scope: Construct, id: string, props: BashJobRunnerProps) {
super(scope, id);
addTemplateTag(this, 'BashJobRunner');

const environmentVariablesOverride: {
name: string;
value: string;
Expand Down
4 changes: 2 additions & 2 deletions src/core-app-plane/core-app-plane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import * as iam from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import { BashJobOrchestrator } from './bash-job-orchestrator';
import { BashJobRunner } from './bash-job-runner';
import { EventManager, IEventManager, DetailType, setTemplateDesc } from '../utils';
import { EventManager, IEventManager, DetailType, addTemplateTag } from '../utils';

/**
* Encapsulates the list of properties for a CoreApplicationPlaneJobRunner.
Expand Down Expand Up @@ -95,7 +95,7 @@ export class CoreApplicationPlane extends Construct {

constructor(scope: Construct, id: string, props: CoreApplicationPlaneProps) {
super(scope, id);
setTemplateDesc(this, 'SaaS Builder Toolkit - CoreApplicationPlane (uksb-1tupboc57)');
addTemplateTag(this, 'CoreApplicationPlane');
this.eventManager = props.eventManager ?? new EventManager(this, 'EventManager');
const eventBus = EventBus.fromEventBusArn(this, 'EventBus', this.eventManager.busArn);

Expand Down
2 changes: 2 additions & 0 deletions src/utils/event-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { IEventBus, Rule, IRuleTarget, EventBus } from 'aws-cdk-lib/aws-events';
import { IGrantable } from 'aws-cdk-lib/aws-iam';
import { Construct } from 'constructs';
import { addTemplateTag } from './utils';

/**
* Provides an easy way of accessing event detail types.
Expand Down Expand Up @@ -221,6 +222,7 @@ export class EventManager extends Construct implements IEventManager {

constructor(scope: Construct, id: string, props?: EventManagerProps) {
super(scope, id);
addTemplateTag(this, 'EventManager');
this.eventBus = props?.eventBus ?? new EventBus(this, 'SbtEventBus');
this.busName = this.eventBus.eventBusName;
this.busArn = this.eventBus.eventBusArn;
Expand Down
41 changes: 39 additions & 2 deletions src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,45 @@
import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';

export const setTemplateDesc = (construct: Construct, sbtDesc: string) => {
export const addTemplateTag = (construct: Construct, tag: string) => {
const stackDesc = Stack.of(construct).templateOptions.description;
let description = stackDesc === undefined ? sbtDesc : stackDesc + ' - ' + sbtDesc;
const baseTelemetry = 'SaaS Builder Toolkit (uksb-1tupboc57)';
tobuck-aws marked this conversation as resolved.
Show resolved Hide resolved
let description = stackDesc;
// There is no description, just make it telemetry + tags
if (stackDesc === undefined) {
description = appendTagToDescription(baseTelemetry, tag);
}
// There is a description, and it doesn't contain telemetry. We need to append telemetry + tags to it
else if (!stackDesc.includes(baseTelemetry)) {
description = appendTagToDescription(`${stackDesc} - ${baseTelemetry}`, tag);
}
// There is a telemetry description already
else {
description = appendTagToDescription(stackDesc, tag);
}
Stack.of(construct).templateOptions.description = description;
};

const appendTagToDescription = (existingDescription: string, newTag: string): string => {
// Check if the existing description already has tags
if (existingDescription.includes('(Tags:')) {
// Extract the existing tags
const startIndex = existingDescription.indexOf('(Tags:') + 6;
tobuck-aws marked this conversation as resolved.
Show resolved Hide resolved
const endIndex = existingDescription.lastIndexOf(')');
const existingTags = existingDescription.substring(startIndex, endIndex).split(', ');

// Check if the new tag already exists
if (!existingTags.includes(newTag)) {
// Append the new tag to the existing tags
existingTags.push(newTag);
const newDescription = `${existingDescription.substring(0, startIndex)}${existingTags.join(', ')})`;
return newDescription;
} else {
// The new tag already exists, return the original description
return existingDescription;
}
} else {
// Append the new tag to the description
return `${existingDescription} (Tags: ${newTag})`;
}
};
21 changes: 0 additions & 21 deletions test/control-plane.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,27 +91,6 @@ describe('ControlPlane Targets', () => {
});
});

describe('ControlPlane description', () => {
it('should have a fixed template description, when the containing stack does not have description', () => {
const stackWithoutDescription = new TestStack(app, 'stackWithoutDescription', {
systemAdminEmail: '[email protected]',
});
const actual = stackWithoutDescription.templateOptions.description;
const expected = 'SaaS Builder Toolkit - CoreApplicationPlane (uksb-1tupboc57)';
expect(actual).toStrictEqual(expected);
});

it('should have a concatenated template description, when the containing stack has an existing desc', () => {
const stackWithDescription = new TestStack(app, 'stackWithDescription', {
systemAdminEmail: '[email protected]',
description: 'ABC',
});
const actual = stackWithDescription.templateOptions.description;
const expected = 'ABC - SaaS Builder Toolkit - CoreApplicationPlane (uksb-1tupboc57)';
expect(expected).toStrictEqual(actual);
});
});

describe('ControlPlane cloudwatch roles', () => {
it('should create the cloudwatch IAM apigw push to cw role by default', () => {
const stackWithLogging = new TestStack(new cdk.App(), 'stackWithLogging', {
Expand Down
43 changes: 43 additions & 0 deletions test/utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0

import { App, Stack } from 'aws-cdk-lib';
import { addTemplateTag } from '../src/utils';
const app = new App();
const telemetryConst = 'SaaS Builder Toolkit (uksb-1tupboc57)';

describe('addTemplateTag', () => {
tobuck-aws marked this conversation as resolved.
Show resolved Hide resolved
it('should append telemetry and tags to existing template description', () => {
const stackA = new Stack(app, 'TestStackA', { description: 'test' });
const newTag = 'new-tag';
const expectedDescription = `test - ${telemetryConst} (Tags: new-tag)`;
addTemplateTag(stackA, newTag);
expect(stackA.templateOptions.description).toBe(expectedDescription);
});

it('should append a new tag to the description if it does not have any tags', () => {
const stackB = new Stack(app, 'TestStackB');
const newTag = 'new-tag';
const expectedDescription = `${telemetryConst} (Tags: new-tag)`;
addTemplateTag(stackB, newTag);
expect(stackB.templateOptions.description).toBe(expectedDescription);
});

it('should append a new tag to the existing tags in the description', () => {
const existingDescription = `This is a sample description - ${telemetryConst} (Tags: tag1, tag2)`;
const stackC = new Stack(app, 'TestStackC', { description: existingDescription });
const newTag = 'new-tag';
const expectedDescription = `This is a sample description - ${telemetryConst} (Tags: tag1, tag2, new-tag)`;
addTemplateTag(stackC, newTag);
expect(stackC.templateOptions.description).toBe(expectedDescription);
});

it('should not append a new tag if it already exists in the description', () => {
const existingDescription = `This is a sample description - ${telemetryConst} (Tags: tag1, tag2, new-tag)`;
const stackD = new Stack(app, 'TestStackD', { description: existingDescription });
const newTag = 'new-tag';
const expectedDescription = `This is a sample description - ${telemetryConst} (Tags: tag1, tag2, new-tag)`;
addTemplateTag(stackD, newTag);
expect(stackD.templateOptions.description).toBe(expectedDescription);
});
});
Loading