diff --git a/bin/stacks/analytics-stack.ts b/bin/stacks/analytics-stack.ts index 68a9d300..7f6fc16d 100644 --- a/bin/stacks/analytics-stack.ts +++ b/bin/stacks/analytics-stack.ts @@ -38,8 +38,8 @@ enum RS_DATA_TYPES { } export interface AnalyticsStackProps extends cdk.NestedStackProps { - // quoteLambda: aws_lambda_nodejs.NodejsFunction; - // hardQuoteLambda: aws_lambda_nodejs.NodejsFunction; + quoteLambda: aws_lambda_nodejs.NodejsFunction; + hardQuoteLambda: aws_lambda_nodejs.NodejsFunction; envVars: Record; analyticsStreamArn: string; stage: string; @@ -62,7 +62,7 @@ export class AnalyticsStack extends cdk.NestedStack { constructor(scope: Construct, id: string, props: AnalyticsStackProps) { super(scope, id, props); - const { analyticsStreamArn, stage, chatbotSNSArn } = props; + const { quoteLambda, hardQuoteLambda, analyticsStreamArn, stage, chatbotSNSArn } = props; /* S3 Initialization */ const rfqRequestBucket = new aws_s3.Bucket(this, 'RfqRequestBucket'); @@ -1259,28 +1259,28 @@ export class AnalyticsStack extends cdk.NestedStack { new aws_logs.CfnSubscriptionFilter(this, 'RequestSub', { destinationArn: rfqRequestFirehoseStream.attrArn, filterPattern: '{ $.eventType = "QuoteRequest" }', - logGroupName: '/aws/lambda/beta-us-east-2-GoudaParameterization-QuoteE2906A56-dD269KqZUBHo', + logGroupName: quoteLambda.logGroup.logGroupName, roleArn: subscriptionRole.roleArn, }); new aws_logs.CfnSubscriptionFilter(this, 'ResponseSub', { destinationArn: rfqResponseFirehoseStream.attrArn, filterPattern: '{ $.eventType = "QuoteResponse" }', - logGroupName: '/aws/lambda/beta-us-east-2-GoudaParameterization-QuoteE2906A56-dD269KqZUBHo', + logGroupName: quoteLambda.logGroup.logGroupName, roleArn: subscriptionRole.roleArn, }); new aws_logs.CfnSubscriptionFilter(this, 'HardRequestSub', { destinationArn: hardRequestFirehoseStream.attrArn, filterPattern: '{ $.eventType = "HardRequest" }', - logGroupName: '/aws/lambda/beta-us-east-2-GoudaParameteriza-HardQuote29A66D69-nfILopzkGEIk', + logGroupName: hardQuoteLambda.logGroup.logGroupName, roleArn: subscriptionRole.roleArn, }); new aws_logs.CfnSubscriptionFilter(this, 'HardResponseSub', { destinationArn: hardResponseFirehoseStream.attrArn, filterPattern: '{ $.eventType = "HardResponse" }', - logGroupName: '/aws/lambda/beta-us-east-2-GoudaParameteriza-HardQuote29A66D69-nfILopzkGEIk', + logGroupName: hardQuoteLambda.logGroup.logGroupName, roleArn: subscriptionRole.roleArn, }); diff --git a/bin/stacks/api-stack.ts b/bin/stacks/api-stack.ts index c5a5b2f3..1067d356 100644 --- a/bin/stacks/api-stack.ts +++ b/bin/stacks/api-stack.ts @@ -2,17 +2,17 @@ import * as cdk from 'aws-cdk-lib'; import { CfnOutput, Duration } from 'aws-cdk-lib'; import * as aws_apigateway from 'aws-cdk-lib/aws-apigateway'; import { MethodLoggingLevel } from 'aws-cdk-lib/aws-apigateway'; -// import * as aws_asg from 'aws-cdk-lib/aws-applicationautoscaling'; +import * as aws_asg from 'aws-cdk-lib/aws-applicationautoscaling'; import * as aws_cloudwatch from 'aws-cdk-lib/aws-cloudwatch'; import * as aws_dynamo from 'aws-cdk-lib/aws-dynamodb'; import { CfnEIP, NatProvider, Vpc } from 'aws-cdk-lib/aws-ec2'; import * as aws_iam from 'aws-cdk-lib/aws-iam'; -// import * as aws_lambda from 'aws-cdk-lib/aws-lambda'; -// import * as aws_lambda_nodejs from 'aws-cdk-lib/aws-lambda-nodejs'; +import * as aws_lambda from 'aws-cdk-lib/aws-lambda'; +import * as aws_lambda_nodejs from 'aws-cdk-lib/aws-lambda-nodejs'; import * as aws_logs from 'aws-cdk-lib/aws-logs'; import * as aws_waf from 'aws-cdk-lib/aws-wafv2'; import { Construct } from 'constructs'; -// import * as path from 'path'; +import * as path from 'path'; import { KmsStack } from './kms-stack'; import { DYNAMO_TABLE_NAME } from '../../lib/constants'; @@ -25,7 +25,7 @@ import { import { STAGE } from '../../lib/util/stage'; import { PROD_TABLE_CAPACITY } from '../config'; import { SERVICE_NAME } from '../constants'; -// import { AnalyticsStack } from './analytics-stack'; +import { AnalyticsStack } from './analytics-stack'; import { CronDashboardStack } from './cron-dashboard-stack'; import { CronStack } from './cron-stack'; import { FirehoseStack } from './firehose-stack'; @@ -53,8 +53,7 @@ export class APIStack extends cdk.Stack { ) { super(parent, name, props); const region = cdk.Stack.of(this).region; - //const { provisionedConcurrency, internalApiKey, stage, chatbotSNSArn } = props; - const { internalApiKey, stage, chatbotSNSArn } = props; + const { provisionedConcurrency, internalApiKey, stage, chatbotSNSArn } = props; /* * API Gateway Initialization @@ -171,8 +170,7 @@ export class APIStack extends cdk.Stack { * Firehose Initialization */ - //const firehoseStack = - new FirehoseStack(this, 'FirehoseStack'); + const firehoseStack = new FirehoseStack(this, 'FirehoseStack'); /* * Lambda Initialization @@ -235,8 +233,7 @@ export class APIStack extends cdk.Stack { ], }); - // const vpc = - new Vpc(this, 'QuoteLambdaVpc', { + const vpc = new Vpc(this, 'QuoteLambdaVpc', { vpcName: 'QuoteLambdaVpc', natGateways: 1, natGatewayProvider: NatProvider.gateway({ @@ -245,176 +242,176 @@ export class APIStack extends cdk.Stack { maxAzs: 3, }); - // const quoteLambda = new aws_lambda_nodejs.NodejsFunction(this, 'Quote', { - // role: lambdaRole, - // runtime: aws_lambda.Runtime.NODEJS_18_X, - // entry: path.join(__dirname, '../../lib/handlers/quote/exports.ts'), - // handler: 'quoteHandler', - // vpc, - // vpcSubnets: { - // subnets: [...vpc.privateSubnets], - // }, - // memorySize: 2048, - // bundling: { - // minify: true, - // sourceMap: true, - // }, - // environment: { - // VERSION: '4', - // NODE_OPTIONS: '--enable-source-maps', - // ...props.envVars, - // stage, - // ANALYTICS_STREAM_ARN: firehoseStack.analyticsStreamArn, - // }, - // timeout: Duration.seconds(30), - // }); - - // const quoteLambdaAlias = new aws_lambda.Alias(this, `GetOrdersLiveAlias`, { - // aliasName: 'live', - // version: quoteLambda.currentVersion, - // provisionedConcurrentExecutions: provisionedConcurrency > 0 ? provisionedConcurrency : undefined, - // }); - - // const hardQuoteLambda = new aws_lambda_nodejs.NodejsFunction(this, 'HardQuote', { - // role: lambdaRole, - // runtime: aws_lambda.Runtime.NODEJS_18_X, - // entry: path.join(__dirname, '../../lib/handlers/hard-quote/exports.ts'), - // handler: 'hardQuoteHandler', - // vpc, - // vpcSubnets: { - // subnets: [...vpc.privateSubnets], - // }, - // memorySize: 2048, - // bundling: { - // minify: true, - // sourceMap: true, - // }, - // environment: { - // VERSION: '4', - // NODE_OPTIONS: '--enable-source-maps', - // REGION: region, - // KMS_KEY_ID: kmsStack.key.keyId, - // ...props.envVars, - // stage, - // ANALYTICS_STREAM_ARN: firehoseStack.analyticsStreamArn, - // }, - // timeout: Duration.seconds(30), - // }); - - // const hardQuoteLambdaAlias = new aws_lambda.Alias(this, `HardQuoteLiveAlias`, { - // aliasName: 'live', - // version: hardQuoteLambda.currentVersion, - // provisionedConcurrentExecutions: provisionedConcurrency > 0 ? provisionedConcurrency : undefined, - // }); - - // const switchLambda = new aws_lambda_nodejs.NodejsFunction(this, 'Switch', { - // role: lambdaRole, - // runtime: aws_lambda.Runtime.NODEJS_18_X, - // entry: path.join(__dirname, '../../lib/handlers/synth-switch/exports.ts'), - // handler: 'switchHandler', - // memorySize: 512, - // bundling: { - // minify: true, - // sourceMap: true, - // }, - // environment: { - // VERSION: '4', - // NODE_OPTIONS: '--enable-source-maps', - // ...props.envVars, - // stage, - // ANALYTICS_STREAM_ARN: firehoseStack.analyticsStreamArn, - // }, - // timeout: Duration.seconds(30), - // }); - - // const switchLambdaAlias = new aws_lambda.Alias(this, `SwitchLiveAlias`, { - // aliasName: 'live', - // version: switchLambda.currentVersion, - // provisionedConcurrentExecutions: 0, - // }); - - // if (provisionedConcurrency > 0) { - // const quoteTarget = new aws_asg.ScalableTarget(this, 'QuoteProvConcASG', { - // serviceNamespace: aws_asg.ServiceNamespace.LAMBDA, - // maxCapacity: provisionedConcurrency * 10, - // minCapacity: provisionedConcurrency, - // resourceId: `function:${quoteLambdaAlias.lambda.functionName}:${quoteLambdaAlias.aliasName}`, - // scalableDimension: 'lambda:function:ProvisionedConcurrency', - // }); - - // quoteTarget.node.addDependency(quoteLambdaAlias); - - // quoteTarget.scaleToTrackMetric('QuoteProvConcTracking', { - // targetValue: 0.7, - // predefinedMetric: aws_asg.PredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION, - // }); - // } - - // /* - // * APIG <> Lambda Integration - // */ - // const quoteLambdaIntegration = new aws_apigateway.LambdaIntegration(quoteLambdaAlias, {}); - // const quote = api.root.addResource('quote', { - // defaultCorsPreflightOptions: { - // allowOrigins: aws_apigateway.Cors.ALL_ORIGINS, - // allowMethods: aws_apigateway.Cors.ALL_METHODS, - // }, - // }); - // quote.addMethod('POST', quoteLambdaIntegration); - - // const hardQuoteLambdaIntegration = new aws_apigateway.LambdaIntegration(hardQuoteLambdaAlias, {}); - // const hardQuote = api.root.addResource('hard-quote', { - // defaultCorsPreflightOptions: { - // allowOrigins: aws_apigateway.Cors.ALL_ORIGINS, - // allowMethods: aws_apigateway.Cors.ALL_METHODS, - // }, - // }); - // hardQuote.addMethod('POST', hardQuoteLambdaIntegration); - - // const switchLambdaIntegration = new aws_apigateway.LambdaIntegration(switchLambdaAlias, {}); - // const switchResource = api.root.addResource('synthetic-switch', { - // defaultCorsPreflightOptions: { - // allowOrigins: aws_apigateway.Cors.ALL_ORIGINS, - // allowMethods: aws_apigateway.Cors.ALL_METHODS, - // }, - // }); - // const enabled = switchResource.addResource('enabled'); + const quoteLambda = new aws_lambda_nodejs.NodejsFunction(this, 'Quote', { + role: lambdaRole, + runtime: aws_lambda.Runtime.NODEJS_18_X, + entry: path.join(__dirname, '../../lib/handlers/quote/exports.ts'), + handler: 'quoteHandler', + vpc, + vpcSubnets: { + subnets: [...vpc.privateSubnets], + }, + memorySize: 2048, + bundling: { + minify: true, + sourceMap: true, + }, + environment: { + VERSION: '4', + NODE_OPTIONS: '--enable-source-maps', + ...props.envVars, + stage, + ANALYTICS_STREAM_ARN: firehoseStack.analyticsStreamArn, + }, + timeout: Duration.seconds(30), + }); + + const quoteLambdaAlias = new aws_lambda.Alias(this, `GetOrdersLiveAlias`, { + aliasName: 'live', + version: quoteLambda.currentVersion, + provisionedConcurrentExecutions: provisionedConcurrency > 0 ? provisionedConcurrency : undefined, + }); + + const hardQuoteLambda = new aws_lambda_nodejs.NodejsFunction(this, 'HardQuote', { + role: lambdaRole, + runtime: aws_lambda.Runtime.NODEJS_18_X, + entry: path.join(__dirname, '../../lib/handlers/hard-quote/exports.ts'), + handler: 'hardQuoteHandler', + vpc, + vpcSubnets: { + subnets: [...vpc.privateSubnets], + }, + memorySize: 2048, + bundling: { + minify: true, + sourceMap: true, + }, + environment: { + VERSION: '4', + NODE_OPTIONS: '--enable-source-maps', + REGION: region, + KMS_KEY_ID: kmsStack.key.keyId, + ...props.envVars, + stage, + ANALYTICS_STREAM_ARN: firehoseStack.analyticsStreamArn, + }, + timeout: Duration.seconds(30), + }); + + const hardQuoteLambdaAlias = new aws_lambda.Alias(this, `HardQuoteLiveAlias`, { + aliasName: 'live', + version: hardQuoteLambda.currentVersion, + provisionedConcurrentExecutions: provisionedConcurrency > 0 ? provisionedConcurrency : undefined, + }); + + const switchLambda = new aws_lambda_nodejs.NodejsFunction(this, 'Switch', { + role: lambdaRole, + runtime: aws_lambda.Runtime.NODEJS_18_X, + entry: path.join(__dirname, '../../lib/handlers/synth-switch/exports.ts'), + handler: 'switchHandler', + memorySize: 512, + bundling: { + minify: true, + sourceMap: true, + }, + environment: { + VERSION: '4', + NODE_OPTIONS: '--enable-source-maps', + ...props.envVars, + stage, + ANALYTICS_STREAM_ARN: firehoseStack.analyticsStreamArn, + }, + timeout: Duration.seconds(30), + }); + + const switchLambdaAlias = new aws_lambda.Alias(this, `SwitchLiveAlias`, { + aliasName: 'live', + version: switchLambda.currentVersion, + provisionedConcurrentExecutions: 0, + }); + + if (provisionedConcurrency > 0) { + const quoteTarget = new aws_asg.ScalableTarget(this, 'QuoteProvConcASG', { + serviceNamespace: aws_asg.ServiceNamespace.LAMBDA, + maxCapacity: provisionedConcurrency * 10, + minCapacity: provisionedConcurrency, + resourceId: `function:${quoteLambdaAlias.lambda.functionName}:${quoteLambdaAlias.aliasName}`, + scalableDimension: 'lambda:function:ProvisionedConcurrency', + }); + + quoteTarget.node.addDependency(quoteLambdaAlias); + + quoteTarget.scaleToTrackMetric('QuoteProvConcTracking', { + targetValue: 0.7, + predefinedMetric: aws_asg.PredefinedMetric.LAMBDA_PROVISIONED_CONCURRENCY_UTILIZATION, + }); + } + + /* + * APIG <> Lambda Integration + */ + const quoteLambdaIntegration = new aws_apigateway.LambdaIntegration(quoteLambdaAlias, {}); + const quote = api.root.addResource('quote', { + defaultCorsPreflightOptions: { + allowOrigins: aws_apigateway.Cors.ALL_ORIGINS, + allowMethods: aws_apigateway.Cors.ALL_METHODS, + }, + }); + quote.addMethod('POST', quoteLambdaIntegration); + + const hardQuoteLambdaIntegration = new aws_apigateway.LambdaIntegration(hardQuoteLambdaAlias, {}); + const hardQuote = api.root.addResource('hard-quote', { + defaultCorsPreflightOptions: { + allowOrigins: aws_apigateway.Cors.ALL_ORIGINS, + allowMethods: aws_apigateway.Cors.ALL_METHODS, + }, + }); + hardQuote.addMethod('POST', hardQuoteLambdaIntegration); + + const switchLambdaIntegration = new aws_apigateway.LambdaIntegration(switchLambdaAlias, {}); + const switchResource = api.root.addResource('synthetic-switch', { + defaultCorsPreflightOptions: { + allowOrigins: aws_apigateway.Cors.ALL_ORIGINS, + allowMethods: aws_apigateway.Cors.ALL_METHODS, + }, + }); + const enabled = switchResource.addResource('enabled'); /* add auth key */ - // const apiAuthzKey = api.addApiKey('AuthzKey'); - // const plan = api.addUsagePlan('AccessPlan', { - // name: 'AccessPlan', - // }); - // plan.addApiKey(apiAuthzKey); - // plan.addApiStage({ - // stage: api.deploymentStage, - // }); + const apiAuthzKey = api.addApiKey('AuthzKey'); + const plan = api.addUsagePlan('AccessPlan', { + name: 'AccessPlan', + }); + plan.addApiKey(apiAuthzKey); + plan.addApiStage({ + stage: api.deploymentStage, + }); - // enabled.addMethod('GET', switchLambdaIntegration, { apiKeyRequired: true }); + enabled.addMethod('GET', switchLambdaIntegration, { apiKeyRequired: true }); /* * Param Dashboard Stack Initialization */ new ParamDashboardStack(this, 'ParamDashboardStack', { - //quoteLambda, + quoteLambda, }); /* * Analytics Stack Initialization */ - // const analyticsStack = new AnalyticsStack(this, 'AnalyticsStack', { - // // quoteLambda, - // // hardQuoteLambda, - // envVars: props.envVars, - // analyticsStreamArn: firehoseStack.analyticsStreamArn, - // stage, - // chatbotSNSArn, - // }); + const analyticsStack = new AnalyticsStack(this, 'AnalyticsStack', { + quoteLambda, + hardQuoteLambda, + envVars: props.envVars, + analyticsStreamArn: firehoseStack.analyticsStreamArn, + stage, + chatbotSNSArn, + }); const cronStack = new CronStack(this, 'CronStack', { - RsDatabase: 'uniswap_x', - RsClusterIdentifier: 'parametrizationcluster2acf90d1-nv1fmfiwbsgj', - RedshiftCredSecretArn: 'arn:aws:secretsmanager:us-east-2:801328487475:secret:RsCredsD1DA9D21-wfkkcOIPjYTj-H9Py06', + RsDatabase: analyticsStack.dbName, + RsClusterIdentifier: analyticsStack.clusterId, + RedshiftCredSecretArn: analyticsStack.credSecretArn, lambdaRole: lambdaRole, chatbotSNSArn: chatbotSNSArn, stage: stage, @@ -422,7 +419,7 @@ export class APIStack extends cdk.Stack { new CronDashboardStack(this, 'CronDashboardStack', { synthSwitchLambdaName: cronStack.synthSwitchCronLambda.functionName, - quoteLambdaName: 'beta-us-east-2-GoudaParameterization-QuoteE2906A56-dD269KqZUBHo'//quoteLambda.functionName, + quoteLambdaName: quoteLambda.functionName, }); /* filler addr table */ diff --git a/bin/stacks/param-dashboard-stack.ts b/bin/stacks/param-dashboard-stack.ts index 9da7be2d..fe4977c9 100644 --- a/bin/stacks/param-dashboard-stack.ts +++ b/bin/stacks/param-dashboard-stack.ts @@ -1,6 +1,6 @@ import * as cdk from 'aws-cdk-lib'; import * as aws_cloudwatch from 'aws-cdk-lib/aws-cloudwatch'; -// import * as aws_lambda_nodejs from 'aws-cdk-lib/aws-lambda-nodejs'; +import * as aws_lambda_nodejs from 'aws-cdk-lib/aws-lambda-nodejs'; import * as lambda from 'aws-cdk-lib/aws-lambda'; import { Construct } from 'constructs'; @@ -287,7 +287,7 @@ const CircuitBreakerV2Widget = (region: string): LambdaWidget => { }; export interface DashboardProps extends cdk.NestedStackProps { - //quoteLambda: aws_lambda_nodejs.NodejsFunction; + quoteLambda: aws_lambda_nodejs.NodejsFunction; } // TODO: fetch dynamically from s3? @@ -310,7 +310,7 @@ export class ParamDashboardStack extends cdk.NestedStack { ErrorRatesWidget(region), RFQFailRatesWidget(region, RFQ_PROVIDERS), LambdaErrorRatesWidget(region, scope), - FailingRFQLogsWidget(region, 'arn:aws:logs:us-east-2:801328487475:log-group:/aws/lambda/beta-us-east-2-GoudaParameterization-QuoteE2906A56-dD269KqZUBHo:*'), + FailingRFQLogsWidget(region, props.quoteLambda.logGroup.logGroupArn), CircuitBreakerV2Widget(region), ].flat(), }),