diff --git a/python/lambda-cloudwatch-dashboard/README.md b/python/lambda-cloudwatch-dashboard/README.md index fdd3e091f7..bc9a5997d5 100644 --- a/python/lambda-cloudwatch-dashboard/README.md +++ b/python/lambda-cloudwatch-dashboard/README.md @@ -7,49 +7,66 @@ CloudWatch dashboards are used to create customized views of the metrics and ala This CDK sample uses an AWS Lambda Function, as an example, for the source of CloudWatch metrics. This approach can used with AWS Services that create [CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/working_with_metrics.html) or even [Custom CloudWatch metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/publishingMetrics.html) that you publish yourself. -The following resources are defined in the CDK Stack: -- [AWS Lambda Function](https://aws.amazon.com/lambda/) +The following resources are defined in the main CDK Stack: - [Amazon CloudWatch](https://aws.amazon.com/cloudwatch/) +- [AWS Lambda Function](https://aws.amazon.com/lambda/) + +To automatically trigger the Lambda Function we use an +[AWS StepFunctions](https://aws.amazon.com/step-functions/), started after provisioning by a Custom Resource(another Lambda Function). -After deploying solution, you will have created a CloudWatch Dashboard, like the one shown below: +After deploying the CDK Stacks the StepFunctions state machine will run 20+ minutes to generate sample metrics. + +In CloudWatch you see the provisioned dashboard, like the one shown below: ![Sample Dashboard](img/sample_cloudwatch_dashboard.png) ---- -### Requirements: +## Setup + +This project is set up like a standard Python project. -- git -- npm (node.js) -- python 3.x -- AWS access key & secret for AWS user with permissions to create resources listed above +## Use uv +Create a virtualenv and install all dependencies +``` +uv sync +``` +At this point you can now synthesize the CloudFormation template for this code. +``` +uv run cdk synth +``` +Or simple proceed to deployment of the stack. +``` +uv run cdk deploy --all +``` ---- +### View CloudWatch Dashboard -## Setup +1) Sign in to the AWS Console +2) Navigate to the URL in this CDK Stack Output: `LambdaCloudwatchDashboardStack.DashboardOutput` +3) Please note, the metrics are aggregated for a period of 5 minutes before being displayed on the Dashboard. The value of the period can be configured, please see the [CDK documentation](https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_cloudwatch/MetricProps.html) for further details. -This project is set up like a standard Python project. The initialization process also creates -a virtualenv within this project, stored under the .env directory. To create the virtualenv -it assumes that there is a `python3` executable in your path with access to the `venv` package. -If for any reason the automatic creation of the virtualenv fails, you can create the virtualenv -manually once the init process completes. +To clean up, issue this command: +``` +uv run cdk destroy --all +``` +## Or use the default deployment To manually create a virtualenv on MacOS and Linux: ``` -$ python3 -m venv .env +$ python3 -m venv .venv ``` After the init process completes and the virtualenv is created, you can use the following step to activate your virtualenv. ``` -$ source .env/bin/activate +$ source .venv/bin/activate ``` If you are a Windows platform, you would activate the virtualenv like this: ``` -$ .env\Scripts\activate.bat +% .venv\Scripts\activate.bat ``` Once the virtualenv is activated, you can install the required dependencies. @@ -58,15 +75,6 @@ Once the virtualenv is activated, you can install the required dependencies. $ pip install -r requirements.txt ``` - -Install the latest version of the AWS CDK CLI: - -``` -$ npm i -g aws-cdk -``` - -## Deployment - At this point you can now synthesize the CloudFormation template for this code. ``` cdk synth @@ -76,36 +84,8 @@ Or simple proceed to deployment of the stack. ``` cdk deploy ``` - -## Test - -### Invoke Lambda Function -In order to generate some metrics, you can invoke the sample Lambda Function: - -Replace `` with the value of this CDK Stack Output: `LambdaCloudwatchDashboardStack.LambdaName` -``` -aws lambda invoke --function-name text_output.txt -``` - -### View CloudWatch Dashboard - -1) Sign into to the AWS Console -2) Navigate to the URL in this CDK Stack Output: `LambdaCloudwatchDashboardStack.DashboardOutput` -3) Please note, the metrics are aggregated for a period of 5 minutes before being displayed on the Dashboard. The value of the period can be configured, please see the [CDK documentation](https://docs.aws.amazon.com/cdk/api/latest/python/aws_cdk.aws_cloudwatch/MetricProps.html) for further details. - - ## Clean Up To clean up, issue this command: ``` cdk destroy -``` - -## Useful commands - - * `cdk ls` list all stacks in the app - * `cdk synth` emits the synthesized CloudFormation template - * `cdk deploy` deploy this stack to your default AWS account/region - * `cdk diff` compare deployed stack with current state - * `cdk docs` open CDK documentation - -Enjoy! +``` \ No newline at end of file diff --git a/python/lambda-cloudwatch-dashboard/app.py b/python/lambda-cloudwatch-dashboard/app.py index b445fc86c9..5df36690ba 100644 --- a/python/lambda-cloudwatch-dashboard/app.py +++ b/python/lambda-cloudwatch-dashboard/app.py @@ -1,8 +1,19 @@ #!/usr/bin/env python3 + from aws_cdk import App -from lambda_cloudwatch_dashboard.lambda_cloudwatch_dashboard_stack import LambdaCloudwatchDashboardStack +from lambda_cloudwatch_dashboard.lambda_cloudwatch_dashboard_stack import ( + LambdaCloudwatchDashboardStack, +) +from lambda_cloudwatch_dashboard.stepfunctions_invoker_stack import ( + StepfunctionsInvokerStack, +) app = App() -LambdaCloudwatchDashboardStack(app, "LambdaCloudwatchDashboardStack") + +lambdastack = LambdaCloudwatchDashboardStack(app, "LambdaCloudwatchDashboardStack") + +stepfunctionsstack = StepfunctionsInvokerStack(app, "StepfunctionsInvokerStack") +stepfunctionsstack.add_dependency(lambdastack) + app.synth() diff --git a/python/lambda-cloudwatch-dashboard/cdk.json b/python/lambda-cloudwatch-dashboard/cdk.json index b4baa10225..9a4d3ad109 100644 --- a/python/lambda-cloudwatch-dashboard/cdk.json +++ b/python/lambda-cloudwatch-dashboard/cdk.json @@ -1,3 +1,117 @@ { - "app": "python3 app.py" + "app": "python3 app.py", + "staging": "false", + "watch": { + "include": [ + "**" + ], + "exclude": [ + "README.md", + "cdk*.json", + "pyproject.toml", + "requirements*.txt", + "source.bat", + "**/__init__.py", + "**/__pycache__", + "tests" + ] + }, + "context": { + "@aws-cdk/aws-signer:signingProfileNamePassedToCfn": true, + "@aws-cdk/aws-ecs-patterns:secGroupsDisablesImplicitOpenListener": true, + "@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-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-kms:applyImportedAliasPermissionsToPrincipal": 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, + "@aws-cdk/aws-eks:nodegroupNameAttribute": true, + "@aws-cdk/aws-ec2:ebsDefaultGp3Volume": true, + "@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm": true, + "@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault": false, + "@aws-cdk/aws-s3:keepNotificationInImportedBucket": false, + "@aws-cdk/core:explicitStackTags": true, + "@aws-cdk/aws-ecs:enableImdsBlockingDeprecatedFeature": false, + "@aws-cdk/aws-ecs:disableEcsImdsBlocking": true, + "@aws-cdk/aws-ecs:reduceEc2FargateCloudWatchPermissions": true, + "@aws-cdk/aws-dynamodb:resourcePolicyPerReplica": true, + "@aws-cdk/aws-ec2:ec2SumTImeoutEnabled": true, + "@aws-cdk/aws-appsync:appSyncGraphQLAPIScopeLambdaPermission": true, + "@aws-cdk/aws-rds:setCorrectValueForDatabaseInstanceReadReplicaInstanceResourceId": true, + "@aws-cdk/core:cfnIncludeRejectComplexResourceUpdateCreatePolicyIntrinsics": true, + "@aws-cdk/aws-lambda-nodejs:sdkV3ExcludeSmithyPackages": true, + "@aws-cdk/aws-stepfunctions-tasks:fixRunEcsTaskPolicy": true, + "@aws-cdk/aws-ec2:bastionHostUseAmazonLinux2023ByDefault": true, + "@aws-cdk/aws-route53-targets:userPoolDomainNameMethodWithoutCustomResource": true, + "@aws-cdk/aws-elasticloadbalancingV2:albDualstackWithoutPublicIpv4SecurityGroupRulesDefault": true, + "@aws-cdk/aws-iam:oidcRejectUnauthorizedConnections": true, + "@aws-cdk/core:enableAdditionalMetadataCollection": true, + "@aws-cdk/aws-lambda:createNewPoliciesWithAddToRolePolicy": false, + "@aws-cdk/aws-s3:setUniqueReplicationRoleName": true, + "@aws-cdk/aws-events:requireEventBusPolicySid": true, + "@aws-cdk/core:aspectPrioritiesMutating": true, + "@aws-cdk/aws-dynamodb:retainTableReplica": true, + "@aws-cdk/aws-stepfunctions:useDistributedMapResultWriterV2": true, + "@aws-cdk/s3-notifications:addS3TrustKeyPolicyForSnsSubscriptions": true, + "@aws-cdk/aws-ec2:requirePrivateSubnetsForEgressOnlyInternetGateway": true, + "@aws-cdk/aws-s3:publicAccessBlockedByDefault": true, + "@aws-cdk/aws-lambda:useCdkManagedLogGroup": true, + "@aws-cdk/core:newStyleStackSynthesis": true, + "@aws-cdk/core:stackRelativeExports": true, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": true, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true, + "@aws-cdk/aws-lambda:recognizeVersionProps": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true, + "@aws-cdk/pipelines:reduceAssetRoleTrustScope": true, + "@aws-cdk/aws-stepfunctions-tasks:useNewS3UriParametersForBedrockInvokeModelTask": true, + "@aws-cdk/core:aspectStabilization": true, + "@aws-cdk/pipelines:reduceStageRoleTrustScope": true, + "@aws-cdk/cognito:logUserPoolClientSecretValue": false, + "@aws-cdk/pipelines:reduceCrossAccountActionRoleTrustScope": true, + "@aws-cdk/aws-ec2-alpha:useResourceIdForVpcV2Migration": false, + "@aws-cdk/aws-elasticloadbalancingv2:networkLoadBalancerWithSecurityGroupByDefault": true, + "@aws-cdk/aws-stepfunctions-tasks:httpInvokeDynamicJsonPathEndpoint": true, + "@aws-cdk/aws-ecs-patterns:uniqueTargetGroupId": true + } } diff --git a/python/lambda-cloudwatch-dashboard/img/sample_cloudwatch_dashboard.jpg b/python/lambda-cloudwatch-dashboard/img/sample_cloudwatch_dashboard.jpg new file mode 100644 index 0000000000..a9b67d3e07 Binary files /dev/null and b/python/lambda-cloudwatch-dashboard/img/sample_cloudwatch_dashboard.jpg differ diff --git a/python/lambda-cloudwatch-dashboard/img/sample_cloudwatch_dashboard.png b/python/lambda-cloudwatch-dashboard/img/sample_cloudwatch_dashboard.png deleted file mode 100644 index 2c3d1e1d4a..0000000000 Binary files a/python/lambda-cloudwatch-dashboard/img/sample_cloudwatch_dashboard.png and /dev/null differ diff --git a/python/lambda-cloudwatch-dashboard/lambda/lambda-handler.py b/python/lambda-cloudwatch-dashboard/lambda/lambda-handler.py deleted file mode 100644 index 767cef268b..0000000000 --- a/python/lambda-cloudwatch-dashboard/lambda/lambda-handler.py +++ /dev/null @@ -1,8 +0,0 @@ -def main(event, context): - # save event to logs - print(event) - - return { - 'statusCode': 200, - 'body': event - } diff --git a/python/lambda-cloudwatch-dashboard/lambda_cloudwatch_dashboard/lambda_cloudwatch_dashboard_stack.py b/python/lambda-cloudwatch-dashboard/lambda_cloudwatch_dashboard/lambda_cloudwatch_dashboard_stack.py index 7b1fa58e61..9f34031bb6 100644 --- a/python/lambda-cloudwatch-dashboard/lambda_cloudwatch_dashboard/lambda_cloudwatch_dashboard_stack.py +++ b/python/lambda-cloudwatch-dashboard/lambda_cloudwatch_dashboard/lambda_cloudwatch_dashboard_stack.py @@ -1,81 +1,128 @@ -from aws_cdk import ( - Aws, CfnOutput, Stack, - aws_lambda, - aws_cloudwatch, - aws_iam -) +from aws_cdk import Aws, CfnOutput, Duration, Stack, aws_cloudwatch, aws_iam, aws_lambda from constructs import Construct -class LambdaCloudwatchDashboardStack(Stack): +class LambdaCloudwatchDashboardStack(Stack): def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: super().__init__(scope, construct_id, **kwargs) example_dashboard_name = "ExampleLambdaDashboard" + # Lambda function Code + lambda_inline_code = """ +import time +import random + +def lambda_handler(event, context): + print(event) # save event to logs + time.sleep(random.uniform(3, 8)) # simulate work + if random.uniform(0, 1) < 0.1: # simulate error + raise ValueError("Random error") + return { + "statusCode": 200, + "body": "OK" + } +""" # Create Example Lambda function - lambda_function = aws_lambda.Function(self, "lambda_function", - runtime=aws_lambda.Runtime.PYTHON_3_7, - handler="lambda-handler.main", - code=aws_lambda.Code.from_asset("./lambda")) + lambda_function = aws_lambda.Function( + self, + "lambda_function", + runtime=aws_lambda.Runtime.PYTHON_3_13, + handler="index.lambda_handler", + code=aws_lambda.Code.from_inline(lambda_inline_code), + reserved_concurrent_executions=4, + timeout=Duration.seconds(12), + ) assert lambda_function.role is not None lambda_function.role.add_managed_policy( - aws_iam.ManagedPolicy.from_aws_managed_policy_name("service-role/AWSLambdaBasicExecutionRole") + aws_iam.ManagedPolicy.from_aws_managed_policy_name( + "service-role/AWSLambdaBasicExecutionRole" + ) ) # Create CloudWatch Dashboard to view Lambda Function Metrics - cw_dashboard = aws_cloudwatch.Dashboard(self, "Lambda Dashboard", - dashboard_name=example_dashboard_name + cw_dashboard = aws_cloudwatch.Dashboard( + self, "Lambda Dashboard", dashboard_name=example_dashboard_name ) # CloudWatch Dashboard Title title_widget = aws_cloudwatch.TextWidget( - markdown="# Dashboard: {}".format(lambda_function.function_name), - height=1, - width=24 + markdown=f"# Dashboard: {lambda_function.function_name}", height=1, width=24 + ) + # Create Widgets for CloudWatch Dashboard + # based on Lambda Function's CloudWatch Metrics + invocations_widget = aws_cloudwatch.GraphWidget( + title="Invocations", + left=[ + lambda_function.metric_invocations( + statistic="sum", period=Duration.minutes(1) + ) + ], + width=8, + height=6, ) - # Create Widgets for CloudWatch Dashboard based on Lambda Function's CloudWatch Metrics - invocations_widget = aws_cloudwatch.GraphWidget(title= "Invocations", - left=[lambda_function.metric_invocations()], - width=24) - - errors_widget = aws_cloudwatch.GraphWidget(title= "Errors", - left=[lambda_function.metric_errors()], - width=24) - duration_widget = aws_cloudwatch.GraphWidget(title= "Duration", + duration_widget = aws_cloudwatch.GraphWidget( + title="Duration", left=[lambda_function.metric_duration()], - width=24) + width=8, + height=6, + ) - throttles_widget = aws_cloudwatch.GraphWidget(title= "Throttles", + throttles_widget = aws_cloudwatch.GraphWidget( + title="Throttles", left=[lambda_function.metric_throttles()], - width=24) + width=8, + height=6, + ) + + errors_widget = aws_cloudwatch.GraphWidget( + title="Errors", + left=[ + lambda_function.metric_errors( + statistic="sum", period=Duration.minutes(1) + ) + ], + width=8, + height=6, + ) # Create Widget to show last 20 Log Entries - log_widget = aws_cloudwatch.LogQueryWidget(log_group_names=[lambda_function.log_group.log_group_name], - query_lines=["fields @timestamp, @message", "sort @timestamp desc", "limit 20"], width=24) + log_widget = aws_cloudwatch.LogQueryWidget( + log_group_names=[lambda_function.log_group.log_group_name], + query_lines=[ + "fields @timestamp, @message", + "sort @timestamp desc", + "limit 20", + ], + width=16, + height=6, + ) # Add Widgets to CloudWatch Dashboard - cw_dashboard.add_widgets(title_widget, - invocations_widget, - errors_widget, - duration_widget, - throttles_widget, - log_widget) + cw_dashboard.add_widgets( + title_widget, + invocations_widget, + errors_widget, + duration_widget, + throttles_widget, + log_widget, + ) # Output Dashboard URL - cloudwatch_dasboard_url = 'https://{}.console.aws.amazon.com/cloudwatch/home?region={}#dashboards:name={}'.format( - Aws.REGION, - Aws.REGION, - example_dashboard_name - ) - CfnOutput(self,"DashboardOutput", + cloudwatch_dasboard_url = f"https://{Aws.REGION}.console.aws.amazon.com/cloudwatch/home?region={Aws.REGION}#dashboards:name={example_dashboard_name}" + CfnOutput( + self, + "DashboardOutput", value=cloudwatch_dasboard_url, description="URL of Sample CloudWatch Dashboard", - export_name="SampleCloudWatchDashboardURL") - - CfnOutput(self,"LambdaName", - value=lambda_function.function_name, - description="Name of the sample Lambda Function", - export_name="LambdaName") + export_name="SampleCloudWatchDashboardURL", + ) + CfnOutput( + self, + "LambdaARN", + value=lambda_function.function_arn, + description="ARN of the sample Lambda Function", + export_name="CloudwatchDashboardLambdaARN", + ) diff --git a/python/lambda-cloudwatch-dashboard/lambda_cloudwatch_dashboard/stepfunctions_invoker_stack.py b/python/lambda-cloudwatch-dashboard/lambda_cloudwatch_dashboard/stepfunctions_invoker_stack.py new file mode 100644 index 0000000000..804d58142c --- /dev/null +++ b/python/lambda-cloudwatch-dashboard/lambda_cloudwatch_dashboard/stepfunctions_invoker_stack.py @@ -0,0 +1,99 @@ +from aws_cdk import ( + Duration, + Fn, + Stack, +) +from aws_cdk import ( + aws_lambda as _lambda, +) +from aws_cdk import ( + aws_stepfunctions as sfn, +) +from aws_cdk import ( + aws_stepfunctions_tasks as sfn_tasks, +) +from aws_cdk import ( + custom_resources as cr, +) +from constructs import Construct + + +class StepfunctionsInvokerStack(Stack): + def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None: + super().__init__(scope, construct_id, **kwargs) + + lambda_arn = Fn.import_value("CloudwatchDashboardLambdaARN") + target_lambda = _lambda.Function.from_function_arn( + self, "ImportedTargetFunction", function_arn=lambda_arn + ) + generate_array = sfn.Pass( + self, "GenerateArray", result=sfn.Result.from_array(list(range(1, 41))) + ) + + invoke_target_lambda_task = sfn_tasks.LambdaInvoke( + self, + "InvokeTargetLambda", + lambda_function=target_lambda, + retry_on_service_exceptions=False, + ).add_retry( + errors=[ + "Lambda.ClientExecutionTimeoutException", + "Lambda.ServiceException", + "Lambda.AWSLambdaException", + "Lambda.SdkClientException", + "ValueError", + ], + interval=Duration.seconds(5), + max_attempts=5, + backoff_rate=2.0, + ) + + wait_task = sfn.Wait( + self, "WaitAfterLambda", time=sfn.WaitTime.duration(Duration.seconds(120)) + ) + lambda_invoker_map = sfn.Map( + self, + "LambdaInvoker40PerMinute", + items_path=sfn.JsonPath.string_at("$"), + item_selector={ + "iteration_index": sfn.JsonPath.string_at("$$.Map.Item.Index"), + "item_value": sfn.JsonPath.string_at("$$.Map.Item.Value"), + }, + max_concurrency=4, + ) + # lambda_invoker_map.item_processor(invoke_target_lambda_task) + lambda_invoker_map.item_processor(invoke_target_lambda_task.next(wait_task)) + + definition = sfn.DefinitionBody.from_chainable( + generate_array.next(lambda_invoker_map) + ) + state_machine = sfn.StateMachine( + self, + "LambdaInvokerStateMachine", + comment="Lambda Invoker - Call Lambda 40 times", + definition_body=definition, + ) + target_lambda.grant_invoke(state_machine.role) + + # Custom resource to start Step Functions execution + start_execution = cr.AwsCustomResource( + self, + "StartStepFunctionsExecution", + on_create=cr.AwsSdkCall( + service="StepFunctions", + action="startExecution", + parameters={ + "stateMachineArn": state_machine.state_machine_arn, + "input": "{}", + }, + physical_resource_id=cr.PhysicalResourceId.from_response( + "executionArn" + ), + ), + policy=cr.AwsCustomResourcePolicy.from_sdk_calls( + resources=[state_machine.state_machine_arn] + ), + ) + + # Ensure the custom resource runs after the state machine is created + start_execution.node.add_dependency(state_machine) diff --git a/python/lambda-cloudwatch-dashboard/pyproject.toml b/python/lambda-cloudwatch-dashboard/pyproject.toml new file mode 100644 index 0000000000..ac44ba12cf --- /dev/null +++ b/python/lambda-cloudwatch-dashboard/pyproject.toml @@ -0,0 +1,45 @@ +[project] +name = "Lambda-CloudWatch-Dashboard" +version = "0.0.2" +description = "CloudWatch Dashboard Sample" +readme = "README.md" +dependencies = [ + "aws-cdk-lib>=2.0.0,<3", + "constructs>=10.0.0,<11" +] +requires-python = ">=3.9,<4" +classifiers = [ + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python :: 3 :: Only", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Topic :: Software Development :: Code Generators", + "Topic :: Utilities", + "Typing :: Typed", +] + +[tool.ruff] +target-version = "py39" + +[tool.ruff.lint] +ignore = [] +select = [ + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # flake8-simplify + "SIM", + # isort + "I", +] \ No newline at end of file diff --git a/python/lambda-cloudwatch-dashboard/requirements.txt b/python/lambda-cloudwatch-dashboard/requirements.txt index 44a6c74166..bd8c62c2e5 100644 --- a/python/lambda-cloudwatch-dashboard/requirements.txt +++ b/python/lambda-cloudwatch-dashboard/requirements.txt @@ -1,3 +1,2 @@ -aws-cdk-lib>=2.0.0 -constructs>=10.0.0 -types-setuptools +aws-cdk-lib>=2.0.0,<3 +constructs>=10.0.0,<11 \ No newline at end of file diff --git a/python/lambda-cloudwatch-dashboard/setup.py b/python/lambda-cloudwatch-dashboard/setup.py deleted file mode 100644 index a19be5e9b7..0000000000 --- a/python/lambda-cloudwatch-dashboard/setup.py +++ /dev/null @@ -1,41 +0,0 @@ -import setuptools - - -with open("README.md") as fp: - long_description = fp.read() - - -setuptools.setup( - name="lambda_cloudwatch_dashboard", - version="0.0.1", - - description="CloudWatch Dashboard Sample", - long_description=long_description, - long_description_content_type="text/markdown", - - author="author", - - package_dir={"": "lambda_cloudwatch_dashboard"}, - packages=setuptools.find_packages(where="lambda_cloudwatch_dashboard"), - - python_requires=">=3.6", - - classifiers=[ - "Development Status :: 4 - Beta", - - "Intended Audience :: Developers", - - "License :: OSI Approved :: Apache Software License", - - "Programming Language :: JavaScript", - "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.6", - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", - - "Topic :: Software Development :: Code Generators", - "Topic :: Utilities", - - "Typing :: Typed", - ], -)