Skip to content

Commit

Permalink
implement backent into cdk
Browse files Browse the repository at this point in the history
  • Loading branch information
pinzon committed Nov 26, 2024
1 parent 06affcc commit eeecc36
Show file tree
Hide file tree
Showing 11 changed files with 248 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ __pycache__
# LocalStack

volume/
.idea
28 changes: 28 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env python3
import os

import aws_cdk as cdk

from quiz_app.quiz_app_stack import QuizAppStack


app = cdk.App()
QuizAppStack(app, "QuizAppStack",
# If you don't specify 'env', this stack will be environment-agnostic.
# Account/Region-dependent features and context lookups will not work,
# but a single synthesized template can be deployed anywhere.

# Uncomment the next line to specialize this stack for the AWS Account
# and Region that are implied by the current CLI configuration.

#env=cdk.Environment(account=os.getenv('CDK_DEFAULT_ACCOUNT'), region=os.getenv('CDK_DEFAULT_REGION')),

# Uncomment the next line if you know exactly what Account and Region you
# want to deploy the stack to. */

#env=cdk.Environment(account='123456789012', region='us-east-1'),

# For more information, see https://docs.aws.amazon.com/cdk/latest/guide/environments.html
)

app.synth()
66 changes: 66 additions & 0 deletions cdk.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
{
"app": "python3 app.py",
"watch": {
"include": [
"**"
],
"exclude": [
"README.md",
"cdk*.json",
"requirements*.txt",
"source.bat",
"**/__init__.py",
"**/__pycache__",
"tests"
]
},
"context": {
"@aws-cdk/aws-lambda:recognizeLayerVersion": true,
"@aws-cdk/core:checkSecretUsage": true,
"@aws-cdk/core:target-partitions": [
"aws",
"aws-cn"
],
"@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true,
"@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true,
"@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true,
"@aws-cdk/aws-iam:minimizePolicies": true,
"@aws-cdk/core:validateSnapshotRemovalPolicy": true,
"@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true,
"@aws-cdk/aws-s3:createDefaultLoggingPolicy": true,
"@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true,
"@aws-cdk/aws-apigateway:disableCloudWatchRole": true,
"@aws-cdk/core:enablePartitionLiterals": true,
"@aws-cdk/aws-events:eventsTargetQueueSameAccount": true,
"@aws-cdk/aws-iam:standardizedServicePrincipals": true,
"@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true,
"@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true,
"@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true,
"@aws-cdk/aws-route53-patters:useCertificate": true,
"@aws-cdk/customresources:installLatestAwsSdkDefault": false,
"@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true,
"@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true,
"@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true,
"@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true,
"@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true,
"@aws-cdk/aws-redshift:columnId": true,
"@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true,
"@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true,
"@aws-cdk/aws-apigateway:requestValidatorUniqueId": true,
"@aws-cdk/aws-kms:aliasNameRef": true,
"@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true,
"@aws-cdk/core:includePrefixInUniqueNameGeneration": true,
"@aws-cdk/aws-efs:denyAnonymousAccess": true,
"@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true,
"@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true,
"@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true,
"@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true,
"@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true,
"@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true,
"@aws-cdk/aws-codepipeline-actions:useNewDefaultBranchForCodeCommitSource": true,
"@aws-cdk/aws-cloudwatch-actions:changeLambdaPermissionLogicalIdForLambdaAction": true,
"@aws-cdk/aws-codepipeline:crossAccountKeysDefaultValueToFalse": true,
"@aws-cdk/aws-codepipeline:defaultPipelineTypeToV2": true,
"@aws-cdk/aws-kms:reduceCrossAccountRegionPolicyScope": true
}
}
Empty file added quiz_app/__init__.py
Empty file.
122 changes: 122 additions & 0 deletions quiz_app/quiz_app_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import json
from pathlib import Path
from tty import CFLAG

import aws_cdk
from aws_cdk import (
# Duration,
Stack,
aws_sqs as sqs,
aws_dynamodb as dynamodb,
aws_iam as iam,
aws_lambda as _lambda,
CfnOutput as Output
)
from constructs import Construct

class QuizAppStack(Stack):

def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)

# TABLES
quizzes_table = dynamodb.Table(
self,
"QuizzesTable",
table_name="Quizzes",
partition_key=dynamodb.Attribute(
name="QuizID",
type=dynamodb.AttributeType.STRING,
),
billing_mode=dynamodb.BillingMode.PROVISIONED,
read_capacity=5,
write_capacity=5,
)

user_submissions_table = dynamodb.Table(
self,
"UserSubmissionsTable",
table_name="UserSubmissions",
partition_key=dynamodb.Attribute(
name="SubmissionID",
type=dynamodb.AttributeType.STRING,
),
billing_mode=dynamodb.BillingMode.PROVISIONED,
read_capacity=5,
write_capacity=5,
)
user_submissions_table.add_global_secondary_index(
index_name="QuizID-Score-index",
partition_key=dynamodb.Attribute(
name="QuizID",
type=dynamodb.AttributeType.STRING,
),
sort_key=dynamodb.Attribute(
name="Score",
type=dynamodb.AttributeType.NUMBER,
),
projection_type=dynamodb.ProjectionType.ALL,
read_capacity=5,
write_capacity=5,
)

Output(self, "QuizTable", value=quizzes_table.table_name)
Output(self, "UserSubmissionsTable", value=user_submissions_table.table_name)


functions_and_roles = [
("CreateQuizFunction","configurations/create_quiz_policy.json","CreateQuizRole", "lambdas/get_quiz/handler.py"),
("GetQuizFunction","configurations/get_quiz_policy.json","GetQuizRole", "lambdas/get_quiz/handler.py"),
("SubmitQuizFunction","configurations/submit_quiz_policy.json", "SubmitQuizRole", "lambdas/submit_quiz/handler.py"),
("ScoringFunction", "configurations/scoring_policy.json", "ScoringRole", "lambdas/scoring/handler.py"),
("GetSubmissionFunction", "configurations/get_submission_policy.json", "GetSubmissionRole", "lambdas/get_submission/handler.py"),
("GetLeaderboardFunction", "configurations/get_leaderboard_policy.json", "GetLeaderboardRole", "lambdas/get_leaderboard/handler.py"),
("ListPublicQuizzesFunction", "configurations/list_quizzes_policy.json", "ListQuizzesRole", "lambdas/list_quizzes/handler.py"),
("RetryQuizzesWritesFunction","configurations/retry_quizzes_writes_policy.json", "RetryQuizzesWritesRole", "lambdas/retry_quizzes_writes/handler.py"),
]

for function_info in functions_and_roles:

function_name, policy_file_path, role_name, handler_path = function_info
policy_json = self.read_policy_file(f"../{policy_file_path}")
policy_document = iam.PolicyDocument.from_json(policy_json)

policy = iam.ManagedPolicy(
self,
"FunctionPolicy",
managed_policy_name=f"{function_name}Policy",
document=policy_document,
)

role = iam.Role(
self,
"LambdaExecutionRole",
role_name=role_name,
assumed_by=iam.ServicePrincipal("lambda.amazonaws.com"),
description=f"Role for Lambda function {function_name}",
)

# Attach the policy to the role
role.add_managed_policy(policy)

_lambda.Function(
self,
"LambdaFunction",
function_name=function_name,
runtime=_lambda.Runtime.PYTHON_3_11,
handler="handler.lambda_handler",
code=_lambda.Code.from_asset(handler_path),
role=role,
timeout=aws_cdk.Duration.seconds(30),
)

sqs.Queue(scope, "QuizSubmissionQueue", queue_name="QuizSubmissionQueue")

@staticmethod
def read_policy_file(file_path: str) -> dict:
"""Reads a JSON policy file and returns it as a dictionary."""
file_path = Path(file_path)
if not file_path.exists():
raise FileNotFoundError(f"Policy file not found: {file_path}")
with open(file_path, "r") as file:
return json.load(file)
1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest==6.2.5
2 changes: 2 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
aws-cdk-lib==2.136.0
constructs>=10.0.0,<11.0.0
13 changes: 13 additions & 0 deletions source.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
@echo off

rem The sole purpose of this script is to make the command
rem
rem source .venv/bin/activate
rem
rem (which activates a Python virtualenv on Linux or Mac OS X) work on Windows.
rem On Windows, this command just runs this batch file (the argument is ignored).
rem
rem Now we don't need to document a Windows command for activating a virtualenv.

echo Executing .venv\Scripts\activate.bat for you
.venv\Scripts\activate.bat
Empty file added tests/__init__.py
Empty file.
Empty file added tests/unit/__init__.py
Empty file.
15 changes: 15 additions & 0 deletions tests/unit/test_quiz_app_stack.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import aws_cdk as core
import aws_cdk.assertions as assertions

from quiz_app.quiz_app_stack import QuizAppStack

# example tests. To run these tests, uncomment this file along with the example
# resource in quiz_app/quiz_app_stack.py
def test_sqs_queue_created():
app = core.App()
stack = QuizAppStack(app, "quiz-app")
template = assertions.Template.from_stack(stack)

# template.has_resource_properties("AWS::SQS::Queue", {
# "VisibilityTimeout": 300
# })

0 comments on commit eeecc36

Please sign in to comment.