├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── base ├── bin │ └── base.ts ├── cdk.json ├── jest.config.js ├── lib │ └── base-stack.ts ├── package-lock.json ├── package.json ├── post-cluster │ └── karpenter-provisioner.yaml └── tsconfig.json ├── examples ├── cmn │ ├── cfn │ │ ├── ci.yaml │ │ ├── springdemo-ci.yaml │ │ ├── springdemo-infra.yaml │ │ └── springdemo-main.yaml │ ├── codebuild │ │ └── buildspec.yml │ ├── dockerfiles │ │ ├── Dockerfile_Build │ │ └── Dockerfile_Run │ ├── k8s-stage │ │ └── s3-mount │ │ │ ├── deployment-crac-s3-express-mount.yaml │ │ │ ├── deployment-crac-s3-mount.yaml │ │ │ ├── s3-express-mount.yaml │ │ │ └── s3-mount.yaml │ └── k8s │ │ ├── efs-mount.yaml │ │ └── springdemo │ │ ├── deployment-crac-efs-mount.yaml │ │ ├── deployment-crac-s3-cli.yaml │ │ ├── deployment-crac.yaml │ │ ├── deployment-nocrac.yaml │ │ ├── kustomization.yaml │ │ └── spring-config-map.yaml ├── springdemo-native-int │ ├── code │ │ ├── mvnw │ │ ├── mvnw.cmd │ │ ├── pom.xml │ │ └── src │ │ │ ├── main │ │ │ ├── java │ │ │ │ └── com │ │ │ │ │ └── amazon │ │ │ │ │ └── customerService │ │ │ │ │ ├── CustomerServiceApplication.java │ │ │ │ │ ├── config │ │ │ │ │ └── AppConfig.java │ │ │ │ │ ├── controller │ │ │ │ │ └── CustomerController.java │ │ │ │ │ ├── exception │ │ │ │ │ └── CustomerNotFoundException.java │ │ │ │ │ ├── model │ │ │ │ │ ├── Customer.java │ │ │ │ │ └── metrics │ │ │ │ │ │ ├── ContainerMetric.java │ │ │ │ │ │ ├── MetricWrapper.java │ │ │ │ │ │ ├── PodMetric.java │ │ │ │ │ │ └── TaskMetric.java │ │ │ │ │ ├── repository │ │ │ │ │ └── CustomerRepository.java │ │ │ │ │ ├── service │ │ │ │ │ ├── CustomerService.java │ │ │ │ │ ├── EcsMetaDataService.java │ │ │ │ │ └── EksMetricsService.java │ │ │ │ │ └── utils │ │ │ │ │ └── TimingUtils.java │ │ │ └── resources │ │ │ │ ├── application-local.properties │ │ │ │ └── application-prod.properties │ │ │ └── test │ │ │ ├── java │ │ │ └── com │ │ │ │ └── amazon │ │ │ │ └── customerService │ │ │ │ └── repository │ │ │ │ └── CustomerRepositoryTest.java │ │ │ └── resources │ │ │ ├── container_response.json │ │ │ └── task_response.json │ └── scripts │ │ ├── checkpoint.sh │ │ ├── run-service-crac-s3.sh │ │ ├── run-service-crac.sh │ │ └── run-service.sh └── springdemo │ ├── code │ ├── mvnw │ ├── mvnw.cmd │ ├── pom.xml │ └── src │ │ ├── main │ │ ├── java │ │ │ └── com │ │ │ │ └── amazon │ │ │ │ └── customerService │ │ │ │ ├── CustomerServiceApplication.java │ │ │ │ ├── config │ │ │ │ └── AppConfig.java │ │ │ │ ├── controller │ │ │ │ └── CustomerController.java │ │ │ │ ├── exception │ │ │ │ └── CustomerNotFoundException.java │ │ │ │ ├── model │ │ │ │ ├── Customer.java │ │ │ │ └── metrics │ │ │ │ │ ├── ContainerMetric.java │ │ │ │ │ ├── MetricWrapper.java │ │ │ │ │ ├── PodMetric.java │ │ │ │ │ └── TaskMetric.java │ │ │ │ ├── repository │ │ │ │ └── CustomerRepository.java │ │ │ │ ├── service │ │ │ │ ├── CustomerService.java │ │ │ │ ├── EcsMetaDataService.java │ │ │ │ └── EksMetricsService.java │ │ │ │ └── utils │ │ │ │ └── TimingUtils.java │ │ └── resources │ │ │ ├── application-local.properties │ │ │ └── application-prod.properties │ │ └── test │ │ ├── java │ │ └── com │ │ │ └── amazon │ │ │ └── customerService │ │ │ └── repository │ │ │ └── CustomerRepositoryTest.java │ │ └── resources │ │ ├── container_response.json │ │ └── task_response.json │ └── scripts │ ├── checkpoint.sh │ ├── run-service-crac-s3.sh │ ├── run-service-crac.sh │ └── run-service.sh └── images ├── architecture-externalize-checkpoint.png └── architecture.png /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,intellij,macos 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,intellij,macos 3 | 4 | ### Intellij ### 5 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider 6 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 7 | 8 | # User-specific stuff 9 | .idea/ 10 | 11 | # File-based project format 12 | *.iws 13 | 14 | # IntelliJ 15 | out/ 16 | 17 | # mpeltonen/sbt-idea plugin 18 | .idea_modules/ 19 | 20 | ### Eclipse ### 21 | examples/springdemo/code/.settings 22 | examples/springdemo/code/bin 23 | 24 | ### macOS ### 25 | # General 26 | .DS_Store 27 | .AppleDouble 28 | .LSOverride 29 | 30 | ### macOS Patch ### 31 | # iCloud generated files 32 | *.icloud 33 | 34 | ### VisualStudioCode ### 35 | .vscode/* 36 | !.vscode/settings.json 37 | !.vscode/tasks.json 38 | !.vscode/launch.json 39 | !.vscode/extensions.json 40 | !.vscode/*.code-snippets 41 | 42 | # Local History for Visual Studio Code 43 | .history/ 44 | 45 | # Built Visual Studio Code Extensions 46 | *.vsix 47 | 48 | ### VisualStudioCode Patch ### 49 | # Ignore all local history of files 50 | .history 51 | .ionide 52 | 53 | ### Maven ### 54 | target/ 55 | pom.xml.tag 56 | pom.xml.releaseBackup 57 | pom.xml.versionsBackup 58 | pom.xml.next 59 | release.properties 60 | dependency-reduced-pom.xml 61 | buildNumber.properties 62 | .mvn/timing.properties 63 | # https://github.com/takari/maven-wrapper#usage-without-binary-jar 64 | .mvn/wrapper/maven-wrapper.jar 65 | 66 | # Eclipse m2e generated files 67 | # Eclipse Core 68 | .project 69 | # JDT-specific (Eclipse Java Development Tools) 70 | .classpath 71 | 72 | *.js 73 | !jest.config.js 74 | *.d.ts 75 | node_modules 76 | 77 | # CDK asset staging directory 78 | .cdk.staging 79 | cdk.out 80 | cdk.context.json -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | ## Code of Conduct 2 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 3 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 4 | opensource-codeofconduct@amazon.com with any additional questions or comments. 5 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thank you for your interest in contributing to our project. Whether it's a bug report, new feature, correction, or additional 4 | documentation, we greatly value feedback and contributions from our community. 5 | 6 | Please read through this document before submitting any issues or pull requests to ensure we have all the necessary 7 | information to effectively respond to your bug report or contribution. 8 | 9 | 10 | ## Reporting Bugs/Feature Requests 11 | 12 | We welcome you to use the GitHub issue tracker to report bugs or suggest features. 13 | 14 | When filing an issue, please check existing open, or recently closed, issues to make sure somebody else hasn't already 15 | reported the issue. Please try to include as much information as you can. Details like these are incredibly useful: 16 | 17 | * A reproducible test case or series of steps 18 | * The version of our code being used 19 | * Any modifications you've made relevant to the bug 20 | * Anything unusual about your environment or deployment 21 | 22 | 23 | ## Contributing via Pull Requests 24 | Contributions via pull requests are much appreciated. Before sending us a pull request, please ensure that: 25 | 26 | 1. You are working against the latest source on the *main* branch. 27 | 2. You check existing open, and recently merged, pull requests to make sure someone else hasn't addressed the problem already. 28 | 3. You open an issue to discuss any significant work - we would hate for your time to be wasted. 29 | 30 | To send us a pull request, please: 31 | 32 | 1. Fork the repository. 33 | 2. Modify the source; please focus on the specific change you are contributing. If you also reformat all the code, it will be hard for us to focus on your change. 34 | 3. Ensure local tests pass. 35 | 4. Commit to your fork using clear commit messages. 36 | 5. Send us a pull request, answering any default questions in the pull request interface. 37 | 6. Pay attention to any automated CI failures reported in the pull request, and stay involved in the conversation. 38 | 39 | GitHub provides additional document on [forking a repository](https://help.github.com/articles/fork-a-repo/) and 40 | [creating a pull request](https://help.github.com/articles/creating-a-pull-request/). 41 | 42 | 43 | ## Finding contributions to work on 44 | Looking at the existing issues is a great way to find something to contribute on. As our projects, by default, use the default GitHub issue labels (enhancement/bug/duplicate/help wanted/invalid/question/wontfix), looking at any 'help wanted' issues is a great place to start. 45 | 46 | 47 | ## Code of Conduct 48 | This project has adopted the [Amazon Open Source Code of Conduct](https://aws.github.io/code-of-conduct). 49 | For more information see the [Code of Conduct FAQ](https://aws.github.io/code-of-conduct-faq) or contact 50 | opensource-codeofconduct@amazon.com with any additional questions or comments. 51 | 52 | 53 | ## Security issue notifications 54 | If you discover a potential security issue in this project we ask that you notify AWS/Amazon Security via our [vulnerability reporting page](http://aws.amazon.com/security/vulnerability-reporting/). Please do **not** create a public github issue. 55 | 56 | 57 | ## Licensing 58 | 59 | See the [LICENSE](LICENSE) file for our project's licensing. We will ask you to confirm the licensing of your contribution. 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT No Attribution 2 | 3 | Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so. 10 | 11 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 12 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 13 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 14 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 15 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 16 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 17 | 18 | -------------------------------------------------------------------------------- /base/bin/base.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import * as cdk from 'aws-cdk-lib'; 3 | import * as blueprints from '@aws-quickstart/eks-blueprints'; 4 | import * as iam from 'aws-cdk-lib/aws-iam'; 5 | import { AwsSolutionsChecks } from 'cdk-nag'; 6 | import { Aspects } from 'aws-cdk-lib'; 7 | import { NagSuppressions } from 'cdk-nag'; 8 | 9 | import { BaseStack } from '../lib/base-stack'; 10 | 11 | const app = new cdk.App(); 12 | // Add the cdk-nag AwsSolutions Pack with extra verbose logging enabled. 13 | Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true })) 14 | 15 | const account = process.env.CDK_DEFAULT_ACCOUNT!; 16 | const region = process.env.CDK_DEFAULT_REGION; 17 | const env = {account, region} 18 | 19 | //Base creation 20 | const baseStack = new BaseStack(app, 'BaseStack', { 21 | env: env 22 | }); 23 | 24 | //EKS cluster creation 25 | const clusterName = "eks-crac-cluster"; 26 | const addOns: Array = [ 27 | new blueprints.KarpenterAddOn({ 28 | values: { 29 | replicas: 1 30 | } 31 | }), 32 | new blueprints.AwsLoadBalancerControllerAddOn(), 33 | new blueprints.EfsCsiDriverAddOn() 34 | ]; 35 | 36 | const blueprintVpcProvider = new blueprints.DirectVpcProvider(baseStack.vpc) 37 | const blueprint = blueprints.EksBlueprint.builder() 38 | .resourceProvider(blueprints.GlobalResources.Vpc, blueprintVpcProvider) 39 | .resourceProvider(blueprints.GlobalResources.KmsKey, new blueprints.CreateKmsKeyProvider('eks-cluster-key', { 40 | enableKeyRotation: true 41 | })) 42 | .account(account) 43 | .region(region) 44 | .version("auto") 45 | .addOns(...addOns) 46 | .name(clusterName) 47 | .build(app, clusterName + '-stack'); 48 | 49 | const springdemoServiceAccountName = 'springdemo'; 50 | const springdemoServiceAccount = blueprint.getClusterInfo().cluster.addServiceAccount(springdemoServiceAccountName, { 51 | name: springdemoServiceAccountName, 52 | namespace: "default" 53 | }); 54 | springdemoServiceAccount.role.addToPrincipalPolicy(new iam.PolicyStatement( 55 | { 56 | actions: ['dynamodb:PutItem', 'dynamodb:GetItem', 'dynamodb:Scan'], 57 | resources: ['arn:aws:dynamodb:' + process.env.CDK_DEFAULT_REGION + ':' + process.env.CDK_DEFAULT_ACCOUNT + ':table/springdemo-prod-customer'], 58 | } 59 | )); 60 | springdemoServiceAccount.role.addToPrincipalPolicy(new iam.PolicyStatement( 61 | { 62 | actions: ['s3:GetBucketLocation', 's3:GetObject', 's3:ListBucket'], 63 | resources: [baseStack.cracCheckpointsS3.bucketArn, baseStack.cracCheckpointsS3.bucketArn + '/*'], 64 | } 65 | )); 66 | 67 | const springdemoNativeIntServiceAccountName = 'springdemo-native-int'; 68 | const springdemoNativeIntServiceAccount = blueprint.getClusterInfo().cluster.addServiceAccount(springdemoNativeIntServiceAccountName, { 69 | name: springdemoNativeIntServiceAccountName, 70 | namespace: "default" 71 | }); 72 | springdemoNativeIntServiceAccount.role.addToPrincipalPolicy(new iam.PolicyStatement( 73 | { 74 | actions: ['dynamodb:PutItem', 'dynamodb:GetItem', 'dynamodb:Scan'], 75 | resources: ['arn:aws:dynamodb:' + process.env.CDK_DEFAULT_REGION + ':' + process.env.CDK_DEFAULT_ACCOUNT + ':table/springdemo-native-int-prod-customer'], 76 | } 77 | )); 78 | springdemoNativeIntServiceAccount.role.addToPrincipalPolicy(new iam.PolicyStatement( 79 | { 80 | actions: ['s3:GetBucketLocation', 's3:GetObject', 's3:ListBucket'], 81 | resources: [baseStack.cracCheckpointsS3.bucketArn, baseStack.cracCheckpointsS3.bucketArn + '/*'], 82 | } 83 | )); 84 | 85 | 86 | //configure cdk-nag suppressions 87 | const globalSuppressions = [ 88 | { 89 | id: 'AwsSolutions-IAM4', 90 | reason: 'Suppress errors related to the usage of IAM managed policies.' 91 | } 92 | ] 93 | 94 | const eksBlueprintsSuppressions = [ 95 | { 96 | id: 'AwsSolutions-EKS2', 97 | reason: 'Suppress errors related to EKS control plane logging to reduce charges given it is a demo cluster' 98 | }, 99 | { 100 | id: 'AwsSolutions-EKS1', 101 | reason: 'Suppress errors related to EKS API server allowing accessing it through public network to facilitate experimentation (authN/authZ is configured)' 102 | }, 103 | { 104 | id: 'AwsSolutions-IAM5', 105 | reason: 'Suppress errors related to IAM produced by EKS CDK construct' 106 | }, 107 | { 108 | id: 'AwsSolutions-L1', 109 | reason: 'Suppress errors related to EKS blueprints Lambda functions that are not using latest runtime version' 110 | } 111 | ] 112 | NagSuppressions.addStackSuppressions(blueprint, globalSuppressions.concat(eksBlueprintsSuppressions), true); 113 | NagSuppressions.addStackSuppressions(baseStack, globalSuppressions); 114 | NagSuppressions.addResourceSuppressions(baseStack.efsSg, [ 115 | { 116 | id: 'AwsSolutions-EC23', 117 | reason: 'Suppress the error related to allowing inbound access from 0.0.0.0/0 on EFS security group' 118 | } 119 | ]); 120 | -------------------------------------------------------------------------------- /base/cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/base.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 38 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 39 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 40 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 41 | "@aws-cdk/aws-route53-patters:useCertificate": true, 42 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false, 43 | "@aws-cdk/aws-rds:databaseProxyUniqueResourceName": true, 44 | "@aws-cdk/aws-codedeploy:removeAlarmsFromDeploymentGroup": true, 45 | "@aws-cdk/aws-apigateway:authorizerChangeDeploymentLogicalId": true, 46 | "@aws-cdk/aws-ec2:launchTemplateDefaultUserData": true, 47 | "@aws-cdk/aws-secretsmanager:useAttachedSecretResourcePolicyForSecretTargetAttachments": true, 48 | "@aws-cdk/aws-redshift:columnId": true, 49 | "@aws-cdk/aws-stepfunctions-tasks:enableEmrServicePolicyV2": true, 50 | "@aws-cdk/aws-ec2:restrictDefaultSecurityGroup": true, 51 | "@aws-cdk/aws-apigateway:requestValidatorUniqueId": true, 52 | "@aws-cdk/aws-kms:aliasNameRef": true, 53 | "@aws-cdk/aws-autoscaling:generateLaunchTemplateInsteadOfLaunchConfig": true, 54 | "@aws-cdk/core:includePrefixInUniqueNameGeneration": true, 55 | "@aws-cdk/aws-efs:denyAnonymousAccess": true, 56 | "@aws-cdk/aws-opensearchservice:enableOpensearchMultiAzWithStandby": true, 57 | "@aws-cdk/aws-lambda-nodejs:useLatestRuntimeVersion": true, 58 | "@aws-cdk/aws-efs:mountTargetOrderInsensitiveLogicalId": true, 59 | "@aws-cdk/aws-rds:auroraClusterChangeScopeOfInstanceParameterGroupWithEachParameters": true, 60 | "@aws-cdk/aws-appsync:useArnForSourceApiAssociationIdentifier": true, 61 | "@aws-cdk/aws-rds:preventRenderingDeprecatedCredentials": true 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /base/jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /base/lib/base-stack.ts: -------------------------------------------------------------------------------- 1 | import { Stack, StackProps, CfnOutput, RemovalPolicy } from 'aws-cdk-lib'; 2 | import * as ec2 from 'aws-cdk-lib/aws-ec2' 3 | import * as efs from 'aws-cdk-lib/aws-efs' 4 | import * as s3 from 'aws-cdk-lib/aws-s3' 5 | import * as iam from 'aws-cdk-lib/aws-iam' 6 | import * as logs from 'aws-cdk-lib/aws-logs' 7 | 8 | import { Construct } from 'constructs'; 9 | 10 | export class BaseStack extends Stack { 11 | public readonly vpc: ec2.Vpc; 12 | 13 | public readonly efs: efs.FileSystem; 14 | 15 | public readonly efsSg: ec2.SecurityGroup; 16 | public readonly ciSg: ec2.SecurityGroup; 17 | 18 | public readonly cracCheckpointsS3: s3.Bucket; 19 | 20 | constructor(scope: Construct, id: string, props: StackProps) { 21 | super(scope, id, props); 22 | 23 | //create VPC 24 | this.vpc = new ec2.Vpc(this, 'EksCracVpc', { 25 | ipAddresses: ec2.IpAddresses.cidr('10.0.0.0/16') 26 | }); 27 | new CfnOutput(this, 'VpcId', { value: this.vpc.vpcId}); 28 | new CfnOutput(this, 'VpcPrivateSubnetIds', { value: this.vpc.selectSubnets({subnetType:ec2.SubnetType.PRIVATE_WITH_EGRESS}).subnetIds.toString()}); 29 | 30 | //enable VPC flow logs 31 | const logGroup = new logs.LogGroup(this, 'VpcFlowLogsGroup'); 32 | const role = new iam.Role(this, 'MyCustomRole', { 33 | assumedBy: new iam.ServicePrincipal('vpc-flow-logs.amazonaws.com') 34 | }); 35 | 36 | new ec2.FlowLog(this, 'FlowLog', { 37 | resourceType: ec2.FlowLogResourceType.fromVpc(this.vpc), 38 | destination: ec2.FlowLogDestination.toCloudWatchLogs(logGroup, role) 39 | }); 40 | 41 | //create EFS security group 42 | this.efsSg = new ec2.SecurityGroup(this, 'EfsSg', { 43 | vpc: this.vpc, 44 | }); 45 | this.efsSg.addIngressRule(ec2.Peer.anyIpv4(), ec2.Port.tcp(2049), ''); //to be narrowed down later to allow CI and EKS only 46 | 47 | //create EFS file system 48 | this.efs = new efs.FileSystem(this, 'crac-checkpoints-efs', { 49 | fileSystemName: 'crac-checkpoints', 50 | vpc: this.vpc, 51 | securityGroup: this.efsSg, 52 | vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS }, 53 | removalPolicy: RemovalPolicy.DESTROY, 54 | lifecyclePolicy: efs.LifecyclePolicy.AFTER_14_DAYS, // files are not transitioned to infrequent access (IA) storage by default 55 | performanceMode: efs.PerformanceMode.GENERAL_PURPOSE, // default 56 | outOfInfrequentAccessPolicy: efs.OutOfInfrequentAccessPolicy.AFTER_1_ACCESS, // files are not transitioned back from (infrequent access) IA to primary storage by default 57 | fileSystemPolicy: new iam.PolicyDocument() 58 | }); 59 | this.efs.addToResourcePolicy(new iam.PolicyStatement({ 60 | principals: [new iam.AnyPrincipal()], 61 | actions: ['elasticfilesystem:ClientRootAccess', 'elasticfilesystem:ClientWrite', 'elasticfilesystem:ClientMount'], 62 | resources: ['*'], 63 | conditions: { 64 | "Bool": { 65 | "elasticfilesystem:AccessedViaMountTarget": "true" 66 | } 67 | } 68 | })); 69 | 70 | new CfnOutput(this, 'CracCheckpointsFileSystemId', { value: this.efs.fileSystemId}); 71 | new CfnOutput(this, 'CracCheckpointsFileSystemDns', { value: this.efs.fileSystemId + '.efs.' + process.env.CDK_DEFAULT_REGION + '.amazonaws.com'}); 72 | 73 | //create CI security group 74 | this.ciSg = new ec2.SecurityGroup(this, 'CiSg', { 75 | vpc: this.vpc, 76 | }); 77 | new CfnOutput(this, 'CiSgId', { value: this.ciSg.securityGroupId}); 78 | 79 | //create S3 bucket for access logs 80 | const accessLogsS3 = new s3.Bucket(this, 'access-logs-s3bucket', { 81 | bucketName: 'crac-accesslogs-' + process.env.CDK_DEFAULT_ACCOUNT, 82 | enforceSSL: true, 83 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 84 | removalPolicy: RemovalPolicy.DESTROY, 85 | autoDeleteObjects: true 86 | 87 | }); 88 | 89 | //create S3 bucket for checkpoint files 90 | this.cracCheckpointsS3 = new s3.Bucket(this, 'crac-checkpoints-s3bucket', { 91 | bucketName: 'crac-checkpoints-' + process.env.CDK_DEFAULT_ACCOUNT, 92 | serverAccessLogsBucket: accessLogsS3, 93 | enforceSSL: true, 94 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 95 | removalPolicy: RemovalPolicy.DESTROY, 96 | autoDeleteObjects: true 97 | }); 98 | new CfnOutput(this, 'CracCheckpointsS3', {value: this.cracCheckpointsS3.bucketName}); 99 | 100 | //create S3 bucket for CI cloudformation templates 101 | const cracCfS3 = new s3.Bucket(this, 'crac-cf-s3bucket', { 102 | bucketName: 'crac-cf-' + process.env.CDK_DEFAULT_ACCOUNT, 103 | serverAccessLogsBucket: accessLogsS3, 104 | enforceSSL: true, 105 | blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL, 106 | removalPolicy: RemovalPolicy.DESTROY, 107 | autoDeleteObjects: true 108 | }); 109 | new CfnOutput(this, 'CracCfS3', {value: cracCfS3.bucketName}); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /base/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base", 3 | "version": "0.1.0", 4 | "bin": { 5 | "base": "bin/base.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk" 12 | }, 13 | "devDependencies": { 14 | "@types/jest": "^29.5.5", 15 | "@types/node": "20.7.1", 16 | "jest": "^29.7.0", 17 | "ts-jest": "^29.1.1", 18 | "ts-node": "^10.9.1", 19 | "typescript": "~5.2.2" 20 | }, 21 | "dependencies": { 22 | "@aws-quickstart/eks-blueprints": "1.13.1", 23 | "aws-cdk-lib": "2.115.0", 24 | "cdk-nag": "2.28.12", 25 | "constructs": "10.3.0", 26 | "source-map-support": "0.5.21" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /base/post-cluster/karpenter-provisioner.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: karpenter.sh/v1alpha5 2 | kind: Provisioner 3 | metadata: 4 | name: default 5 | spec: 6 | requirements: 7 | - key: karpenter.sh/capacity-type 8 | operator: In 9 | values: ["on-demand"] 10 | limits: 11 | resources: 12 | cpu: 1000 13 | providerRef: 14 | name: default 15 | ttlSecondsAfterEmpty: 30 16 | --- 17 | apiVersion: karpenter.k8s.aws/v1alpha1 18 | kind: AWSNodeTemplate 19 | metadata: 20 | name: default 21 | spec: 22 | subnetSelector: 23 | Name: eks-sample-cluster-stack/eks-sample-cluster-stack-vpc/PrivateSubnet* 24 | securityGroupSelector: 25 | kubernetes.io/cluster/eks-sample-cluster-stack: owned -------------------------------------------------------------------------------- /base/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020", 7 | "dom" 8 | ], 9 | "declaration": true, 10 | "strict": true, 11 | "noImplicitAny": true, 12 | "strictNullChecks": true, 13 | "noImplicitThis": true, 14 | "alwaysStrict": true, 15 | "noUnusedLocals": false, 16 | "noUnusedParameters": false, 17 | "noImplicitReturns": true, 18 | "noFallthroughCasesInSwitch": false, 19 | "inlineSourceMap": true, 20 | "inlineSources": true, 21 | "experimentalDecorators": true, 22 | "strictPropertyInitialization": false, 23 | "typeRoots": [ 24 | "./node_modules/@types" 25 | ] 26 | }, 27 | "exclude": [ 28 | "node_modules", 29 | "cdk.out" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /examples/cmn/cfn/ci.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: CI template 3 | Parameters: 4 | ServiceName: 5 | Type: String 6 | Description: Enter the service name. 7 | ServiceJarFilename: 8 | Type: String 9 | Description: Enter the service JAR file name. 10 | CracCheckpointsBucket: 11 | Type: String 12 | Description: Enter CRaC checkpoints S3 bucket name 13 | VpcId: 14 | Type: String 15 | Description: Enter the id of the VPC that CI runs in (should have access to EFS where CRaC checkpoint files are stored) 16 | VpcSubnetIds: 17 | Type: CommaDelimitedList 18 | Description: Enter the ids of the subnets that CI runs in (should have access to EFS where CRaC checkpoint files are stored) 19 | SecurityGroupIds: 20 | Type: CommaDelimitedList 21 | Description: Enter the ids of the security group that CI uses for accessing VPC resources (EFS where CRaC checkpoint files are stored) 22 | EfsDns: 23 | Type: String 24 | Description: Enter the EFS filesystem DNS 25 | 26 | Resources: 27 | CiCodeBuildRole: 28 | Type: AWS::IAM::Role 29 | Properties: 30 | RoleName: !Sub "${ServiceName}-CiCodeBuildRole" 31 | AssumeRolePolicyDocument: 32 | Version: "2012-10-17" 33 | Statement: 34 | - Effect: Allow 35 | Principal: 36 | Service: 37 | - codebuild.amazonaws.com 38 | Action: 39 | - sts:AssumeRole 40 | Policies: 41 | - PolicyName: !Sub "${ServiceName}-CiCodeBuildRolePolicy" 42 | PolicyDocument: 43 | Version: "2012-10-17" 44 | Statement: 45 | - Effect: Allow 46 | Action: 47 | - "logs:CreateLogGroup" 48 | - "logs:CreateLogStream" 49 | - "logs:PutLogEvents" 50 | Resource: 51 | - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${ServiceName}-Ci" 52 | - !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/codebuild/${ServiceName}-Ci:*" 53 | - Effect: Allow 54 | Action: 55 | - "ecr:GetAuthorizationToken" 56 | Resource: '*' 57 | - Effect: Allow 58 | Action: 59 | - "ecr:DescribeRepositories" 60 | - "ecr:InitiateLayerUpload" 61 | - "ecr:UploadLayerPart" 62 | - "ecr:CompleteLayerUpload" 63 | - "ecr:BatchCheckLayerAvailability" 64 | - "ecr:PutImage" 65 | Resource: 66 | - !GetAtt ServiceEcrRepo.Arn 67 | - Effect: Allow 68 | Action: 69 | - "s3:DeleteObject" 70 | - "s3:GetBucketLocation" 71 | - "s3:GetObject" 72 | - "s3:ListBucket" 73 | - "s3:PutObject" 74 | Resource: 75 | - !Sub "arn:aws:s3:::${CracCheckpointsBucket}" 76 | - !Sub "arn:aws:s3:::${CracCheckpointsBucket}/${ServiceName}/*" 77 | - !Sub "${CodePipelineArtifactStoreBucket.Arn}" 78 | - !Sub "${CodePipelineArtifactStoreBucket.Arn}/*" 79 | - Effect: Allow 80 | Action: 81 | - "ec2:CreateNetworkInterface" 82 | - "ec2:DescribeDhcpOptions" 83 | - "ec2:DescribeNetworkInterfaces" 84 | - "ec2:DeleteNetworkInterface" 85 | - "ec2:DescribeSubnets" 86 | - "ec2:DescribeSecurityGroups" 87 | - "ec2:DescribeVpcs" 88 | Resource: '*' 89 | - Effect: Allow 90 | Action: 91 | - "ec2:CreateNetworkInterfacePermission" 92 | Resource: !Sub "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:network-interface/*" 93 | Condition: 94 | StringEquals: 95 | "ec2:AuthorizedService": "codebuild.amazonaws.com" 96 | 97 | CiCodeBuildKms: 98 | Type: AWS::KMS::Key 99 | Properties: 100 | Description: "KMS key for CodeBuild" 101 | EnableKeyRotation: true 102 | KeyPolicy: 103 | Version: '2012-10-17' 104 | Statement: 105 | - Effect: Allow 106 | Principal: 107 | AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root' 108 | Action: 'kms:*' 109 | Resource: '*' 110 | 111 | CiCodeBuild: 112 | Type: AWS::CodeBuild::Project 113 | Properties: 114 | EncryptionKey: !GetAtt CiCodeBuildKms.Arn 115 | Artifacts: 116 | Type: NO_ARTIFACTS 117 | Description: !Sub "CodeBuild project that represents the CI pipeline for ${ServiceName}" 118 | Environment: 119 | ComputeType: "BUILD_GENERAL1_SMALL" 120 | EnvironmentVariables: 121 | - Name: SRVC_NAME 122 | Type: PLAINTEXT 123 | Value: !Sub "${ServiceName}" 124 | - Name: AWS_ACCOUNT_ID 125 | Type: PLAINTEXT 126 | Value: !Sub "${AWS::AccountId}" 127 | - Name: ROLE_ARN 128 | Type: PLAINTEXT 129 | Value: !Sub "arn:aws:iam::${AWS::AccountId}:role/${ServiceName}-CiRole" 130 | - Name: SRVC_JAR_FILE_NAME 131 | Type: PLAINTEXT 132 | Value: !Sub "${ServiceJarFilename}" 133 | - Name: CRAC_CHECKPOINTS_BUCKET 134 | Type: PLAINTEXT 135 | Value: !Sub "${CracCheckpointsBucket}" 136 | Image: "aws/codebuild/standard:7.0" 137 | ImagePullCredentialsType: "CODEBUILD" 138 | PrivilegedMode: true 139 | Type: "LINUX_CONTAINER" 140 | VpcConfig: 141 | SecurityGroupIds: !Ref SecurityGroupIds 142 | Subnets: !Ref VpcSubnetIds 143 | VpcId: !Ref VpcId 144 | FileSystemLocations: 145 | - Identifier: "crac_checkpoints_efs" 146 | Location: !Sub "${EfsDns}:/" 147 | MountPoint: "/opt/crac-files" 148 | Type: "EFS" 149 | LogsConfig: 150 | CloudWatchLogs: 151 | Status: "ENABLED" 152 | Name: !Sub "${ServiceName}-Ci" 153 | ServiceRole: !GetAtt CiCodeBuildRole.Arn 154 | Source: 155 | Type: "CODECOMMIT" 156 | Location: !GetAtt ServiceGitRepo.CloneUrlHttp 157 | 158 | ServiceGitRepo: 159 | Type: AWS::CodeCommit::Repository 160 | Properties: 161 | RepositoryDescription: !Sub "This repo contains the code artifacts for ${ServiceName}" 162 | RepositoryName: !Ref ServiceName 163 | 164 | ServiceEcrRepo: 165 | Type: AWS::ECR::Repository 166 | Properties: 167 | RepositoryName: !Ref ServiceName 168 | ImageScanningConfiguration: 169 | ScanOnPush: true 170 | 171 | CodePipelineArtifactStoreBucket: 172 | Type: 'AWS::S3::Bucket' 173 | DeletionPolicy: Retain 174 | Properties: 175 | LoggingConfiguration: 176 | DestinationBucketName: !Sub 'crac-accesslogs-${AWS::AccountId}' 177 | PublicAccessBlockConfiguration: 178 | BlockPublicAcls: true 179 | BlockPublicPolicy: true 180 | IgnorePublicAcls: true 181 | RestrictPublicBuckets: true 182 | 183 | CodePipelineArtifactStoreBucketPolicy: 184 | Type: 'AWS::S3::BucketPolicy' 185 | Properties: 186 | Bucket: !Ref CodePipelineArtifactStoreBucket 187 | PolicyDocument: 188 | Version: 2012-10-17 189 | Statement: 190 | - Sid: DenyUnEncryptedObjectUploads 191 | Effect: Deny 192 | Principal: '*' 193 | Action: 's3:PutObject' 194 | Resource: !Join 195 | - '' 196 | - - !GetAtt 197 | - CodePipelineArtifactStoreBucket 198 | - Arn 199 | - /* 200 | Condition: 201 | StringNotEquals: 202 | 's3:x-amz-server-side-encryption': 'aws:kms' 203 | - Sid: DenyInsecureConnections 204 | Effect: Deny 205 | Principal: '*' 206 | Action: 's3:*' 207 | Resource: !Join 208 | - '' 209 | - - !GetAtt 210 | - CodePipelineArtifactStoreBucket 211 | - Arn 212 | - /* 213 | Condition: 214 | Bool: 215 | 'aws:SecureTransport': false 216 | 217 | AmazonCloudWatchEventRole: 218 | Type: 'AWS::IAM::Role' 219 | Properties: 220 | AssumeRolePolicyDocument: 221 | Version: 2012-10-17 222 | Statement: 223 | - Effect: Allow 224 | Principal: 225 | Service: 226 | - events.amazonaws.com 227 | Action: 'sts:AssumeRole' 228 | Path: / 229 | Policies: 230 | - PolicyName: cwe-pipeline-execution 231 | PolicyDocument: 232 | Version: 2012-10-17 233 | Statement: 234 | - Effect: Allow 235 | Action: 'codepipeline:StartPipelineExecution' 236 | Resource: !Join 237 | - '' 238 | - - 'arn:aws:codepipeline:' 239 | - !Ref 'AWS::Region' 240 | - ':' 241 | - !Ref 'AWS::AccountId' 242 | - ':' 243 | - !Ref ServicePipeline 244 | 245 | AmazonCloudWatchEventRule: 246 | Type: 'AWS::Events::Rule' 247 | Properties: 248 | EventPattern: 249 | source: 250 | - aws.codecommit 251 | detail-type: 252 | - CodeCommit Repository State Change 253 | resources: 254 | - !Join 255 | - '' 256 | - - 'arn:aws:codecommit:' 257 | - !Ref 'AWS::Region' 258 | - ':' 259 | - !Ref 'AWS::AccountId' 260 | - ':' 261 | - !Ref ServiceName 262 | detail: 263 | event: 264 | - referenceCreated 265 | - referenceUpdated 266 | referenceType: 267 | - branch 268 | referenceName: 269 | - main 270 | Targets: 271 | - Arn: !Join 272 | - '' 273 | - - 'arn:aws:codepipeline:' 274 | - !Ref 'AWS::Region' 275 | - ':' 276 | - !Ref 'AWS::AccountId' 277 | - ':' 278 | - !Ref ServicePipeline 279 | RoleArn: !GetAtt 280 | - AmazonCloudWatchEventRole 281 | - Arn 282 | Id: codepipeline-ServicePipeline 283 | ServicePipeline: 284 | Type: 'AWS::CodePipeline::Pipeline' 285 | Properties: 286 | Name: !Ref ServiceName 287 | RoleArn: !GetAtt 288 | - CodePipelineServiceRole 289 | - Arn 290 | Stages: 291 | - Name: Source 292 | Actions: 293 | - Name: SourceAction 294 | ActionTypeId: 295 | Category: Source 296 | Owner: AWS 297 | Version: 1 298 | Provider: CodeCommit 299 | OutputArtifacts: 300 | - Name: SourceOutput 301 | Configuration: 302 | BranchName: 'main' 303 | RepositoryName: !Ref ServiceName 304 | PollForSourceChanges: false 305 | RunOrder: 1 306 | - Name: Build 307 | Actions: 308 | - Name: BuildAction 309 | InputArtifacts: 310 | - Name: SourceOutput 311 | ActionTypeId: 312 | Category: Build 313 | Owner: AWS 314 | Version: 1 315 | Provider: CodeBuild 316 | Configuration: 317 | ProjectName: !Sub "${ServiceName}-Ci" 318 | RunOrder: 1 319 | ArtifactStore: 320 | Type: S3 321 | Location: !Ref CodePipelineArtifactStoreBucket 322 | CodePipelineServiceRole: #Permissions to be narrowed down 323 | Type: 'AWS::IAM::Role' 324 | Properties: 325 | AssumeRolePolicyDocument: 326 | Version: 2012-10-17 327 | Statement: 328 | - Effect: Allow 329 | Principal: 330 | Service: 331 | - codepipeline.amazonaws.com 332 | Action: 'sts:AssumeRole' 333 | Path: / 334 | Policies: 335 | - PolicyName: AWS-CodePipeline-Policy 336 | PolicyDocument: 337 | Version: 2012-10-17 338 | Statement: 339 | - Effect: Allow 340 | Action: 341 | - 'codecommit:CancelUploadArchive' 342 | - 'codecommit:GetBranch' 343 | - 'codecommit:GetCommit' 344 | - 'codecommit:GetUploadArchiveStatus' 345 | - 'codecommit:UploadArchive' 346 | Resource: !GetAtt ServiceGitRepo.Arn 347 | - Effect: Allow 348 | Action: 349 | - 'codebuild:BatchGetBuilds' 350 | - 'codebuild:StartBuild' 351 | Resource: !GetAtt CiCodeBuild.Arn 352 | - Effect: Allow 353 | Action: 354 | - 's3:PutObject' 355 | - 's3:PutObjectAcl' 356 | - 's3:GetObject' 357 | - 's3:GetObjectAcl' 358 | - 's3:DeleteObject' 359 | Resource: 360 | - !GetAtt CodePipelineArtifactStoreBucket.Arn 361 | - !Join 362 | - '' 363 | - - !GetAtt 364 | - CodePipelineArtifactStoreBucket 365 | - Arn 366 | - /* 367 | 368 | 369 | Outputs: 370 | CiCodeBuildArn: 371 | Description: The ARN of the IAM role used by the CodeBuild project 372 | Value: !GetAtt CiCodeBuildRole.Arn 373 | Export: 374 | Name: !Sub "${ServiceName}-CiCodeBuildRoleArn" -------------------------------------------------------------------------------- /examples/cmn/cfn/springdemo-ci.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: CI stack 3 | Parameters: 4 | CfnS3Bucket: 5 | Type: String 6 | Description: Enter the name of the S3 buckets that contains the CloudFormation templates 7 | ServiceName: 8 | Type: String 9 | Description: Enter the service name. 10 | ServiceJarFilename: 11 | Type: String 12 | Description: Enter the service JAR filename. 13 | CracCheckpointsBucket: 14 | Type: String 15 | Description: Enter CRaC checkpoints S3 bucket name 16 | VpcId: 17 | Type: String 18 | Description: Enter the id of the VPC that CI runs in (should have access to EFS where CRaC checkpoint files are stored) 19 | VpcSubnetIds: 20 | Type: CommaDelimitedList 21 | Description: Enter the ids of the subnets that CI runs in (should have access to EFS where CRaC checkpoint files are stored) 22 | SecurityGroupIds: 23 | Type: CommaDelimitedList 24 | Description: Enter the ids of the security group that CI uses for accessing VPC resources (EFS where CRaC checkpoint files are stored) 25 | EfsDns: 26 | Type: String 27 | Description: Enter the EFS filesystem DNS 28 | 29 | Resources: 30 | CiRole: 31 | Type: AWS::IAM::Role 32 | DependsOn: CiStack 33 | Properties: 34 | RoleName: !Sub "${ServiceName}-CiRole" 35 | AssumeRolePolicyDocument: 36 | Version: "2012-10-17" 37 | Statement: 38 | - Effect: Allow 39 | Principal: 40 | AWS: !Sub "arn:aws:iam::${AWS::AccountId}:role/${ServiceName}-CiCodeBuildRole" 41 | Action: 42 | - sts:AssumeRole 43 | Policies: 44 | - PolicyName: !Sub "${ServiceName}-CiRolePolicy" 45 | PolicyDocument: 46 | Version: "2012-10-17" 47 | Statement: 48 | - Effect: Allow 49 | Action: 50 | - "dynamodb:PutItem" 51 | - "dynamodb:GetItem" 52 | - "dynamodb:Scan" 53 | Resource: 54 | - !Sub "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${ServiceName}-staging-customer" 55 | 56 | CiStack: 57 | Type: 'AWS::CloudFormation::Stack' 58 | Properties: 59 | TemplateURL: !Sub "https://${CfnS3Bucket}.s3.${AWS::Region}.amazonaws.com/ci.yaml" 60 | Parameters: 61 | ServiceName: !Ref ServiceName 62 | ServiceJarFilename: !Ref ServiceJarFilename 63 | CracCheckpointsBucket: !Ref CracCheckpointsBucket 64 | VpcId: !Ref VpcId 65 | VpcSubnetIds: !Join [",", !Ref VpcSubnetIds] 66 | SecurityGroupIds: !Join [",", !Ref SecurityGroupIds] 67 | EfsDns: !Ref EfsDns 68 | -------------------------------------------------------------------------------- /examples/cmn/cfn/springdemo-infra.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: Infrastructure stack 3 | Parameters: 4 | ServiceName: 5 | Type: String 6 | Description: Enter the service name. 7 | 8 | Resources: 9 | StagingCustomerTable: 10 | Type: AWS::DynamoDB::Table 11 | Properties: 12 | AttributeDefinitions: 13 | - AttributeName: "Id" 14 | AttributeType: "S" 15 | KeySchema: 16 | - AttributeName: "Id" 17 | KeyType: "HASH" 18 | ProvisionedThroughput: 19 | ReadCapacityUnits: "5" 20 | WriteCapacityUnits: "5" 21 | TableName: !Sub "${ServiceName}-staging-customer" 22 | ProdCustomerTable: 23 | Type: AWS::DynamoDB::Table 24 | Properties: 25 | AttributeDefinitions: 26 | - AttributeName: "Id" 27 | AttributeType: "S" 28 | KeySchema: 29 | - AttributeName: "Id" 30 | KeyType: "HASH" 31 | ProvisionedThroughput: 32 | ReadCapacityUnits: "5" 33 | WriteCapacityUnits: "5" 34 | TableName: !Sub "${ServiceName}-prod-customer" 35 | 36 | -------------------------------------------------------------------------------- /examples/cmn/cfn/springdemo-main.yaml: -------------------------------------------------------------------------------- 1 | AWSTemplateFormatVersion: "2010-09-09" 2 | Description: Deploys springdemo infrastructure dependencies and CI pipeline 3 | Parameters: 4 | CfnS3Bucket: 5 | Type: String 6 | Description: Enter the name of the S3 buckets that contains the CloudFormation templates 7 | ServiceName: 8 | Type: String 9 | Description: Enter the service name 10 | ServiceJarFilename: 11 | Type: String 12 | Description: Enter the service JAR filename 13 | CracCheckpointsBucket: 14 | Type: String 15 | Description: Enter CRaC checkpoints S3 bucket name 16 | VpcId: 17 | Type: String 18 | Description: Enter the id of the VPC that CI runs in (should have access to EFS where CRaC checkpoint files are stored) 19 | VpcSubnetIds: 20 | Type: CommaDelimitedList 21 | Description: Enter the ids of the subnets that CI runs in (should have access to EFS where CRaC checkpoint files are stored) 22 | SecurityGroupIds: 23 | Type: CommaDelimitedList 24 | Description: Enter the ids of the security group that CI uses for accessing VPC resources (EFS where CRaC checkpoint files are stored) 25 | EfsDns: 26 | Type: String 27 | Description: Enter the EFS filesystem DNS 28 | 29 | Resources: 30 | CiStack: 31 | Type: 'AWS::CloudFormation::Stack' 32 | Properties: 33 | TemplateURL: !Sub "https://${CfnS3Bucket}.s3.${AWS::Region}.amazonaws.com/springdemo-ci.yaml" 34 | Parameters: 35 | ServiceName: !Sub "${ServiceName}" 36 | CfnS3Bucket: !Sub "${CfnS3Bucket}" 37 | ServiceJarFilename: !Sub "${ServiceJarFilename}" 38 | CracCheckpointsBucket: !Sub "${CracCheckpointsBucket}" 39 | VpcId: !Ref VpcId 40 | VpcSubnetIds: !Join [",", !Ref VpcSubnetIds] 41 | SecurityGroupIds: !Join [",", !Ref SecurityGroupIds] 42 | EfsDns: !Ref EfsDns 43 | 44 | InfraStack: 45 | Type: 'AWS::CloudFormation::Stack' 46 | Properties: 47 | TemplateURL: !Sub "https://${CfnS3Bucket}.s3.${AWS::Region}.amazonaws.com/springdemo-infra.yaml" 48 | Parameters: 49 | ServiceName: !Sub "${ServiceName}" 50 | 51 | -------------------------------------------------------------------------------- /examples/cmn/codebuild/buildspec.yml: -------------------------------------------------------------------------------- 1 | version: 0.2 2 | 3 | phases: 4 | pre_build: 5 | commands: 6 | - echo Logging in to Amazon ECR... 7 | - aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com 8 | build: 9 | commands: 10 | - echo Build started on `date` 11 | - export IMAGE_REPO_NAME=${SRVC_NAME} 12 | - docker build -t $SRVC_NAME:wo-checkpoint -f dockerfiles/Dockerfile_Build . 13 | - ASSUME_ROLE_ARN="${ROLE_ARN}" 14 | - TEMP_ROLE=$(aws sts assume-role --role-arn $ASSUME_ROLE_ARN --role-session-name test) 15 | - export TEMP_ROLE 16 | - export CI_AWS_ACCESS_KEY_ID=$(echo "${TEMP_ROLE}" | jq -r '.Credentials.AccessKeyId') 17 | - export CI_AWS_SECRET_ACCESS_KEY=$(echo "${TEMP_ROLE}" | jq -r '.Credentials.SecretAccessKey') 18 | - export CI_AWS_SESSION_TOKEN=$(echo "${TEMP_ROLE}" | jq -r '.Credentials.SessionToken') 19 | - mkdir crac-files 20 | - docker run --env AWS_REGION=$AWS_DEFAULT_REGION --env AWS_ACCESS_KEY_ID=$CI_AWS_ACCESS_KEY_ID --env AWS_SECRET_ACCESS_KEY=$CI_AWS_SECRET_ACCESS_KEY --env AWS_SESSION_TOKEN=$CI_AWS_SESSION_TOKEN --env SRVC_JAR_FILE_NAME=$SRVC_JAR_FILE_NAME --env MODE=ci --env AMAZON_DYNAMO_DB_ENDPOINT=https://dynamodb.$AWS_DEFAULT_REGION.amazonaws.com -v $PWD/crac-files:/opt/crac-files --rm --name $SRVC_NAME $SRVC_NAME:wo-checkpoint /opt/scripts/checkpoint.sh 21 | - aws s3 sync crac-files s3://$CRAC_CHECKPOINTS_BUCKET/$SRVC_NAME/v$CODEBUILD_BUILD_NUMBER/ 22 | - echo $CODEBUILD_CRAC_CHECKPOINTS_EFS 23 | - mkdir -p $CODEBUILD_CRAC_CHECKPOINTS_EFS/$SRVC_NAME/v$CODEBUILD_BUILD_NUMBER 24 | - cp crac-files/* $CODEBUILD_CRAC_CHECKPOINTS_EFS/$SRVC_NAME/v$CODEBUILD_BUILD_NUMBER 25 | - sed -i "s|SRVC_NAME|${SRVC_NAME}|" dockerfiles/Dockerfile_Run 26 | - docker build -t $SRVC_NAME:checkpoint -f dockerfiles/Dockerfile_Run . 27 | - docker tag $SRVC_NAME:wo-checkpoint $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:v$CODEBUILD_BUILD_NUMBER 28 | - docker tag $SRVC_NAME:checkpoint $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:v$CODEBUILD_BUILD_NUMBER-checkpoint 29 | 30 | post_build: 31 | commands: 32 | - echo Build completed on `date` 33 | - echo Pushing the Docker image... 34 | - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:v$CODEBUILD_BUILD_NUMBER 35 | - docker push $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME:v$CODEBUILD_BUILD_NUMBER-checkpoint -------------------------------------------------------------------------------- /examples/cmn/dockerfiles/Dockerfile_Build: -------------------------------------------------------------------------------- 1 | FROM azul/zulu-openjdk:23.0.1-jdk-crac as builder 2 | 3 | COPY ./pom.xml ./pom.xml 4 | COPY src ./src/ 5 | 6 | ENV MAVEN_OPTS='-Xmx6g' 7 | 8 | # > /dev/null 2>&1 used for sdkman because sdkmans uses stderr for progress bar. 9 | # Neither is a best practice, this is done to reduce the log lines produced. 10 | RUN apt-get --fix-missing -qq update \ 11 | && apt-get -qq -y install zip curl > /dev/null \ 12 | && curl -s "https://get.sdkman.io" | bash > /dev/null 2>&1 \ 13 | && bash -c "source $HOME/.sdkman/bin/sdkman-init.sh; \ 14 | sdk install maven > /dev/null 2>&1; \ 15 | mvn --no-transfer-progress -Dmaven.test.skip=true clean package" 16 | 17 | FROM azul/zulu-openjdk:23.0.1-jdk-crac 18 | 19 | RUN apt-get --fix-missing -qq update \ 20 | && apt-get -qq -y install zip curl > /dev/null \ 21 | && curl -s "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip" \ 22 | && unzip -qq awscliv2.zip \ 23 | && ./aws/install \ 24 | && chown root:root $JAVA_HOME/lib/criu \ 25 | && chmod 777 $JAVA_HOME/lib/criu \ 26 | && rm -f awscliv2.zip \ 27 | && rm -rf /var/lib/apt/lists/* 28 | COPY scripts/* /opt/scripts/ 29 | COPY --from=builder target/${SRVC_JAR_FILE_NAME} ${SRVC_JAR_FILE_NAME} 30 | -------------------------------------------------------------------------------- /examples/cmn/dockerfiles/Dockerfile_Run: -------------------------------------------------------------------------------- 1 | FROM SRVC_NAME:wo-checkpoint 2 | COPY crac-files /opt/crac-files -------------------------------------------------------------------------------- /examples/cmn/k8s-stage/s3-mount/deployment-crac-s3-express-mount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: spring-boot-ddb-crac-s3-express-mount 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: spring-boot-ddb-crac-s3-express-mount 10 | template: 11 | metadata: 12 | labels: 13 | app: spring-boot-ddb-crac-s3-express-mount 14 | spec: 15 | serviceAccountName: spring-boot-ddb 16 | volumes: 17 | - name: persistent-storage 18 | persistentVolumeClaim: 19 | claimName: s3-express-claim 20 | containers: 21 | - name: spring-boot-ddb-crac-s3-express-mount 22 | image: $SRVC_IMAGE_WO_CRAC 23 | imagePullPolicy: Always 24 | volumeMounts: 25 | - name: persistent-storage 26 | mountPath: /opt/crac-files 27 | ports: 28 | - containerPort: 8080 29 | name: http 30 | protocol: TCP 31 | securityContext: 32 | capabilities: 33 | add: 34 | - CHECKPOINT_RESTORE 35 | - SYS_PTRACE 36 | privileged: false 37 | runAsUser: 0 38 | allowPrivilegeEscalation: false 39 | command: ["/bin/bash"] 40 | args: ["/opt/scripts/run-service-crac.sh"] 41 | env: 42 | - name: CRAC_CHECKPOINT_PATH 43 | value: /opt/crac-files/$SRVC_NAME/$SRVC_VERSION 44 | - name: SRVC_JAR_FILE_NAME 45 | value: $SRVC_JAR_FILENAME 46 | - name: MODE 47 | valueFrom: 48 | configMapKeyRef: 49 | name: spring-demo-config 50 | key: mode 51 | - name: AMAZON_DYNAMO_DB_ENDPOINT 52 | valueFrom: 53 | configMapKeyRef: 54 | name: spring-demo-config 55 | key: amazon.dynamodb.endpoint 56 | readinessProbe: 57 | httpGet: 58 | path: /actuator/health/readiness 59 | port: 8080 60 | initialDelaySeconds: 1 61 | periodSeconds: 1 62 | failureThreshold: 60 63 | --- 64 | apiVersion: v1 65 | kind: Service 66 | metadata: 67 | name: spring-boot-ddb-crac-s3-express-mount-service 68 | spec: 69 | ports: 70 | - port: 8080 71 | targetPort: 8080 72 | protocol: TCP 73 | type: NodePort 74 | selector: 75 | app: spring-boot-ddb-crac-s3-express-mount 76 | --- 77 | apiVersion: networking.k8s.io/v1 78 | kind: Ingress 79 | metadata: 80 | name: spring-boot-ddb-crac-s3-express-mount-ingress 81 | annotations: 82 | alb.ingress.kubernetes.io/scheme: internet-facing 83 | alb.ingress.kubernetes.io/target-type: ip 84 | spec: 85 | ingressClassName: alb 86 | rules: 87 | - http: 88 | paths: 89 | - path: / 90 | pathType: Prefix 91 | backend: 92 | service: 93 | name: spring-boot-ddb-crac-s3-express-mount-service 94 | port: 95 | number: 8080 -------------------------------------------------------------------------------- /examples/cmn/k8s-stage/s3-mount/deployment-crac-s3-mount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: spring-boot-ddb-crac-s3-mount 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: spring-boot-ddb-crac-s3-mount 10 | template: 11 | metadata: 12 | labels: 13 | app: spring-boot-ddb-crac-s3-mount 14 | spec: 15 | serviceAccountName: spring-boot-ddb 16 | volumes: 17 | - name: persistent-storage 18 | persistentVolumeClaim: 19 | claimName: s3-claim 20 | containers: 21 | - name: spring-boot-ddb-crac-s3-mount 22 | image: $SRVC_IMAGE_WO_CRAC 23 | imagePullPolicy: Always 24 | volumeMounts: 25 | - name: persistent-storage 26 | mountPath: /opt/crac-files 27 | ports: 28 | - containerPort: 8080 29 | name: http 30 | protocol: TCP 31 | securityContext: 32 | capabilities: 33 | add: 34 | - CHECKPOINT_RESTORE 35 | - SYS_PTRACE 36 | privileged: false 37 | runAsUser: 0 38 | allowPrivilegeEscalation: false 39 | command: ["/bin/bash"] 40 | args: ["/opt/scripts/run-service-crac.sh"] 41 | env: 42 | - name: CRAC_CHECKPOINT_PATH 43 | value: /opt/crac-files/$SRVC_NAME/$SRVC_VERSION 44 | - name: SRVC_JAR_FILE_NAME 45 | value: $SRVC_JAR_FILENAME 46 | - name: MODE 47 | valueFrom: 48 | configMapKeyRef: 49 | name: spring-demo-config 50 | key: mode 51 | - name: AMAZON_DYNAMO_DB_ENDPOINT 52 | valueFrom: 53 | configMapKeyRef: 54 | name: spring-demo-config 55 | key: amazon.dynamodb.endpoint 56 | readinessProbe: 57 | httpGet: 58 | path: /actuator/health/readiness 59 | port: 8080 60 | initialDelaySeconds: 1 61 | periodSeconds: 1 62 | failureThreshold: 60 63 | --- 64 | apiVersion: v1 65 | kind: Service 66 | metadata: 67 | name: spring-boot-ddb-crac-s3-mount-service 68 | spec: 69 | ports: 70 | - port: 8080 71 | targetPort: 8080 72 | protocol: TCP 73 | type: NodePort 74 | selector: 75 | app: spring-boot-ddb-crac-s3-mount 76 | --- 77 | apiVersion: networking.k8s.io/v1 78 | kind: Ingress 79 | metadata: 80 | name: spring-boot-ddb-crac-s3-mount-ingress 81 | annotations: 82 | alb.ingress.kubernetes.io/scheme: internet-facing 83 | alb.ingress.kubernetes.io/target-type: ip 84 | spec: 85 | ingressClassName: alb 86 | rules: 87 | - http: 88 | paths: 89 | - path: / 90 | pathType: Prefix 91 | backend: 92 | service: 93 | name: spring-boot-ddb-crac-s3-mount-service 94 | port: 95 | number: 8080 -------------------------------------------------------------------------------- /examples/cmn/k8s-stage/s3-mount/s3-express-mount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolume 3 | metadata: 4 | name: s3-express-pv 5 | spec: 6 | capacity: 7 | storage: 1200Gi # ignored, required 8 | accessModes: 9 | - ReadWriteMany # supported options: ReadWriteMany / ReadOnlyMany 10 | mountOptions: 11 | - allow-delete 12 | - region $AWS_REGION 13 | - cache /mnt/mp-cache 14 | #- cache /mnt/mp-cache-tmpfs 15 | csi: 16 | driver: s3.csi.aws.com # required 17 | volumeHandle: s3-csi-driver-volume 18 | volumeAttributes: 19 | bucketName: $CRAC_CHECKPOINTS_S3_EXPRESS 20 | nodeAffinity: 21 | required: 22 | nodeSelectorTerms: 23 | - matchExpressions: 24 | - key: topology.kubernetes.io/zone 25 | operator: In 26 | values: 27 | - $AZ 28 | --- 29 | apiVersion: v1 30 | kind: PersistentVolumeClaim 31 | metadata: 32 | name: s3-express-claim 33 | spec: 34 | accessModes: 35 | - ReadWriteMany # supported options: ReadWriteMany / ReadOnlyMany 36 | storageClassName: "" # required for static provisioning 37 | resources: 38 | requests: 39 | storage: 1200Gi # ignored, required 40 | volumeName: s3-express-pv 41 | -------------------------------------------------------------------------------- /examples/cmn/k8s-stage/s3-mount/s3-mount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolume 3 | metadata: 4 | name: s3-pv 5 | spec: 6 | capacity: 7 | storage: 1200Gi # ignored, required 8 | accessModes: 9 | - ReadWriteMany # supported options: ReadWriteMany / ReadOnlyMany 10 | mountOptions: 11 | - allow-delete 12 | - region $AWS_REGION 13 | - cache /mnt/mp-cache 14 | #- cache /mnt/mp-cache-tmpfs 15 | csi: 16 | driver: s3.csi.aws.com # required 17 | volumeHandle: s3-csi-driver-volume 18 | volumeAttributes: 19 | bucketName: $CRAC_CHECKPOINTS_S3 20 | --- 21 | apiVersion: v1 22 | kind: PersistentVolumeClaim 23 | metadata: 24 | name: s3-claim 25 | spec: 26 | accessModes: 27 | - ReadWriteMany # supported options: ReadWriteMany / ReadOnlyMany 28 | storageClassName: "" # required for static provisioning 29 | resources: 30 | requests: 31 | storage: 1200Gi # ignored, required 32 | volumeName: s3-pv 33 | -------------------------------------------------------------------------------- /examples/cmn/k8s/efs-mount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: storage.k8s.io/v1 2 | kind: StorageClass 3 | metadata: 4 | name: efs-sc 5 | provisioner: efs.csi.aws.com 6 | --- 7 | apiVersion: v1 8 | kind: PersistentVolume 9 | metadata: 10 | name: efs-pv 11 | spec: 12 | capacity: 13 | storage: 5Gi 14 | volumeMode: Filesystem 15 | accessModes: 16 | - ReadWriteMany 17 | storageClassName: efs-sc 18 | persistentVolumeReclaimPolicy: Retain 19 | csi: 20 | driver: efs.csi.aws.com 21 | volumeHandle: $EFS_ID 22 | --- 23 | apiVersion: v1 24 | kind: PersistentVolumeClaim 25 | metadata: 26 | name: efs-claim 27 | spec: 28 | accessModes: 29 | - ReadWriteMany 30 | storageClassName: efs-sc 31 | resources: 32 | requests: 33 | storage: 5Gi -------------------------------------------------------------------------------- /examples/cmn/k8s/springdemo/deployment-crac-efs-mount.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: $SRVC_NAME-crac-efs-mount 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: $SRVC_NAME-crac-efs-mount 10 | template: 11 | metadata: 12 | labels: 13 | app: $SRVC_NAME-crac-efs-mount 14 | spec: 15 | serviceAccountName: $SRVC_NAME 16 | volumes: 17 | - name: persistent-storage 18 | persistentVolumeClaim: 19 | claimName: efs-claim 20 | containers: 21 | - name: $SRVC_NAME-crac-efs-mount 22 | image: $SRVC_IMAGE_NOCRAC 23 | imagePullPolicy: Always 24 | volumeMounts: 25 | - name: persistent-storage 26 | mountPath: /opt/crac-files 27 | ports: 28 | - containerPort: 8080 29 | name: http 30 | protocol: TCP 31 | command: ["/bin/bash"] 32 | args: ["/opt/scripts/run-service-crac.sh"] 33 | envFrom: 34 | - configMapRef: 35 | name: $SRVC_NAME-config 36 | env: 37 | - name: CRAC_CHECKPOINT_PATH 38 | value: /opt/crac-files/$SRVC_NAME/$SRVC_VERSION 39 | - name: SRVC_JAR_FILE_NAME 40 | value: $SRVC_JAR_FILENAME 41 | readinessProbe: 42 | httpGet: 43 | path: /actuator/health/readiness 44 | port: 8080 45 | initialDelaySeconds: 1 46 | periodSeconds: 1 47 | failureThreshold: 60 48 | --- 49 | apiVersion: v1 50 | kind: Service 51 | metadata: 52 | name: $SRVC_NAME-crac-efs-mount-service 53 | spec: 54 | ports: 55 | - port: 8080 56 | targetPort: 8080 57 | protocol: TCP 58 | type: NodePort 59 | selector: 60 | app: $SRVC_NAME-crac-efs-mount 61 | --- 62 | apiVersion: networking.k8s.io/v1 63 | kind: Ingress 64 | metadata: 65 | name: $SRVC_NAME-crac-efs-mount-ingress 66 | annotations: 67 | alb.ingress.kubernetes.io/scheme: internet-facing 68 | alb.ingress.kubernetes.io/target-type: ip 69 | spec: 70 | ingressClassName: alb 71 | rules: 72 | - http: 73 | paths: 74 | - path: / 75 | pathType: Prefix 76 | backend: 77 | service: 78 | name: $SRVC_NAME-crac-efs-mount-service 79 | port: 80 | number: 8080 -------------------------------------------------------------------------------- /examples/cmn/k8s/springdemo/deployment-crac-s3-cli.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: $SRVC_NAME-crac-s3-cli 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: $SRVC_NAME-crac-s3-cli 10 | template: 11 | metadata: 12 | labels: 13 | app: $SRVC_NAME-crac-s3-cli 14 | spec: 15 | serviceAccountName: $SRVC_NAME 16 | containers: 17 | - name: $SRVC_NAME-crac-s3-cli 18 | image: $SRVC_IMAGE_NOCRAC 19 | imagePullPolicy: Always 20 | ports: 21 | - containerPort: 8080 22 | name: http 23 | protocol: TCP 24 | command: ["/bin/bash"] 25 | args: ["/opt/scripts/run-service-crac-s3.sh"] 26 | envFrom: 27 | - configMapRef: 28 | name: $SRVC_NAME-config 29 | env: 30 | - name: CRAC_CHECKPOINT_PATH 31 | value: /opt/crac-files 32 | - name: CRAC_CHECKPOINT_S3 33 | value: $CRAC_CHECKPOINTS_S3/$SRVC_NAME/$SRVC_VERSION 34 | - name: SRVC_JAR_FILE_NAME 35 | value: $SRVC_JAR_FILENAME 36 | readinessProbe: 37 | httpGet: 38 | path: /actuator/health/readiness 39 | port: 8080 40 | initialDelaySeconds: 1 41 | periodSeconds: 1 42 | failureThreshold: 60 43 | --- 44 | apiVersion: v1 45 | kind: Service 46 | metadata: 47 | name: $SRVC_NAME-crac-s3-cli-service 48 | spec: 49 | ports: 50 | - port: 8080 51 | targetPort: 8080 52 | protocol: TCP 53 | type: NodePort 54 | selector: 55 | app: $SRVC_NAME-crac-s3-cli 56 | --- 57 | apiVersion: networking.k8s.io/v1 58 | kind: Ingress 59 | metadata: 60 | name: $SRVC_NAME-crac-s3-cli-ingress 61 | annotations: 62 | alb.ingress.kubernetes.io/scheme: internet-facing 63 | alb.ingress.kubernetes.io/target-type: ip 64 | spec: 65 | ingressClassName: alb 66 | rules: 67 | - http: 68 | paths: 69 | - path: / 70 | pathType: Prefix 71 | backend: 72 | service: 73 | name: $SRVC_NAME-crac-s3-cli-service 74 | port: 75 | number: 8080 -------------------------------------------------------------------------------- /examples/cmn/k8s/springdemo/deployment-crac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: $SRVC_NAME-crac 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: $SRVC_NAME-crac 10 | template: 11 | metadata: 12 | labels: 13 | app: $SRVC_NAME-crac 14 | spec: 15 | serviceAccountName: $SRVC_NAME 16 | containers: 17 | - name: $SRVC_NAME-crac 18 | image: $SRVC_IMAGE 19 | imagePullPolicy: Always 20 | ports: 21 | - containerPort: 8080 22 | name: http 23 | protocol: TCP 24 | envFrom: 25 | - configMapRef: 26 | name: $SRVC_NAME-config 27 | env: 28 | - name: CRAC_CHECKPOINT_PATH 29 | value: /opt/crac-files 30 | command: ["/bin/bash"] 31 | args: ["/opt/scripts/run-service-crac.sh"] 32 | readinessProbe: 33 | httpGet: 34 | path: /actuator/health/readiness 35 | port: 8080 36 | initialDelaySeconds: 1 37 | periodSeconds: 1 38 | failureThreshold: 60 39 | 40 | --- 41 | apiVersion: v1 42 | kind: Service 43 | metadata: 44 | name: $SRVC_NAME-crac-service 45 | spec: 46 | ports: 47 | - port: 8080 48 | targetPort: 8080 49 | protocol: TCP 50 | type: NodePort 51 | selector: 52 | app: $SRVC_NAME-crac 53 | --- 54 | apiVersion: networking.k8s.io/v1 55 | kind: Ingress 56 | metadata: 57 | name: $SRVC_NAME-crac-ingress 58 | annotations: 59 | alb.ingress.kubernetes.io/scheme: internet-facing 60 | alb.ingress.kubernetes.io/target-type: ip 61 | spec: 62 | ingressClassName: alb 63 | rules: 64 | - http: 65 | paths: 66 | - path: / 67 | pathType: Prefix 68 | backend: 69 | service: 70 | name: $SRVC_NAME-crac-service 71 | port: 72 | number: 8080 -------------------------------------------------------------------------------- /examples/cmn/k8s/springdemo/deployment-nocrac.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: $SRVC_NAME-nocrac 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: $SRVC_NAME-nocrac 10 | template: 11 | metadata: 12 | labels: 13 | app: $SRVC_NAME-nocrac 14 | spec: 15 | serviceAccountName: $SRVC_NAME 16 | containers: 17 | - name: $SRVC_NAME-nocrac 18 | image: $SRVC_IMAGE_NOCRAC 19 | imagePullPolicy: Always 20 | ports: 21 | - containerPort: 8080 22 | name: http 23 | protocol: TCP 24 | command: ["/bin/bash"] 25 | args: ["/opt/scripts/run-service.sh"] 26 | envFrom: 27 | - configMapRef: 28 | name: $SRVC_NAME-config 29 | env: 30 | - name: SRVC_JAR_FILE_NAME 31 | value: $SRVC_JAR_FILENAME 32 | readinessProbe: 33 | httpGet: 34 | path: /actuator/health/readiness 35 | port: 8080 36 | initialDelaySeconds: 1 37 | periodSeconds: 1 38 | failureThreshold: 60 39 | --- 40 | apiVersion: v1 41 | kind: Service 42 | metadata: 43 | name: $SRVC_NAME-nocrac-service 44 | spec: 45 | ports: 46 | - port: 8080 47 | targetPort: 8080 48 | protocol: TCP 49 | type: NodePort 50 | selector: 51 | app: $SRVC_NAME-nocrac 52 | --- 53 | apiVersion: networking.k8s.io/v1 54 | kind: Ingress 55 | metadata: 56 | name: $SRVC_NAME-nocrac-ingress 57 | annotations: 58 | alb.ingress.kubernetes.io/scheme: internet-facing 59 | alb.ingress.kubernetes.io/target-type: ip 60 | spec: 61 | ingressClassName: alb 62 | rules: 63 | - http: 64 | paths: 65 | - path: / 66 | pathType: Prefix 67 | backend: 68 | service: 69 | name: $SRVC_NAME-nocrac-service 70 | port: 71 | number: 8080 -------------------------------------------------------------------------------- /examples/cmn/k8s/springdemo/kustomization.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: kustomize.config.k8s.io/v1beta1 2 | kind: Kustomization 3 | resources: 4 | - deployment-crac-efs-mount.yaml 5 | - deployment-crac-s3-cli.yaml 6 | - deployment-crac.yaml 7 | - deployment-nocrac.yaml 8 | - spring-config-map.yaml -------------------------------------------------------------------------------- /examples/cmn/k8s/springdemo/spring-config-map.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: $SRVC_NAME-config 5 | data: 6 | AMAZON_DYNAMO_DB_ENDPOINT: "https://dynamodb.$AWS_REGION.amazonaws.com" 7 | TABLE_NAME: "$SRVC_NAME-prod-customer" 8 | MODE: "prod" -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.1 9 | 10 | 11 | com.amazon 12 | CustomerService 13 | 0.0.1 14 | CustomerService 15 | Demo application to demonstrate steps for reducing startup time for Spring Boot app using CRaC 16 | 17 | 23 18 | 2.20.68 19 | 20 | 21 | 22 | software.amazon.awssdk 23 | dynamodb 24 | ${aws.sdk.version} 25 | 26 | 27 | commons-logging 28 | commons-logging 29 | 30 | 31 | 32 | 33 | software.amazon.awssdk 34 | ecs 35 | ${aws.sdk.version} 36 | 37 | 38 | software.amazon.awssdk 39 | sts 40 | ${aws.sdk.version} 41 | 42 | 43 | software.amazon.awssdk 44 | dynamodb-enhanced 45 | ${aws.sdk.version} 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-data-rest 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-web 54 | 55 | 56 | commons-logging 57 | commons-logging 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-starter-aop 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-actuator 68 | 69 | 70 | 71 | org.apache.commons 72 | commons-lang3 73 | 3.12.0 74 | 75 | 76 | com.fasterxml.jackson.datatype 77 | jackson-datatype-jsr310 78 | 2.13.2 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-starter-test 83 | test 84 | 85 | 86 | org.projectlombok 87 | lombok 88 | 1.18.36 89 | 90 | 91 | junit 92 | junit 93 | test 94 | 95 | 96 | org.crac 97 | crac 98 | 1.4.0 99 | 100 | 101 | io.kubernetes 102 | client-java 103 | 15.0.1 104 | 105 | 106 | io.kubernetes 107 | client-java-api 108 | 13.0.0 109 | 110 | 111 | 112 | 113 | 114 | 115 | org.apache.maven.plugins 116 | maven-compiler-plugin 117 | 118 | 119 | -proc:full 120 | 121 | 122 | 123 | 124 | org.springframework.boot 125 | spring-boot-maven-plugin 126 | 127 | 128 | 129 | 130 | src/main/resources 131 | true 132 | 133 | **/*.properties 134 | 135 | 136 | 137 | 138 | 139 | 140 | local 141 | 142 | local 143 | 144 | 145 | 146 | prod 147 | 148 | prod 149 | 150 | 151 | true 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/CustomerServiceApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService; 17 | 18 | import java.time.Instant; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | 23 | @SpringBootApplication 24 | public class CustomerServiceApplication { 25 | 26 | public static void main(String[] args) { 27 | SpringApplication.run(CustomerServiceApplication.class, args); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.config; 17 | 18 | import org.springframework.beans.factory.annotation.Value; 19 | import org.springframework.context.annotation.Configuration; 20 | 21 | @Configuration 22 | public class AppConfig { 23 | 24 | public final static Integer APPLICATION_VERSION = 2; 25 | 26 | @Value("${amazon.dynamodb.endpoint}") 27 | private String amazonDynamoDBEndpoint; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/controller/CustomerController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.controller; 17 | 18 | import com.amazon.customerService.exception.CustomerNotFoundException; 19 | import com.amazon.customerService.model.Customer; 20 | import com.amazon.customerService.service.CustomerService; 21 | import lombok.extern.slf4j.Slf4j; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.web.bind.annotation.*; 24 | 25 | import java.util.List; 26 | 27 | @Slf4j 28 | @RestController 29 | @RequestMapping("/api") 30 | public class CustomerController { 31 | 32 | @Autowired 33 | CustomerService customerService; 34 | 35 | @GetMapping("/customers") 36 | List getCustomers() { 37 | return customerService.findAll(); 38 | } 39 | 40 | @GetMapping("/customers/load") 41 | List loadCustomers() { 42 | customerService.loadCustomerData(100); 43 | return customerService.findAll(); 44 | } 45 | 46 | @PostMapping("/customers") 47 | Customer createCustomer(@RequestBody Customer customer) { 48 | return customerService.create(customer); 49 | } 50 | 51 | @GetMapping("/customers/{id}") 52 | Customer getCustomerbyId(@PathVariable String id) { 53 | return customerService.findById(id); 54 | } 55 | 56 | @PutMapping("/customers/{id}") 57 | Customer replaceCustomer(@RequestBody Customer newCustomer, @PathVariable String id) { 58 | Customer customer = customerService.findById(id); 59 | 60 | if (null == customer) { 61 | throw new CustomerNotFoundException(newCustomer.getId()); 62 | } 63 | 64 | customer.setId(newCustomer.getId()); 65 | customer.setRegDate(newCustomer.getRegDate()); 66 | customer.setEmail(newCustomer.getEmail()); 67 | customer.setAccountNumber(newCustomer.getAccountNumber()); 68 | customer.setName(newCustomer.getName()); 69 | 70 | customerService.update(customer); 71 | 72 | return customer; 73 | } 74 | 75 | @DeleteMapping("/customers/{id}") 76 | void deleteCustomerById(@PathVariable String id) { 77 | customerService.deleteById(id); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/exception/CustomerNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.exception; 17 | 18 | public class CustomerNotFoundException extends RuntimeException { 19 | 20 | public CustomerNotFoundException(String id) { 21 | super("Could not find customer " + id); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/model/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.model; 17 | 18 | import com.fasterxml.jackson.annotation.JsonInclude; 19 | import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute; 20 | import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; 21 | import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; 22 | 23 | import java.util.Date; 24 | import java.util.Objects; 25 | 26 | @DynamoDbBean 27 | @JsonInclude(JsonInclude.Include.NON_NULL) 28 | 29 | public class Customer { 30 | 31 | private String id, name, email, accountNumber; 32 | private Date regDate; 33 | 34 | @DynamoDbPartitionKey 35 | @DynamoDbAttribute(value = "Id") 36 | public String getId() { 37 | return id; 38 | } 39 | 40 | public void setId(String id) { 41 | this.id = id; 42 | } 43 | 44 | @DynamoDbAttribute(value = "Name") 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | 53 | @DynamoDbAttribute(value = "Email") 54 | public String getEmail() { 55 | return email; 56 | } 57 | 58 | public void setEmail(String email) { 59 | this.email = email; 60 | } 61 | 62 | @DynamoDbAttribute(value = "AccountNumber") 63 | public String getAccountNumber() { 64 | return accountNumber; 65 | } 66 | 67 | public void setAccountNumber(String accountNumber) { 68 | this.accountNumber = accountNumber; 69 | } 70 | 71 | @DynamoDbAttribute(value = "RegistrationDate") 72 | public Date getRegDate() { 73 | return regDate; 74 | } 75 | 76 | public void setRegDate(Date regDate) { 77 | this.regDate = regDate; 78 | } 79 | 80 | @Override 81 | public boolean equals(Object o) { 82 | if (this == o) return true; 83 | if (o == null || getClass() != o.getClass()) return false; 84 | Customer customer = (Customer) o; 85 | return id.equals(customer.id); 86 | } 87 | 88 | @Override 89 | public int hashCode() { 90 | return Objects.hash(id); 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return "Customer{" + 96 | "id='" + id + '\'' + 97 | ", name='" + name + '\'' + 98 | ", email='" + email + '\'' + 99 | ", accountNumber='" + accountNumber + '\'' + 100 | ", regDate=" + regDate + 101 | '}'; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/model/metrics/ContainerMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.model.metrics; 17 | 18 | import java.time.Duration; 19 | import java.time.Instant; 20 | import java.util.Objects; 21 | 22 | public class ContainerMetric { 23 | private Instant createdAt; 24 | private Instant startedAt; 25 | 26 | public ContainerMetric() { 27 | } 28 | 29 | public ContainerMetric(Instant createdAt, Instant startedAt) { 30 | this.createdAt = createdAt; 31 | this.startedAt = startedAt; 32 | } 33 | 34 | public Duration calculateDuration() { 35 | if (startedAt == null || createdAt == null) 36 | return null; 37 | 38 | Duration duration = Duration.between(createdAt, startedAt); 39 | 40 | return duration; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "ContainerMetric{" + 46 | "createdAt=" + createdAt + 47 | ", startedAt=" + startedAt + 48 | '}'; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) return true; 54 | if (o == null || getClass() != o.getClass()) return false; 55 | ContainerMetric that = (ContainerMetric) o; 56 | return createdAt.equals(that.createdAt) && startedAt.equals(that.startedAt); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Objects.hash(createdAt, startedAt); 62 | } 63 | 64 | public Instant getCreatedAt() { 65 | return createdAt; 66 | } 67 | 68 | public void setCreatedAt(Instant createdAt) { 69 | this.createdAt = createdAt; 70 | } 71 | 72 | public Instant getStartedAt() { 73 | return startedAt; 74 | } 75 | 76 | public void setStartedAt(Instant startedAt) { 77 | this.startedAt = startedAt; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/model/metrics/MetricWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.model.metrics; 17 | 18 | import java.time.Duration; 19 | import java.time.Instant; 20 | 21 | public class MetricWrapper { 22 | 23 | private ContainerMetric containerMetric; 24 | private TaskMetric taskMetric; 25 | private PodMetric podMetric; 26 | private Duration springBootStartDuration; 27 | private Instant springBootReadyTime; 28 | private Integer version; 29 | 30 | public MetricWrapper() { 31 | } 32 | 33 | public MetricWrapper(ContainerMetric containerMetric, TaskMetric taskMetric, PodMetric podMetric, Duration springBootStartTime, Instant springBootReadyTime, Integer version) { 34 | this.containerMetric = containerMetric; 35 | this.taskMetric = taskMetric; 36 | this.springBootStartDuration = springBootStartTime; 37 | this.springBootReadyTime = springBootReadyTime; 38 | this.version = version; 39 | this.podMetric = podMetric; 40 | } 41 | 42 | public Integer getVersion() { 43 | return version; 44 | } 45 | 46 | public void setVersion(Integer version) { 47 | this.version = version; 48 | } 49 | 50 | public ContainerMetric getContainerMetric() { 51 | return containerMetric; 52 | } 53 | 54 | public void setContainerMetric(ContainerMetric containerMetric) { 55 | this.containerMetric = containerMetric; 56 | } 57 | 58 | public TaskMetric getTaskMetric() { 59 | return taskMetric; 60 | } 61 | 62 | public void setTaskMetric(TaskMetric taskMetric) { 63 | this.taskMetric = taskMetric; 64 | } 65 | 66 | public Instant getSpringBootReadyTime() { 67 | return springBootReadyTime; 68 | } 69 | 70 | public void setSpringBootReadyTime(Instant springBootReadyTime) { 71 | this.springBootReadyTime = springBootReadyTime; 72 | } 73 | 74 | public Duration getSpringBootStartDuration() { 75 | return springBootStartDuration; 76 | } 77 | 78 | public void setSpringBootStartDuration(Duration springBootStartDuration) { 79 | this.springBootStartDuration = springBootStartDuration; 80 | } 81 | 82 | public PodMetric getPodMetric() { 83 | return podMetric; 84 | } 85 | 86 | public void setPodMetric(PodMetric podMetric) { 87 | this.podMetric = podMetric; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/model/metrics/PodMetric.java: -------------------------------------------------------------------------------- 1 | package com.amazon.customerService.model.metrics; 2 | 3 | import java.time.Instant; 4 | import java.util.Objects; 5 | 6 | public class PodMetric { 7 | 8 | private Instant podScheduled; 9 | private Instant podReady; 10 | private String podId; 11 | 12 | public PodMetric() { 13 | 14 | } 15 | 16 | public PodMetric(Instant podScheduled, Instant podReady, String podId) { 17 | this.podScheduled = podScheduled; 18 | this.podReady = podReady; 19 | this.podId = podId; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "PodMetric{" + 25 | "podScheduled=" + podScheduled + 26 | ", podReady=" + podReady + 27 | ", podId='" + podId + '\'' + 28 | '}'; 29 | } 30 | 31 | @Override 32 | public boolean equals(Object o) { 33 | if (this == o) return true; 34 | if (o == null || getClass() != o.getClass()) return false; 35 | PodMetric podMetric = (PodMetric) o; 36 | return Objects.equals(podId, podMetric.podId); 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return Objects.hash(podId); 42 | } 43 | 44 | public Instant getPodScheduled() { 45 | return podScheduled; 46 | } 47 | 48 | public void setPodScheduled(Instant podScheduled) { 49 | this.podScheduled = podScheduled; 50 | } 51 | 52 | public Instant getPodReady() { 53 | return podReady; 54 | } 55 | 56 | public void setPodReady(Instant podReady) { 57 | this.podReady = podReady; 58 | } 59 | 60 | public String getPodId() { 61 | return podId; 62 | } 63 | 64 | public void setPodId(String podId) { 65 | this.podId = podId; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/model/metrics/TaskMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.model.metrics; 17 | 18 | import java.time.Duration; 19 | import java.time.Instant; 20 | import java.util.Objects; 21 | 22 | public class TaskMetric { 23 | private Instant pullStartedAt; 24 | private Instant pullStoppedAt; 25 | private String taskArn; 26 | 27 | public TaskMetric() { 28 | } 29 | 30 | public TaskMetric(Instant pullStartedAt, Instant pullStoppedAt, String taskArn) { 31 | this.pullStartedAt = pullStartedAt; 32 | this.pullStoppedAt = pullStoppedAt; 33 | this.taskArn = taskArn; 34 | } 35 | 36 | public Instant getPullStartedAt() { 37 | return pullStartedAt; 38 | } 39 | 40 | public void setPullStartedAt(Instant pullStartedAt) { 41 | this.pullStartedAt = pullStartedAt; 42 | } 43 | 44 | public Instant getPullStoppedAt() { 45 | return pullStoppedAt; 46 | } 47 | 48 | public void setPullStoppedAt(Instant pullStoppedAt) { 49 | this.pullStoppedAt = pullStoppedAt; 50 | } 51 | 52 | public Duration calculateDuration() { 53 | if (pullStartedAt == null || pullStoppedAt == null) 54 | return null; 55 | 56 | Duration duration = Duration.between(pullStartedAt, pullStoppedAt); 57 | 58 | return duration; 59 | } 60 | 61 | public String getTaskArn() { 62 | return taskArn; 63 | } 64 | 65 | public void setTaskArn(String taskArn) { 66 | this.taskArn = taskArn; 67 | } 68 | 69 | @Override 70 | public boolean equals(Object o) { 71 | if (this == o) return true; 72 | if (o == null || getClass() != o.getClass()) return false; 73 | TaskMetric that = (TaskMetric) o; 74 | return taskArn.equals(that.taskArn); 75 | } 76 | 77 | @Override 78 | public int hashCode() { 79 | return Objects.hash(taskArn); 80 | } 81 | 82 | @Override 83 | public String toString() { 84 | return "TaskMetric{" + 85 | "pullStartedAt=" + pullStartedAt + 86 | ", pullStoppedAt=" + pullStoppedAt + 87 | ", taskArn='" + taskArn + '\'' + 88 | '}'; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/repository/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.repository; 17 | 18 | import java.text.ParseException; 19 | import java.text.SimpleDateFormat; 20 | import java.util.ArrayList; 21 | import java.util.Date; 22 | import java.util.HashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | import java.util.UUID; 26 | 27 | import javax.annotation.PostConstruct; 28 | 29 | import org.crac.Context; 30 | import org.crac.Core; 31 | import org.crac.Resource; 32 | import org.springframework.beans.factory.annotation.Autowired; 33 | import org.springframework.core.env.Environment; 34 | import org.springframework.stereotype.Repository; 35 | 36 | import com.amazon.customerService.model.Customer; 37 | 38 | import lombok.extern.slf4j.Slf4j; 39 | import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; 40 | import software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider; 41 | import software.amazon.awssdk.services.dynamodb.DynamoDbClient; 42 | import software.amazon.awssdk.services.dynamodb.model.AttributeValue; 43 | import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest; 44 | import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; 45 | import software.amazon.awssdk.services.dynamodb.model.GetItemResponse; 46 | import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; 47 | import software.amazon.awssdk.services.dynamodb.model.ScanRequest; 48 | 49 | @Slf4j 50 | @Repository 51 | public class CustomerRepository implements Resource { 52 | 53 | public static final String ID_COLUMN = "Id"; 54 | public static final String NAME_COLUMN = "Name"; 55 | public static final String EMAIL_COLUMN = "Email"; 56 | public static final String ACCOUNT_NUMBER_COLUMN = "AccountNumber"; 57 | public static final String REGISTRATION_DATE_COLUMN = "RegistrationDate"; 58 | private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); 59 | 60 | private DynamoDbClient client; 61 | private String tableName; 62 | private String mode; 63 | 64 | @Autowired 65 | private Environment environment; 66 | 67 | @PostConstruct 68 | public void init() { 69 | loadConfig(); 70 | this.client = createDynamoDbClient(); 71 | Core.getGlobalContext().register(this); 72 | } 73 | 74 | @Override 75 | public void beforeCheckpoint(Context context) { 76 | log.info("Executing beforeCheckpoint..."); 77 | this.client.close(); 78 | } 79 | 80 | @Override 81 | public void afterRestore(Context context) { 82 | log.info("Executing afterRestore ..."); 83 | loadConfig(); 84 | this.client = createDynamoDbClient(); 85 | } 86 | 87 | public Customer save(final Customer customer) { 88 | 89 | customer.setId(UUID.randomUUID().toString()); 90 | 91 | if (customer.getRegDate() == null) { 92 | customer.setRegDate(new Date()); 93 | } 94 | 95 | PutItemRequest putItemRequest = PutItemRequest.builder() 96 | .tableName(this.tableName) 97 | .item(convertPojoToMap(customer)) 98 | .build(); 99 | 100 | client.putItem(putItemRequest); 101 | 102 | return customer; 103 | } 104 | 105 | public Customer findById(final String id) { 106 | 107 | log.debug("Find customer with id: " + id); 108 | 109 | Map key = new HashMap<>(); 110 | key.put(ID_COLUMN, AttributeValue.builder().s(id).build()); 111 | 112 | GetItemRequest getItemRequest = GetItemRequest.builder() 113 | .tableName(this.tableName) 114 | .key(key) 115 | .build(); 116 | 117 | GetItemResponse item = client.getItem(getItemRequest); 118 | Customer customer = null; 119 | if (item.hasItem()) { 120 | Map itemAttr = item.item(); 121 | customer = convertMapToPojo(itemAttr); 122 | } 123 | 124 | return customer; 125 | } 126 | 127 | public List findAll() { 128 | 129 | log.debug("Find all customers"); 130 | List customerList = new ArrayList<>(); 131 | 132 | ScanRequest scanRequest = ScanRequest.builder(). 133 | tableName(this.tableName). 134 | build(); 135 | 136 | List> list = client.scan(scanRequest).items(); 137 | 138 | for (Map item : list) { 139 | Customer customer = convertMapToPojo(item); 140 | customerList.add(customer); 141 | } 142 | 143 | log.debug("Found customers: "); 144 | for (Customer customer : customerList 145 | ) { 146 | log.debug(" -> " + customer); 147 | } 148 | 149 | return customerList; 150 | } 151 | 152 | public void deleteById(String id) { 153 | 154 | log.debug("Delete customer with id: " + id); 155 | 156 | Map key = new HashMap<>(); 157 | key.put(ID_COLUMN, AttributeValue.builder().s(id).build()); 158 | 159 | DeleteItemRequest deleteItemRequest = DeleteItemRequest.builder() 160 | .tableName(this.tableName) 161 | .key(key) 162 | .build(); 163 | 164 | client.deleteItem(deleteItemRequest); 165 | } 166 | 167 | private Map convertPojoToMap(final Customer customer) { 168 | Map item = new HashMap<>(); 169 | 170 | item.put(ID_COLUMN, AttributeValue.builder().s(customer.getId()).build()); 171 | item.put(NAME_COLUMN, AttributeValue.builder().s(customer.getName()).build()); 172 | item.put(EMAIL_COLUMN, AttributeValue.builder().s(customer.getEmail()).build()); 173 | item.put(ACCOUNT_NUMBER_COLUMN, AttributeValue.builder().s(customer.getAccountNumber()).build()); 174 | item.put(REGISTRATION_DATE_COLUMN, AttributeValue.builder().s(sdf.format(customer.getRegDate())).build()); 175 | 176 | return item; 177 | } 178 | 179 | private Customer convertMapToPojo(final Map item) { 180 | Customer customer = new Customer(); 181 | 182 | customer.setAccountNumber(item.get(ACCOUNT_NUMBER_COLUMN).s()); 183 | customer.setEmail(item.get(EMAIL_COLUMN).s()); 184 | customer.setAccountNumber(item.get(ACCOUNT_NUMBER_COLUMN).s()); 185 | customer.setId(item.get(ID_COLUMN).s()); 186 | 187 | Date registrationDate = null; 188 | 189 | try { 190 | registrationDate = sdf.parse(item.get(REGISTRATION_DATE_COLUMN).s()); 191 | } catch (ParseException exc) { 192 | log.error(exc.toString()); 193 | } 194 | 195 | customer.setRegDate(registrationDate); 196 | 197 | return customer; 198 | } 199 | 200 | private DynamoDbClient createDynamoDbClient() { 201 | log.info("Mode (through Environment Abstraction):" + this.mode); 202 | if ("ci".equals(this.mode)) { 203 | return DynamoDbClient.builder() 204 | .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) 205 | .build(); 206 | } 207 | 208 | return DynamoDbClient.builder() 209 | .credentialsProvider(WebIdentityTokenFileCredentialsProvider.create()) 210 | .build(); 211 | } 212 | 213 | private void loadConfig() { 214 | this.mode = environment.getProperty("mode"); 215 | this.tableName = environment.getProperty("table.name"); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/service/CustomerService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.service; 17 | 18 | import com.amazon.customerService.model.Customer; 19 | import com.amazon.customerService.repository.CustomerRepository; 20 | import org.apache.commons.lang3.RandomStringUtils; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.stereotype.Service; 23 | 24 | import java.sql.Date; 25 | import java.time.Instant; 26 | import java.util.List; 27 | import java.util.Random; 28 | import java.util.UUID; 29 | 30 | @Service 31 | public class CustomerService { 32 | 33 | @Autowired 34 | CustomerRepository customerRepository; 35 | 36 | public List findAll() { 37 | return customerRepository.findAll(); 38 | } 39 | 40 | public Customer findById(String id) { 41 | return customerRepository.findById(id); 42 | } 43 | 44 | public Customer create(Customer customer) { 45 | return customerRepository.save(customer); 46 | } 47 | 48 | public Customer update(Customer customer) { 49 | return customerRepository.save(customer); 50 | } 51 | 52 | public void deleteById(String id) { 53 | customerRepository.deleteById(id); 54 | } 55 | 56 | public void loadCustomerData(int count) { 57 | 58 | for (int i = 0; i < count; i++) { 59 | String generatedString = RandomStringUtils.randomAlphabetic(10); 60 | 61 | Customer cust = new Customer(); 62 | cust.setName(generatedString); 63 | cust.setId(UUID.randomUUID().toString()); 64 | cust.setRegDate(Date.from(Instant.now())); 65 | cust.setEmail(generatedString + "@test.com"); 66 | 67 | Random rnd = new Random(); 68 | int number = rnd.nextInt(999999); 69 | 70 | cust.setAccountNumber(String.format("%06d", number)); 71 | 72 | customerRepository.save(cust); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/service/EcsMetaDataService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.service; 17 | 18 | import com.amazon.customerService.model.metrics.ContainerMetric; 19 | import com.amazon.customerService.model.metrics.MetricWrapper; 20 | import com.amazon.customerService.model.metrics.TaskMetric; 21 | import com.fasterxml.jackson.core.JsonPointer; 22 | import com.fasterxml.jackson.databind.JsonNode; 23 | import com.fasterxml.jackson.databind.ObjectMapper; 24 | import lombok.extern.slf4j.Slf4j; 25 | import org.springframework.stereotype.Service; 26 | import software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider; 27 | import software.amazon.awssdk.services.ecs.EcsClient; 28 | import software.amazon.awssdk.services.ecs.model.DescribeTasksRequest; 29 | import software.amazon.awssdk.services.ecs.model.DescribeTasksResponse; 30 | import software.amazon.awssdk.services.ecs.model.Task; 31 | 32 | import java.io.IOException; 33 | import java.net.URI; 34 | import java.time.Instant; 35 | import java.util.List; 36 | 37 | @Slf4j 38 | @Service 39 | public class EcsMetaDataService { 40 | 41 | public MetricWrapper getMetaData() { 42 | 43 | MetricWrapper metricWrapper = new MetricWrapper(); 44 | 45 | try { 46 | var metaDataUrl = System.getenv("ECS_CONTAINER_METADATA_URI_V4"); 47 | 48 | if (metaDataUrl == null) { 49 | log.debug("metaDataUrl is null"); 50 | return null; 51 | } 52 | 53 | ObjectMapper objectMapper = new ObjectMapper(); 54 | JsonNode node = objectMapper.readTree(URI.create(metaDataUrl + "/task").toURL()); 55 | 56 | JsonPointer pointer = JsonPointer.compile("/TaskARN"); 57 | String taskArn = node.at(pointer).asText(); 58 | 59 | pointer = JsonPointer.compile("/Cluster"); 60 | String cluster = node.at(pointer).asText(); 61 | 62 | ContainerCredentialsProvider provider = ContainerCredentialsProvider.builder().build(); 63 | EcsClient ecsClient = EcsClient.builder().credentialsProvider(provider).build(); 64 | 65 | DescribeTasksRequest request = DescribeTasksRequest.builder() 66 | .tasks(taskArn).cluster(cluster).build(); 67 | DescribeTasksResponse response = ecsClient.describeTasks(request); 68 | 69 | Instant pullStartedAtInstant = null, pullStoppedAtInstant = null, createdAtInstant = null, startedAtInstant = null; 70 | 71 | if (response.hasTasks()) { 72 | List taskList = response.tasks(); 73 | Task task = taskList.get(0); 74 | 75 | pullStartedAtInstant = task.pullStartedAt(); 76 | pullStoppedAtInstant = task.pullStoppedAt(); 77 | createdAtInstant = task.createdAt(); 78 | startedAtInstant = task.startedAt(); 79 | } 80 | 81 | TaskMetric taskMetric = new TaskMetric(pullStartedAtInstant, pullStoppedAtInstant, taskArn); 82 | ContainerMetric containerMetric = new ContainerMetric(createdAtInstant, startedAtInstant); 83 | 84 | metricWrapper.setTaskMetric(taskMetric); 85 | metricWrapper.setContainerMetric(containerMetric); 86 | } catch (IOException exc) { 87 | log.error("An error occurred: ", exc); 88 | } 89 | 90 | return metricWrapper; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/service/EksMetricsService.java: -------------------------------------------------------------------------------- 1 | package com.amazon.customerService.service; 2 | 3 | import com.amazon.customerService.model.metrics.MetricWrapper; 4 | import com.amazon.customerService.model.metrics.PodMetric; 5 | import io.kubernetes.client.openapi.ApiClient; 6 | import io.kubernetes.client.openapi.ApiException; 7 | import io.kubernetes.client.openapi.Configuration; 8 | import io.kubernetes.client.openapi.apis.CoreV1Api; 9 | import io.kubernetes.client.openapi.models.V1Pod; 10 | import io.kubernetes.client.openapi.models.V1PodCondition; 11 | import io.kubernetes.client.util.ClientBuilder; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.io.BufferedReader; 16 | import java.io.FileReader; 17 | import java.io.IOException; 18 | import java.time.OffsetDateTime; 19 | import java.util.Objects; 20 | 21 | @Slf4j 22 | @Service 23 | public class EksMetricsService { 24 | public MetricWrapper getMetaData() { 25 | 26 | MetricWrapper metricWrapper = new MetricWrapper(); 27 | 28 | try { 29 | ApiClient client = ClientBuilder.cluster().build(); 30 | Configuration.setDefaultApiClient(client); 31 | 32 | BufferedReader reader = new BufferedReader(new FileReader("/var/run/secrets/kubernetes.io/serviceaccount/namespace")); 33 | String namespaceName = reader.readLine(); 34 | log.info("Namespace: " + namespaceName); 35 | 36 | reader.close(); 37 | 38 | String podName = System.getenv("HOSTNAME"); 39 | log.info("Pod: " + podName); 40 | 41 | CoreV1Api api = new CoreV1Api(); 42 | V1Pod pod = api.readNamespacedPod(podName, namespaceName, null, null, null); 43 | 44 | OffsetDateTime podScheduled = null, podReady = null; 45 | 46 | for (V1PodCondition condition : Objects.requireNonNull(pod.getStatus()).getConditions()) { 47 | if (condition.getType().equals("PodScheduled")) { 48 | if (condition.getStatus().equals("True")) { 49 | podScheduled = condition.getLastTransitionTime(); 50 | } 51 | } else if (condition.getType().equals("Ready")) { 52 | if (condition.getStatus().equals("True")) { 53 | podReady = condition.getLastTransitionTime(); 54 | } 55 | } 56 | } 57 | 58 | if (podReady != null && podScheduled != null) { 59 | 60 | PodMetric podMetric = new PodMetric(podScheduled.toInstant(), podReady.toInstant(), podName); 61 | metricWrapper.setPodMetric(podMetric); 62 | 63 | return metricWrapper; 64 | 65 | } else 66 | log.info("Something is null"); 67 | } catch (ApiException exc) { 68 | log.error("Couldn't generate k8s client"); 69 | log.error(exc.getResponseBody()); 70 | 71 | return null; 72 | } catch (IOException exc) { 73 | exc.printStackTrace(); 74 | return null; 75 | } catch (NumberFormatException exc) { 76 | exc.printStackTrace(); 77 | return null; 78 | } 79 | 80 | return metricWrapper; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/java/com/amazon/customerService/utils/TimingUtils.java: -------------------------------------------------------------------------------- 1 | package com.amazon.customerService.utils; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.RuntimeMXBean; 5 | import java.time.Duration; 6 | import java.time.Instant; 7 | 8 | import org.apache.commons.lang3.StringEscapeUtils; 9 | 10 | import com.amazon.customerService.config.AppConfig; 11 | import com.amazon.customerService.model.metrics.MetricWrapper; 12 | import com.amazon.customerService.service.EcsMetaDataService; 13 | import com.amazon.customerService.service.EksMetricsService; 14 | import com.fasterxml.jackson.core.JsonProcessingException; 15 | import com.fasterxml.jackson.databind.ObjectMapper; 16 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 17 | 18 | import lombok.extern.slf4j.Slf4j; 19 | 20 | @Slf4j 21 | public class TimingUtils { 22 | 23 | public static void measureTime(Instant endTime) { 24 | RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); 25 | Instant startTime = Instant.ofEpochMilli(bean.getStartTime()); 26 | Duration springBootStartTime = Duration.between(startTime, endTime); 27 | 28 | EcsMetaDataService ecsMetaDataService = new EcsMetaDataService(); 29 | EksMetricsService eksMetricsService = new EksMetricsService(); 30 | 31 | MetricWrapper metricWrapper = ecsMetaDataService.getMetaData(); 32 | 33 | if (metricWrapper == null) { 34 | metricWrapper = eksMetricsService.getMetaData(); 35 | } 36 | 37 | if (metricWrapper != null) { 38 | metricWrapper.setVersion(AppConfig.APPLICATION_VERSION); 39 | metricWrapper.setSpringBootStartDuration(springBootStartTime); 40 | metricWrapper.setSpringBootReadyTime(endTime); 41 | ObjectMapper mapper = new ObjectMapper() 42 | .registerModule(new JavaTimeModule()); 43 | 44 | try { 45 | String metricsJson = mapper.writeValueAsString(metricWrapper); 46 | log.info("Metrics: " + StringEscapeUtils.unescapeJson(metricsJson)); 47 | } catch (JsonProcessingException e) { 48 | log.error(e.getMessage()); 49 | } 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/resources/application-local.properties: -------------------------------------------------------------------------------- 1 | amazon.dynamodb.endpoint=http://localhost:8000/ 2 | logging.level.root=DEBUG -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | logging.level.root=INFO 2 | logging.level.com.amazon.customerService=DEBUG 3 | management.endpoint.health.probes.enabled=true 4 | management.health.readinessState.enabled=true -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/test/java/com/amazon/customerService/repository/CustomerRepositoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.repository; 17 | 18 | import com.amazon.customerService.model.Customer; 19 | import org.junit.Assert; 20 | import org.junit.jupiter.api.*; 21 | import org.junit.jupiter.api.extension.ExtendWith; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | import org.springframework.test.context.ActiveProfiles; 25 | import org.springframework.test.context.TestPropertySource; 26 | import org.springframework.test.context.junit.jupiter.SpringExtension; 27 | import org.springframework.test.context.web.WebAppConfiguration; 28 | import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; 29 | import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; 30 | import software.amazon.awssdk.enhanced.dynamodb.TableSchema; 31 | 32 | import java.time.Instant; 33 | import java.util.List; 34 | import java.util.UUID; 35 | 36 | @ExtendWith(SpringExtension.class) 37 | @SpringBootTest 38 | @WebAppConfiguration 39 | @ActiveProfiles("local") 40 | @TestPropertySource(properties = { 41 | "amazon.dynamodb.endpoint=http://localhost:8000/"}) 42 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 43 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 44 | @TestPropertySource(locations = "classpath:application-local.properties") 45 | public class CustomerRepositoryTest { 46 | 47 | @Autowired 48 | CustomerRepository repository; 49 | @Autowired 50 | private DynamoDbEnhancedClient dynamoDbEnhancedClient; 51 | private DynamoDbTable table; 52 | private Customer testCustomer; 53 | 54 | @BeforeAll 55 | public void setup() throws Exception { 56 | 57 | // Create the table locally 58 | 59 | table = dynamoDbEnhancedClient.table("Customer", 60 | TableSchema.fromBean(Customer.class)); 61 | 62 | testCustomer = createCustomer(); 63 | 64 | try { 65 | table.describeTable(); 66 | } catch (software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException exc) { 67 | // Table doesn't exist 68 | table.createTable(); 69 | } 70 | 71 | // Find and delete all customer entries 72 | List customerList = repository.findAll(); 73 | System.out.println("Customerlist: " + customerList); 74 | for (Customer customer : customerList) { 75 | System.out.println("Customer: " + customer); 76 | repository.deleteById(customer.getId()); 77 | } 78 | } 79 | 80 | private Customer createCustomer() { 81 | Customer customer = new Customer(); 82 | customer.setAccountNumber("111111"); 83 | customer.setEmail("test@test.com"); 84 | // customer.setRegDate(Instant.now()); 85 | customer.setName("John Doe"); 86 | 87 | UUID uuid = UUID.randomUUID(); 88 | String uuidAsString = uuid.toString(); 89 | 90 | customer.setId(uuidAsString); 91 | 92 | return customer; 93 | } 94 | 95 | @Test 96 | @Order(1) 97 | public void testCreate() { 98 | System.out.println("Adding customer: " + testCustomer); 99 | 100 | Customer savedCustomer = repository.save(testCustomer); 101 | Customer readCustomer = repository.findById(savedCustomer.getId()); 102 | 103 | Assert.assertEquals(savedCustomer, readCustomer); 104 | } 105 | 106 | @Test 107 | @Order(2) 108 | public void testRead() { 109 | String customerId = testCustomer.getId(); 110 | 111 | Customer tmpCustomer = repository.findById(customerId); 112 | Assert.assertEquals(testCustomer, tmpCustomer); 113 | } 114 | 115 | @Test 116 | @Order(3) 117 | public void testUpdate() { 118 | 119 | testCustomer.setName("NewName"); 120 | repository.save(testCustomer); 121 | 122 | Customer tmpCustomer = repository.findById(testCustomer.getId()); 123 | Assert.assertEquals(testCustomer.getName(), tmpCustomer.getName()); 124 | } 125 | 126 | @Test 127 | @Order(4) 128 | public void testDelete() { 129 | 130 | repository.deleteById(testCustomer.getId()); 131 | 132 | List customerList = repository.findAll(); 133 | Assert.assertEquals(0, customerList.size()); 134 | } 135 | 136 | @AfterAll 137 | public void tearDown() throws Exception { 138 | table.deleteTable(); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/test/resources/container_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "DockerId": "ea32192c8553fbff06c9340478a2ff089b2bb5646fb718b4ee206641c9086d66", 3 | "Name": "curl", 4 | "DockerName": "ecs-curltest-24-curl-cca48e8dcadd97805600", 5 | "Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest", 6 | "ImageID": "sha256:d691691e9652791a60114e67b365688d20d19940dde7c4736ea30e660d8d3553", 7 | "Labels": { 8 | "com.amazonaws.ecs.cluster": "default", 9 | "com.amazonaws.ecs.container-name": "curl", 10 | "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/8f03e41243824aea923aca126495f665", 11 | "com.amazonaws.ecs.task-definition-family": "curltest", 12 | "com.amazonaws.ecs.task-definition-version": "24" 13 | }, 14 | "DesiredStatus": "RUNNING", 15 | "KnownStatus": "RUNNING", 16 | "Limits": { 17 | "CPU": 10, 18 | "Memory": 128 19 | }, 20 | "CreatedAt": "2020-10-02T00:15:07.620912337Z", 21 | "StartedAt": "2020-10-02T00:15:08.062559351Z", 22 | "Type": "NORMAL", 23 | "LogDriver": "awslogs", 24 | "LogOptions": { 25 | "awslogs-create-group": "true", 26 | "awslogs-group": "/ecs/metadata", 27 | "awslogs-region": "us-west-2", 28 | "awslogs-stream": "ecs/curl/8f03e41243824aea923aca126495f665" 29 | }, 30 | "ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9", 31 | "Networks": [ 32 | { 33 | "NetworkMode": "awsvpc", 34 | "IPv4Addresses": [ 35 | "10.0.2.100" 36 | ], 37 | "AttachmentIndex": 0, 38 | "MACAddress": "0e:9e:32:c7:48:85", 39 | "IPv4SubnetCIDRBlock": "10.0.2.0/24", 40 | "PrivateDNSName": "ip-10-0-2-100.us-west-2.compute.internal", 41 | "SubnetGatewayIpv4Address": "10.0.2.1/24" 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /examples/springdemo-native-int/code/src/test/resources/task_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "Cluster": "arn:aws:ecs:us-west-2:111122223333:cluster/default", 3 | "TaskARN": "arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3", 4 | "Family": "curltest", 5 | "Revision": "3", 6 | "DesiredStatus": "RUNNING", 7 | "KnownStatus": "RUNNING", 8 | "Limits": { 9 | "CPU": 0.25, 10 | "Memory": 512 11 | }, 12 | "PullStartedAt": "2020-10-08T20:47:16.053330955Z", 13 | "PullStoppedAt": "2020-10-08T20:47:19.592684631Z", 14 | "AvailabilityZone": "us-west-2a", 15 | "Containers": [ 16 | { 17 | "DockerId": "e9028f8d5d8e4f258373e7b93ce9a3c3-2495160603", 18 | "Name": "curl", 19 | "DockerName": "curl", 20 | "Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest", 21 | "ImageID": "sha256:25f3695bedfb454a50f12d127839a68ad3caf91e451c1da073db34c542c4d2cb", 22 | "Labels": { 23 | "com.amazonaws.ecs.cluster": "arn:aws:ecs:us-west-2:111122223333:cluster/default", 24 | "com.amazonaws.ecs.container-name": "curl", 25 | "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3", 26 | "com.amazonaws.ecs.task-definition-family": "curltest", 27 | "com.amazonaws.ecs.task-definition-version": "3" 28 | }, 29 | "DesiredStatus": "RUNNING", 30 | "KnownStatus": "RUNNING", 31 | "Limits": { 32 | "CPU": 10, 33 | "Memory": 128 34 | }, 35 | "CreatedAt": "2020-10-08T20:47:20.567813946Z", 36 | "StartedAt": "2020-10-08T20:47:20.567813946Z", 37 | "Type": "NORMAL", 38 | "Networks": [ 39 | { 40 | "NetworkMode": "awsvpc", 41 | "IPv4Addresses": [ 42 | "192.0.2.3" 43 | ], 44 | "IPv6Addresses": [ 45 | "2001:dB8:10b:1a00:32bf:a372:d80f:e958" 46 | ], 47 | "AttachmentIndex": 0, 48 | "MACAddress": "02:b7:20:19:72:39", 49 | "IPv4SubnetCIDRBlock": "192.0.2.0/24", 50 | "IPv6SubnetCIDRBlock": "2600:1f13:10b:1a00::/64", 51 | "DomainNameServers": [ 52 | "192.0.2.2" 53 | ], 54 | "DomainNameSearchList": [ 55 | "us-west-2.compute.internal" 56 | ], 57 | "PrivateDNSName": "ip-172-31-30-173.us-west-2.compute.internal", 58 | "SubnetGatewayIpv4Address": "192.0.2.0/24" 59 | } 60 | ], 61 | "ClockDrift": { 62 | "ClockErrorBound": 0.5458234999999999, 63 | "ReferenceTimestamp": "2021-09-07T16:57:44Z", 64 | "ClockSynchronizationStatus": "SYNCHRONIZED" 65 | }, 66 | "ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/1bdcca8b-f905-4ee6-885c-4064cb70f6e6", 67 | "LogOptions": { 68 | "awslogs-create-group": "true", 69 | "awslogs-group": "/ecs/containerlogs", 70 | "awslogs-region": "us-west-2", 71 | "awslogs-stream": "ecs/curl/e9028f8d5d8e4f258373e7b93ce9a3c3" 72 | }, 73 | "LogDriver": "awslogs" 74 | } 75 | ], 76 | "LaunchType": "FARGATE" 77 | } -------------------------------------------------------------------------------- /examples/springdemo-native-int/scripts/checkpoint.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # create directory if it doesn't exist 4 | mkdir -p /opt/crac-files/ 5 | 6 | # delete old snapshot files 7 | rm -rf /opt/crac-files/* 8 | echo Starting the application... 9 | ( echo 128 > /proc/sys/kernel/ns_last_pid ) 2>/dev/null || while [ $(cat /proc/sys/kernel/ns_last_pid) -lt 128 ]; do :; done; 10 | TABLE_NAME=springdemo-native-int-staging-customer 11 | java -Dspring.context.checkpoint=onRefresh -Dtable.name=${TABLE_NAME} -Dspring.profiles.active=prod -Dmode=${MODE} -Damazon.dynamodb.endpoint=${AMAZON_DYNAMO_DB_ENDPOINT} -Djdk.crac.collect-fd-stacktraces=true -XX:CRaCEngine=warp -XX:CRaCCheckpointTo=/opt/crac-files/ -jar /${SRVC_JAR_FILE_NAME} 12 | 13 | EXIT_CODE=$? 14 | 15 | # Error code 137 is expected, because process if killed 16 | if [ $EXIT_CODE -eq 137 ] 17 | then 18 | # let's check if there are snapshot files 19 | if [ -z "$(ls -A /opt/crac-files/)" ] 20 | then 21 | echo "Directory is empty, exiting with -1" 22 | exit -1 23 | fi 24 | fi 25 | 26 | exit 0 -------------------------------------------------------------------------------- /examples/springdemo-native-int/scripts/run-service-crac-s3.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | echo 'Start time (before checkpoint files download from S3: '$(date +"%T.%3N") 3 | mkdir ${CRAC_CHECKPOINT_PATH} 4 | aws s3 sync s3://${CRAC_CHECKPOINT_S3} ${CRAC_CHECKPOINT_PATH} 5 | 6 | source /opt/scripts/run-service-crac.sh -------------------------------------------------------------------------------- /examples/springdemo-native-int/scripts/run-service-crac.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # run java 3 | echo 'Start time: '$(date +"%T.%3N") 4 | java -XX:CRaCEngine=warp -XX:CRaCRestoreFrom=${CRAC_CHECKPOINT_PATH} -Dtable.name=${TABLE_NAME} -Dmode=${MODE} -Damazon.dynamodb.endpoint=${AMAZON_DYNAMO_DB_ENDPOINT} -Daws.webIdentityTokenFile="${AWS_WEB_IDENTITY_TOKEN_FILE}" -Daws.roleArn="${AWS_ROLE_ARN}" 5 | 6 | # the code below is to keep the container running if the java process failed 7 | echo Executing an infinite loop to keep the container running... 8 | while true; do sleep 1; done -------------------------------------------------------------------------------- /examples/springdemo-native-int/scripts/run-service.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # run java 3 | echo Starting the application... 4 | java -Dspring.profiles.active=prod -Dmode=${MODE} -Dtable.name=${TABLE_NAME} -Damazon.dynamodb.endpoint=${AMAZON_DYNAMO_DB_ENDPOINT} -jar /${SRVC_JAR_FILE_NAME} 5 | -------------------------------------------------------------------------------- /examples/springdemo/code/mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ] ; then 38 | 39 | if [ -f /usr/local/etc/mavenrc ] ; then 40 | . /usr/local/etc/mavenrc 41 | fi 42 | 43 | if [ -f /etc/mavenrc ] ; then 44 | . /etc/mavenrc 45 | fi 46 | 47 | if [ -f "$HOME/.mavenrc" ] ; then 48 | . "$HOME/.mavenrc" 49 | fi 50 | 51 | fi 52 | 53 | # OS specific support. $var _must_ be set to either true or false. 54 | cygwin=false; 55 | darwin=false; 56 | mingw=false 57 | case "`uname`" in 58 | CYGWIN*) cygwin=true ;; 59 | MINGW*) mingw=true;; 60 | Darwin*) darwin=true 61 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 62 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 63 | if [ -z "$JAVA_HOME" ]; then 64 | if [ -x "/usr/libexec/java_home" ]; then 65 | export JAVA_HOME="`/usr/libexec/java_home`" 66 | else 67 | export JAVA_HOME="/Library/Java/Home" 68 | fi 69 | fi 70 | ;; 71 | esac 72 | 73 | if [ -z "$JAVA_HOME" ] ; then 74 | if [ -r /etc/gentoo-release ] ; then 75 | JAVA_HOME=`java-config --jre-home` 76 | fi 77 | fi 78 | 79 | if [ -z "$M2_HOME" ] ; then 80 | ## resolve links - $0 may be a link to maven's home 81 | PRG="$0" 82 | 83 | # need this for relative symlinks 84 | while [ -h "$PRG" ] ; do 85 | ls=`ls -ld "$PRG"` 86 | link=`expr "$ls" : '.*-> \(.*\)$'` 87 | if expr "$link" : '/.*' > /dev/null; then 88 | PRG="$link" 89 | else 90 | PRG="`dirname "$PRG"`/$link" 91 | fi 92 | done 93 | 94 | saveddir=`pwd` 95 | 96 | M2_HOME=`dirname "$PRG"`/.. 97 | 98 | # make it fully qualified 99 | M2_HOME=`cd "$M2_HOME" && pwd` 100 | 101 | cd "$saveddir" 102 | # echo Using m2 at $M2_HOME 103 | fi 104 | 105 | # For Cygwin, ensure paths are in UNIX format before anything is touched 106 | if $cygwin ; then 107 | [ -n "$M2_HOME" ] && 108 | M2_HOME=`cygpath --unix "$M2_HOME"` 109 | [ -n "$JAVA_HOME" ] && 110 | JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 111 | [ -n "$CLASSPATH" ] && 112 | CLASSPATH=`cygpath --path --unix "$CLASSPATH"` 113 | fi 114 | 115 | # For Mingw, ensure paths are in UNIX format before anything is touched 116 | if $mingw ; then 117 | [ -n "$M2_HOME" ] && 118 | M2_HOME="`(cd "$M2_HOME"; pwd)`" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" 121 | fi 122 | 123 | if [ -z "$JAVA_HOME" ]; then 124 | javaExecutable="`which javac`" 125 | if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then 126 | # readlink(1) is not available as standard on Solaris 10. 127 | readLink=`which readlink` 128 | if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then 129 | if $darwin ; then 130 | javaHome="`dirname \"$javaExecutable\"`" 131 | javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" 132 | else 133 | javaExecutable="`readlink -f \"$javaExecutable\"`" 134 | fi 135 | javaHome="`dirname \"$javaExecutable\"`" 136 | javaHome=`expr "$javaHome" : '\(.*\)/bin'` 137 | JAVA_HOME="$javaHome" 138 | export JAVA_HOME 139 | fi 140 | fi 141 | fi 142 | 143 | if [ -z "$JAVACMD" ] ; then 144 | if [ -n "$JAVA_HOME" ] ; then 145 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 146 | # IBM's JDK on AIX uses strange locations for the executables 147 | JAVACMD="$JAVA_HOME/jre/sh/java" 148 | else 149 | JAVACMD="$JAVA_HOME/bin/java" 150 | fi 151 | else 152 | JAVACMD="`\\unset -f command; \\command -v java`" 153 | fi 154 | fi 155 | 156 | if [ ! -x "$JAVACMD" ] ; then 157 | echo "Error: JAVA_HOME is not defined correctly." >&2 158 | echo " We cannot execute $JAVACMD" >&2 159 | exit 1 160 | fi 161 | 162 | if [ -z "$JAVA_HOME" ] ; then 163 | echo "Warning: JAVA_HOME environment variable is not set." 164 | fi 165 | 166 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 167 | 168 | # traverses directory structure from process work directory to filesystem root 169 | # first directory with .mvn subdirectory is considered project base directory 170 | find_maven_basedir() { 171 | 172 | if [ -z "$1" ] 173 | then 174 | echo "Path not specified to find_maven_basedir" 175 | return 1 176 | fi 177 | 178 | basedir="$1" 179 | wdir="$1" 180 | while [ "$wdir" != '/' ] ; do 181 | if [ -d "$wdir"/.mvn ] ; then 182 | basedir=$wdir 183 | break 184 | fi 185 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 186 | if [ -d "${wdir}" ]; then 187 | wdir=`cd "$wdir/.."; pwd` 188 | fi 189 | # end of workaround 190 | done 191 | echo "${basedir}" 192 | } 193 | 194 | # concatenates all lines of a file 195 | concat_lines() { 196 | if [ -f "$1" ]; then 197 | echo "$(tr -s '\n' ' ' < "$1")" 198 | fi 199 | } 200 | 201 | BASE_DIR=`find_maven_basedir "$(pwd)"` 202 | if [ -z "$BASE_DIR" ]; then 203 | exit 1; 204 | fi 205 | 206 | ########################################################################################## 207 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 208 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 209 | ########################################################################################## 210 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 211 | if [ "$MVNW_VERBOSE" = true ]; then 212 | echo "Found .mvn/wrapper/maven-wrapper.jar" 213 | fi 214 | else 215 | if [ "$MVNW_VERBOSE" = true ]; then 216 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 217 | fi 218 | if [ -n "$MVNW_REPOURL" ]; then 219 | jarUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 220 | else 221 | jarUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 222 | fi 223 | while IFS="=" read key value; do 224 | case "$key" in (wrapperUrl) jarUrl="$value"; break ;; 225 | esac 226 | done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 227 | if [ "$MVNW_VERBOSE" = true ]; then 228 | echo "Downloading from: $jarUrl" 229 | fi 230 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 231 | if $cygwin; then 232 | wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` 233 | fi 234 | 235 | if command -v wget > /dev/null; then 236 | if [ "$MVNW_VERBOSE" = true ]; then 237 | echo "Found wget ... using wget" 238 | fi 239 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 240 | wget "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 241 | else 242 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" || rm -f "$wrapperJarPath" 243 | fi 244 | elif command -v curl > /dev/null; then 245 | if [ "$MVNW_VERBOSE" = true ]; then 246 | echo "Found curl ... using curl" 247 | fi 248 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 249 | curl -o "$wrapperJarPath" "$jarUrl" -f 250 | else 251 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 252 | fi 253 | 254 | else 255 | if [ "$MVNW_VERBOSE" = true ]; then 256 | echo "Falling back to using Java to download" 257 | fi 258 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 259 | # For Cygwin, switch paths to Windows format before running javac 260 | if $cygwin; then 261 | javaClass=`cygpath --path --windows "$javaClass"` 262 | fi 263 | if [ -e "$javaClass" ]; then 264 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 265 | if [ "$MVNW_VERBOSE" = true ]; then 266 | echo " - Compiling MavenWrapperDownloader.java ..." 267 | fi 268 | # Compiling the Java class 269 | ("$JAVA_HOME/bin/javac" "$javaClass") 270 | fi 271 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 272 | # Running the downloader 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Running MavenWrapperDownloader.java ..." 275 | fi 276 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 277 | fi 278 | fi 279 | fi 280 | fi 281 | ########################################################################################## 282 | # End of extension 283 | ########################################################################################## 284 | 285 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 286 | if [ "$MVNW_VERBOSE" = true ]; then 287 | echo $MAVEN_PROJECTBASEDIR 288 | fi 289 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 290 | 291 | # For Cygwin, switch paths to Windows format before running java 292 | if $cygwin; then 293 | [ -n "$M2_HOME" ] && 294 | M2_HOME=`cygpath --path --windows "$M2_HOME"` 295 | [ -n "$JAVA_HOME" ] && 296 | JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` 297 | [ -n "$CLASSPATH" ] && 298 | CLASSPATH=`cygpath --path --windows "$CLASSPATH"` 299 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 300 | MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` 301 | fi 302 | 303 | # Provide a "standardized" way to retrieve the CLI args that will 304 | # work with both Windows and non-Windows executions. 305 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 306 | export MAVEN_CMD_LINE_ARGS 307 | 308 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 309 | 310 | exec "$JAVACMD" \ 311 | $MAVEN_OPTS \ 312 | $MAVEN_DEBUG_OPTS \ 313 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 314 | "-Dmaven.home=${M2_HOME}" \ 315 | "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 316 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 317 | -------------------------------------------------------------------------------- /examples/springdemo/code/mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* 50 | if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 124 | 125 | FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.0/maven-wrapper-3.1.0.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% ^ 162 | %JVM_CONFIG_MAVEN_PROPS% ^ 163 | %MAVEN_OPTS% ^ 164 | %MAVEN_DEBUG_OPTS% ^ 165 | -classpath %WRAPPER_JAR% ^ 166 | "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ 167 | %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 168 | if ERRORLEVEL 1 goto error 169 | goto end 170 | 171 | :error 172 | set ERROR_CODE=1 173 | 174 | :end 175 | @endlocal & set ERROR_CODE=%ERROR_CODE% 176 | 177 | if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost 178 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 179 | if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" 180 | if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" 181 | :skipRcPost 182 | 183 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 184 | if "%MAVEN_BATCH_PAUSE%"=="on" pause 185 | 186 | if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% 187 | 188 | cmd /C exit /B %ERROR_CODE% 189 | -------------------------------------------------------------------------------- /examples/springdemo/code/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 3.4.1 9 | 10 | 11 | com.amazon 12 | CustomerService 13 | 0.0.1 14 | CustomerService 15 | Demo application to demonstrate steps for reducing startup time for Spring Boot app using CRaC 16 | 17 | 23 18 | 2.20.68 19 | 20 | 21 | 22 | software.amazon.awssdk 23 | dynamodb 24 | ${aws.sdk.version} 25 | 26 | 27 | commons-logging 28 | commons-logging 29 | 30 | 31 | 32 | 33 | software.amazon.awssdk 34 | ecs 35 | ${aws.sdk.version} 36 | 37 | 38 | software.amazon.awssdk 39 | sts 40 | ${aws.sdk.version} 41 | 42 | 43 | software.amazon.awssdk 44 | dynamodb-enhanced 45 | ${aws.sdk.version} 46 | 47 | 48 | org.springframework.boot 49 | spring-boot-starter-data-rest 50 | 51 | 52 | org.springframework.boot 53 | spring-boot-starter-web 54 | 55 | 56 | commons-logging 57 | commons-logging 58 | 59 | 60 | 61 | 62 | org.springframework.boot 63 | spring-boot-starter-aop 64 | 65 | 66 | org.springframework.boot 67 | spring-boot-starter-actuator 68 | 69 | 70 | 71 | org.apache.commons 72 | commons-lang3 73 | 3.12.0 74 | 75 | 76 | com.fasterxml.jackson.datatype 77 | jackson-datatype-jsr310 78 | 2.13.2 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-starter-test 83 | test 84 | 85 | 86 | org.projectlombok 87 | lombok 88 | 1.18.36 89 | 90 | 91 | junit 92 | junit 93 | test 94 | 95 | 96 | org.crac 97 | crac 98 | 1.4.0 99 | 100 | 101 | io.kubernetes 102 | client-java 103 | 15.0.1 104 | 105 | 106 | io.kubernetes 107 | client-java-api 108 | 13.0.0 109 | 110 | 111 | 112 | 113 | 114 | 115 | org.apache.maven.plugins 116 | maven-compiler-plugin 117 | 118 | 119 | -proc:full 120 | 121 | 122 | 123 | 124 | org.springframework.boot 125 | spring-boot-maven-plugin 126 | 127 | 128 | 129 | 130 | src/main/resources 131 | true 132 | 133 | **/*.properties 134 | 135 | 136 | 137 | 138 | 139 | 140 | local 141 | 142 | local 143 | 144 | 145 | 146 | prod 147 | 148 | prod 149 | 150 | 151 | true 152 | 153 | 154 | 155 | 156 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/CustomerServiceApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService; 17 | 18 | import java.time.Instant; 19 | 20 | import org.springframework.boot.SpringApplication; 21 | import org.springframework.boot.autoconfigure.SpringBootApplication; 22 | 23 | @SpringBootApplication 24 | public class CustomerServiceApplication { 25 | 26 | public static void main(String[] args) { 27 | SpringApplication.run(CustomerServiceApplication.class, args); 28 | } 29 | 30 | 31 | } 32 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/config/AppConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.config; 17 | 18 | import org.springframework.beans.factory.annotation.Value; 19 | import org.springframework.context.annotation.Configuration; 20 | 21 | @Configuration 22 | public class AppConfig { 23 | 24 | public final static Integer APPLICATION_VERSION = 2; 25 | 26 | @Value("${amazon.dynamodb.endpoint}") 27 | private String amazonDynamoDBEndpoint; 28 | 29 | } 30 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/controller/CustomerController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.controller; 17 | 18 | import com.amazon.customerService.exception.CustomerNotFoundException; 19 | import com.amazon.customerService.model.Customer; 20 | import com.amazon.customerService.service.CustomerService; 21 | import lombok.extern.slf4j.Slf4j; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.web.bind.annotation.*; 24 | 25 | import java.util.List; 26 | 27 | @Slf4j 28 | @RestController 29 | @RequestMapping("/api") 30 | public class CustomerController { 31 | 32 | @Autowired 33 | CustomerService customerService; 34 | 35 | @GetMapping("/customers") 36 | List getCustomers() { 37 | return customerService.findAll(); 38 | } 39 | 40 | @GetMapping("/customers/load") 41 | List loadCustomers() { 42 | customerService.loadCustomerData(100); 43 | return customerService.findAll(); 44 | } 45 | 46 | @PostMapping("/customers") 47 | Customer createCustomer(@RequestBody Customer customer) { 48 | return customerService.create(customer); 49 | } 50 | 51 | @GetMapping("/customers/{id}") 52 | Customer getCustomerbyId(@PathVariable String id) { 53 | return customerService.findById(id); 54 | } 55 | 56 | @PutMapping("/customers/{id}") 57 | Customer replaceCustomer(@RequestBody Customer newCustomer, @PathVariable String id) { 58 | Customer customer = customerService.findById(id); 59 | 60 | if (null == customer) { 61 | throw new CustomerNotFoundException(newCustomer.getId()); 62 | } 63 | 64 | customer.setId(newCustomer.getId()); 65 | customer.setRegDate(newCustomer.getRegDate()); 66 | customer.setEmail(newCustomer.getEmail()); 67 | customer.setAccountNumber(newCustomer.getAccountNumber()); 68 | customer.setName(newCustomer.getName()); 69 | 70 | customerService.update(customer); 71 | 72 | return customer; 73 | } 74 | 75 | @DeleteMapping("/customers/{id}") 76 | void deleteCustomerById(@PathVariable String id) { 77 | customerService.deleteById(id); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/exception/CustomerNotFoundException.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.exception; 17 | 18 | public class CustomerNotFoundException extends RuntimeException { 19 | 20 | public CustomerNotFoundException(String id) { 21 | super("Could not find customer " + id); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/model/Customer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.model; 17 | 18 | import com.fasterxml.jackson.annotation.JsonInclude; 19 | import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbAttribute; 20 | import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean; 21 | import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey; 22 | 23 | import java.util.Date; 24 | import java.util.Objects; 25 | 26 | @DynamoDbBean 27 | @JsonInclude(JsonInclude.Include.NON_NULL) 28 | 29 | public class Customer { 30 | 31 | private String id, name, email, accountNumber; 32 | private Date regDate; 33 | 34 | @DynamoDbPartitionKey 35 | @DynamoDbAttribute(value = "Id") 36 | public String getId() { 37 | return id; 38 | } 39 | 40 | public void setId(String id) { 41 | this.id = id; 42 | } 43 | 44 | @DynamoDbAttribute(value = "Name") 45 | public String getName() { 46 | return name; 47 | } 48 | 49 | public void setName(String name) { 50 | this.name = name; 51 | } 52 | 53 | @DynamoDbAttribute(value = "Email") 54 | public String getEmail() { 55 | return email; 56 | } 57 | 58 | public void setEmail(String email) { 59 | this.email = email; 60 | } 61 | 62 | @DynamoDbAttribute(value = "AccountNumber") 63 | public String getAccountNumber() { 64 | return accountNumber; 65 | } 66 | 67 | public void setAccountNumber(String accountNumber) { 68 | this.accountNumber = accountNumber; 69 | } 70 | 71 | @DynamoDbAttribute(value = "RegistrationDate") 72 | public Date getRegDate() { 73 | return regDate; 74 | } 75 | 76 | public void setRegDate(Date regDate) { 77 | this.regDate = regDate; 78 | } 79 | 80 | @Override 81 | public boolean equals(Object o) { 82 | if (this == o) return true; 83 | if (o == null || getClass() != o.getClass()) return false; 84 | Customer customer = (Customer) o; 85 | return id.equals(customer.id); 86 | } 87 | 88 | @Override 89 | public int hashCode() { 90 | return Objects.hash(id); 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return "Customer{" + 96 | "id='" + id + '\'' + 97 | ", name='" + name + '\'' + 98 | ", email='" + email + '\'' + 99 | ", accountNumber='" + accountNumber + '\'' + 100 | ", regDate=" + regDate + 101 | '}'; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/model/metrics/ContainerMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.model.metrics; 17 | 18 | import java.time.Duration; 19 | import java.time.Instant; 20 | import java.util.Objects; 21 | 22 | public class ContainerMetric { 23 | private Instant createdAt; 24 | private Instant startedAt; 25 | 26 | public ContainerMetric() { 27 | } 28 | 29 | public ContainerMetric(Instant createdAt, Instant startedAt) { 30 | this.createdAt = createdAt; 31 | this.startedAt = startedAt; 32 | } 33 | 34 | public Duration calculateDuration() { 35 | if (startedAt == null || createdAt == null) 36 | return null; 37 | 38 | Duration duration = Duration.between(createdAt, startedAt); 39 | 40 | return duration; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "ContainerMetric{" + 46 | "createdAt=" + createdAt + 47 | ", startedAt=" + startedAt + 48 | '}'; 49 | } 50 | 51 | @Override 52 | public boolean equals(Object o) { 53 | if (this == o) return true; 54 | if (o == null || getClass() != o.getClass()) return false; 55 | ContainerMetric that = (ContainerMetric) o; 56 | return createdAt.equals(that.createdAt) && startedAt.equals(that.startedAt); 57 | } 58 | 59 | @Override 60 | public int hashCode() { 61 | return Objects.hash(createdAt, startedAt); 62 | } 63 | 64 | public Instant getCreatedAt() { 65 | return createdAt; 66 | } 67 | 68 | public void setCreatedAt(Instant createdAt) { 69 | this.createdAt = createdAt; 70 | } 71 | 72 | public Instant getStartedAt() { 73 | return startedAt; 74 | } 75 | 76 | public void setStartedAt(Instant startedAt) { 77 | this.startedAt = startedAt; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/model/metrics/MetricWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.model.metrics; 17 | 18 | import java.time.Duration; 19 | import java.time.Instant; 20 | 21 | public class MetricWrapper { 22 | 23 | private ContainerMetric containerMetric; 24 | private TaskMetric taskMetric; 25 | private PodMetric podMetric; 26 | private Duration springBootStartDuration; 27 | private Instant springBootReadyTime; 28 | private Integer version; 29 | 30 | public MetricWrapper() { 31 | } 32 | 33 | public MetricWrapper(ContainerMetric containerMetric, TaskMetric taskMetric, PodMetric podMetric, Duration springBootStartTime, Instant springBootReadyTime, Integer version) { 34 | this.containerMetric = containerMetric; 35 | this.taskMetric = taskMetric; 36 | this.springBootStartDuration = springBootStartTime; 37 | this.springBootReadyTime = springBootReadyTime; 38 | this.version = version; 39 | this.podMetric = podMetric; 40 | } 41 | 42 | public Integer getVersion() { 43 | return version; 44 | } 45 | 46 | public void setVersion(Integer version) { 47 | this.version = version; 48 | } 49 | 50 | public ContainerMetric getContainerMetric() { 51 | return containerMetric; 52 | } 53 | 54 | public void setContainerMetric(ContainerMetric containerMetric) { 55 | this.containerMetric = containerMetric; 56 | } 57 | 58 | public TaskMetric getTaskMetric() { 59 | return taskMetric; 60 | } 61 | 62 | public void setTaskMetric(TaskMetric taskMetric) { 63 | this.taskMetric = taskMetric; 64 | } 65 | 66 | public Instant getSpringBootReadyTime() { 67 | return springBootReadyTime; 68 | } 69 | 70 | public void setSpringBootReadyTime(Instant springBootReadyTime) { 71 | this.springBootReadyTime = springBootReadyTime; 72 | } 73 | 74 | public Duration getSpringBootStartDuration() { 75 | return springBootStartDuration; 76 | } 77 | 78 | public void setSpringBootStartDuration(Duration springBootStartDuration) { 79 | this.springBootStartDuration = springBootStartDuration; 80 | } 81 | 82 | public PodMetric getPodMetric() { 83 | return podMetric; 84 | } 85 | 86 | public void setPodMetric(PodMetric podMetric) { 87 | this.podMetric = podMetric; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/model/metrics/PodMetric.java: -------------------------------------------------------------------------------- 1 | package com.amazon.customerService.model.metrics; 2 | 3 | import java.time.Instant; 4 | import java.util.Objects; 5 | 6 | public class PodMetric { 7 | 8 | private Instant podScheduled; 9 | private Instant podReady; 10 | private String podId; 11 | 12 | public PodMetric() { 13 | 14 | } 15 | 16 | public PodMetric(Instant podScheduled, Instant podReady, String podId) { 17 | this.podScheduled = podScheduled; 18 | this.podReady = podReady; 19 | this.podId = podId; 20 | } 21 | 22 | @Override 23 | public String toString() { 24 | return "PodMetric{" + 25 | "podScheduled=" + podScheduled + 26 | ", podReady=" + podReady + 27 | ", podId='" + podId + '\'' + 28 | '}'; 29 | } 30 | 31 | @Override 32 | public boolean equals(Object o) { 33 | if (this == o) return true; 34 | if (o == null || getClass() != o.getClass()) return false; 35 | PodMetric podMetric = (PodMetric) o; 36 | return Objects.equals(podId, podMetric.podId); 37 | } 38 | 39 | @Override 40 | public int hashCode() { 41 | return Objects.hash(podId); 42 | } 43 | 44 | public Instant getPodScheduled() { 45 | return podScheduled; 46 | } 47 | 48 | public void setPodScheduled(Instant podScheduled) { 49 | this.podScheduled = podScheduled; 50 | } 51 | 52 | public Instant getPodReady() { 53 | return podReady; 54 | } 55 | 56 | public void setPodReady(Instant podReady) { 57 | this.podReady = podReady; 58 | } 59 | 60 | public String getPodId() { 61 | return podId; 62 | } 63 | 64 | public void setPodId(String podId) { 65 | this.podId = podId; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/model/metrics/TaskMetric.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.model.metrics; 17 | 18 | import java.time.Duration; 19 | import java.time.Instant; 20 | import java.util.Objects; 21 | 22 | public class TaskMetric { 23 | private Instant pullStartedAt; 24 | private Instant pullStoppedAt; 25 | private String taskArn; 26 | 27 | public TaskMetric() { 28 | } 29 | 30 | public TaskMetric(Instant pullStartedAt, Instant pullStoppedAt, String taskArn) { 31 | this.pullStartedAt = pullStartedAt; 32 | this.pullStoppedAt = pullStoppedAt; 33 | this.taskArn = taskArn; 34 | } 35 | 36 | public Instant getPullStartedAt() { 37 | return pullStartedAt; 38 | } 39 | 40 | public void setPullStartedAt(Instant pullStartedAt) { 41 | this.pullStartedAt = pullStartedAt; 42 | } 43 | 44 | public Instant getPullStoppedAt() { 45 | return pullStoppedAt; 46 | } 47 | 48 | public void setPullStoppedAt(Instant pullStoppedAt) { 49 | this.pullStoppedAt = pullStoppedAt; 50 | } 51 | 52 | public Duration calculateDuration() { 53 | if (pullStartedAt == null || pullStoppedAt == null) 54 | return null; 55 | 56 | Duration duration = Duration.between(pullStartedAt, pullStoppedAt); 57 | 58 | return duration; 59 | } 60 | 61 | public String getTaskArn() { 62 | return taskArn; 63 | } 64 | 65 | public void setTaskArn(String taskArn) { 66 | this.taskArn = taskArn; 67 | } 68 | 69 | @Override 70 | public boolean equals(Object o) { 71 | if (this == o) return true; 72 | if (o == null || getClass() != o.getClass()) return false; 73 | TaskMetric that = (TaskMetric) o; 74 | return taskArn.equals(that.taskArn); 75 | } 76 | 77 | @Override 78 | public int hashCode() { 79 | return Objects.hash(taskArn); 80 | } 81 | 82 | @Override 83 | public String toString() { 84 | return "TaskMetric{" + 85 | "pullStartedAt=" + pullStartedAt + 86 | ", pullStoppedAt=" + pullStoppedAt + 87 | ", taskArn='" + taskArn + '\'' + 88 | '}'; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/repository/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.repository; 17 | 18 | import java.text.ParseException; 19 | import java.text.SimpleDateFormat; 20 | import java.util.ArrayList; 21 | import java.util.Date; 22 | import java.util.HashMap; 23 | import java.util.List; 24 | import java.util.Map; 25 | import java.util.UUID; 26 | 27 | import javax.annotation.PostConstruct; 28 | 29 | import org.crac.Context; 30 | import org.crac.Core; 31 | import org.crac.Resource; 32 | import org.springframework.beans.factory.annotation.Autowired; 33 | import org.springframework.core.env.Environment; 34 | import org.springframework.stereotype.Repository; 35 | 36 | import com.amazon.customerService.model.Customer; 37 | 38 | import lombok.extern.slf4j.Slf4j; 39 | import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; 40 | import software.amazon.awssdk.auth.credentials.WebIdentityTokenFileCredentialsProvider; 41 | import software.amazon.awssdk.services.dynamodb.DynamoDbClient; 42 | import software.amazon.awssdk.services.dynamodb.model.AttributeValue; 43 | import software.amazon.awssdk.services.dynamodb.model.DeleteItemRequest; 44 | import software.amazon.awssdk.services.dynamodb.model.GetItemRequest; 45 | import software.amazon.awssdk.services.dynamodb.model.GetItemResponse; 46 | import software.amazon.awssdk.services.dynamodb.model.PutItemRequest; 47 | import software.amazon.awssdk.services.dynamodb.model.ScanRequest; 48 | 49 | @Slf4j 50 | @Repository 51 | public class CustomerRepository implements Resource { 52 | 53 | public static final String ID_COLUMN = "Id"; 54 | public static final String NAME_COLUMN = "Name"; 55 | public static final String EMAIL_COLUMN = "Email"; 56 | public static final String ACCOUNT_NUMBER_COLUMN = "AccountNumber"; 57 | public static final String REGISTRATION_DATE_COLUMN = "RegistrationDate"; 58 | private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX"); 59 | 60 | private DynamoDbClient client; 61 | private String tableName; 62 | private String mode; 63 | 64 | @Autowired 65 | private Environment environment; 66 | 67 | @PostConstruct 68 | public void init() { 69 | loadConfig(); 70 | this.client = createDynamoDbClient(); 71 | Core.getGlobalContext().register(this); 72 | } 73 | 74 | @Override 75 | public void beforeCheckpoint(Context context) { 76 | log.info("Executing beforeCheckpoint..."); 77 | this.client.close(); 78 | } 79 | 80 | @Override 81 | public void afterRestore(Context context) { 82 | log.info("Executing afterRestore ..."); 83 | loadConfig(); 84 | this.client = createDynamoDbClient(); 85 | } 86 | 87 | public Customer save(final Customer customer) { 88 | 89 | customer.setId(UUID.randomUUID().toString()); 90 | 91 | if (customer.getRegDate() == null) { 92 | customer.setRegDate(new Date()); 93 | } 94 | 95 | PutItemRequest putItemRequest = PutItemRequest.builder() 96 | .tableName(this.tableName) 97 | .item(convertPojoToMap(customer)) 98 | .build(); 99 | 100 | client.putItem(putItemRequest); 101 | 102 | return customer; 103 | } 104 | 105 | public Customer findById(final String id) { 106 | 107 | log.debug("Find customer with id: " + id); 108 | 109 | Map key = new HashMap<>(); 110 | key.put(ID_COLUMN, AttributeValue.builder().s(id).build()); 111 | 112 | GetItemRequest getItemRequest = GetItemRequest.builder() 113 | .tableName(this.tableName) 114 | .key(key) 115 | .build(); 116 | 117 | GetItemResponse item = client.getItem(getItemRequest); 118 | Customer customer = null; 119 | if (item.hasItem()) { 120 | Map itemAttr = item.item(); 121 | customer = convertMapToPojo(itemAttr); 122 | } 123 | 124 | return customer; 125 | } 126 | 127 | public List findAll() { 128 | 129 | log.debug("Find all customers"); 130 | List customerList = new ArrayList<>(); 131 | 132 | ScanRequest scanRequest = ScanRequest.builder(). 133 | tableName(this.tableName). 134 | build(); 135 | 136 | List> list = client.scan(scanRequest).items(); 137 | 138 | for (Map item : list) { 139 | Customer customer = convertMapToPojo(item); 140 | customerList.add(customer); 141 | } 142 | 143 | log.debug("Found customers: "); 144 | for (Customer customer : customerList 145 | ) { 146 | log.debug(" -> " + customer); 147 | } 148 | 149 | return customerList; 150 | } 151 | 152 | public void deleteById(String id) { 153 | 154 | log.debug("Delete customer with id: " + id); 155 | 156 | Map key = new HashMap<>(); 157 | key.put(ID_COLUMN, AttributeValue.builder().s(id).build()); 158 | 159 | DeleteItemRequest deleteItemRequest = DeleteItemRequest.builder() 160 | .tableName(this.tableName) 161 | .key(key) 162 | .build(); 163 | 164 | client.deleteItem(deleteItemRequest); 165 | } 166 | 167 | private Map convertPojoToMap(final Customer customer) { 168 | Map item = new HashMap<>(); 169 | 170 | item.put(ID_COLUMN, AttributeValue.builder().s(customer.getId()).build()); 171 | item.put(NAME_COLUMN, AttributeValue.builder().s(customer.getName()).build()); 172 | item.put(EMAIL_COLUMN, AttributeValue.builder().s(customer.getEmail()).build()); 173 | item.put(ACCOUNT_NUMBER_COLUMN, AttributeValue.builder().s(customer.getAccountNumber()).build()); 174 | item.put(REGISTRATION_DATE_COLUMN, AttributeValue.builder().s(sdf.format(customer.getRegDate())).build()); 175 | 176 | return item; 177 | } 178 | 179 | private Customer convertMapToPojo(final Map item) { 180 | Customer customer = new Customer(); 181 | 182 | customer.setAccountNumber(item.get(ACCOUNT_NUMBER_COLUMN).s()); 183 | customer.setEmail(item.get(EMAIL_COLUMN).s()); 184 | customer.setAccountNumber(item.get(ACCOUNT_NUMBER_COLUMN).s()); 185 | customer.setId(item.get(ID_COLUMN).s()); 186 | 187 | Date registrationDate = null; 188 | 189 | try { 190 | registrationDate = sdf.parse(item.get(REGISTRATION_DATE_COLUMN).s()); 191 | } catch (ParseException exc) { 192 | log.error(exc.toString()); 193 | } 194 | 195 | customer.setRegDate(registrationDate); 196 | 197 | return customer; 198 | } 199 | 200 | private DynamoDbClient createDynamoDbClient() { 201 | log.info("Mode (through Environment Abstraction):" + this.mode); 202 | if ("ci".equals(this.mode)) { 203 | return DynamoDbClient.builder() 204 | .credentialsProvider(EnvironmentVariableCredentialsProvider.create()) 205 | .build(); 206 | } 207 | 208 | return DynamoDbClient.builder() 209 | .credentialsProvider(WebIdentityTokenFileCredentialsProvider.create()) 210 | .build(); 211 | } 212 | 213 | private void loadConfig() { 214 | this.mode = environment.getProperty("mode"); 215 | this.tableName = environment.getProperty("table.name"); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/service/CustomerService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.service; 17 | 18 | import com.amazon.customerService.model.Customer; 19 | import com.amazon.customerService.repository.CustomerRepository; 20 | import org.apache.commons.lang3.RandomStringUtils; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.stereotype.Service; 23 | 24 | import java.sql.Date; 25 | import java.time.Instant; 26 | import java.util.List; 27 | import java.util.Random; 28 | import java.util.UUID; 29 | 30 | @Service 31 | public class CustomerService { 32 | 33 | @Autowired 34 | CustomerRepository customerRepository; 35 | 36 | public List findAll() { 37 | return customerRepository.findAll(); 38 | } 39 | 40 | public Customer findById(String id) { 41 | return customerRepository.findById(id); 42 | } 43 | 44 | public Customer create(Customer customer) { 45 | return customerRepository.save(customer); 46 | } 47 | 48 | public Customer update(Customer customer) { 49 | return customerRepository.save(customer); 50 | } 51 | 52 | public void deleteById(String id) { 53 | customerRepository.deleteById(id); 54 | } 55 | 56 | public void loadCustomerData(int count) { 57 | 58 | for (int i = 0; i < count; i++) { 59 | String generatedString = RandomStringUtils.randomAlphabetic(10); 60 | 61 | Customer cust = new Customer(); 62 | cust.setName(generatedString); 63 | cust.setId(UUID.randomUUID().toString()); 64 | cust.setRegDate(Date.from(Instant.now())); 65 | cust.setEmail(generatedString + "@test.com"); 66 | 67 | Random rnd = new Random(); 68 | int number = rnd.nextInt(999999); 69 | 70 | cust.setAccountNumber(String.format("%06d", number)); 71 | 72 | customerRepository.save(cust); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/service/EcsMetaDataService.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.service; 17 | 18 | import com.amazon.customerService.model.metrics.ContainerMetric; 19 | import com.amazon.customerService.model.metrics.MetricWrapper; 20 | import com.amazon.customerService.model.metrics.TaskMetric; 21 | import com.fasterxml.jackson.core.JsonPointer; 22 | import com.fasterxml.jackson.databind.JsonNode; 23 | import com.fasterxml.jackson.databind.ObjectMapper; 24 | import lombok.extern.slf4j.Slf4j; 25 | import org.springframework.stereotype.Service; 26 | import software.amazon.awssdk.auth.credentials.ContainerCredentialsProvider; 27 | import software.amazon.awssdk.services.ecs.EcsClient; 28 | import software.amazon.awssdk.services.ecs.model.DescribeTasksRequest; 29 | import software.amazon.awssdk.services.ecs.model.DescribeTasksResponse; 30 | import software.amazon.awssdk.services.ecs.model.Task; 31 | 32 | import java.io.IOException; 33 | import java.net.URI; 34 | import java.time.Instant; 35 | import java.util.List; 36 | 37 | @Slf4j 38 | @Service 39 | public class EcsMetaDataService { 40 | 41 | public MetricWrapper getMetaData() { 42 | 43 | MetricWrapper metricWrapper = new MetricWrapper(); 44 | 45 | try { 46 | var metaDataUrl = System.getenv("ECS_CONTAINER_METADATA_URI_V4"); 47 | 48 | if (metaDataUrl == null) { 49 | log.debug("metaDataUrl is null"); 50 | return null; 51 | } 52 | 53 | ObjectMapper objectMapper = new ObjectMapper(); 54 | JsonNode node = objectMapper.readTree(URI.create(metaDataUrl + "/task").toURL()); 55 | 56 | JsonPointer pointer = JsonPointer.compile("/TaskARN"); 57 | String taskArn = node.at(pointer).asText(); 58 | 59 | pointer = JsonPointer.compile("/Cluster"); 60 | String cluster = node.at(pointer).asText(); 61 | 62 | ContainerCredentialsProvider provider = ContainerCredentialsProvider.builder().build(); 63 | EcsClient ecsClient = EcsClient.builder().credentialsProvider(provider).build(); 64 | 65 | DescribeTasksRequest request = DescribeTasksRequest.builder() 66 | .tasks(taskArn).cluster(cluster).build(); 67 | DescribeTasksResponse response = ecsClient.describeTasks(request); 68 | 69 | Instant pullStartedAtInstant = null, pullStoppedAtInstant = null, createdAtInstant = null, startedAtInstant = null; 70 | 71 | if (response.hasTasks()) { 72 | List taskList = response.tasks(); 73 | Task task = taskList.get(0); 74 | 75 | pullStartedAtInstant = task.pullStartedAt(); 76 | pullStoppedAtInstant = task.pullStoppedAt(); 77 | createdAtInstant = task.createdAt(); 78 | startedAtInstant = task.startedAt(); 79 | } 80 | 81 | TaskMetric taskMetric = new TaskMetric(pullStartedAtInstant, pullStoppedAtInstant, taskArn); 82 | ContainerMetric containerMetric = new ContainerMetric(createdAtInstant, startedAtInstant); 83 | 84 | metricWrapper.setTaskMetric(taskMetric); 85 | metricWrapper.setContainerMetric(containerMetric); 86 | } catch (IOException exc) { 87 | log.error("An error occurred: ", exc); 88 | } 89 | 90 | return metricWrapper; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/service/EksMetricsService.java: -------------------------------------------------------------------------------- 1 | package com.amazon.customerService.service; 2 | 3 | import com.amazon.customerService.model.metrics.MetricWrapper; 4 | import com.amazon.customerService.model.metrics.PodMetric; 5 | import io.kubernetes.client.openapi.ApiClient; 6 | import io.kubernetes.client.openapi.ApiException; 7 | import io.kubernetes.client.openapi.Configuration; 8 | import io.kubernetes.client.openapi.apis.CoreV1Api; 9 | import io.kubernetes.client.openapi.models.V1Pod; 10 | import io.kubernetes.client.openapi.models.V1PodCondition; 11 | import io.kubernetes.client.util.ClientBuilder; 12 | import lombok.extern.slf4j.Slf4j; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.io.BufferedReader; 16 | import java.io.FileReader; 17 | import java.io.IOException; 18 | import java.time.OffsetDateTime; 19 | import java.util.Objects; 20 | 21 | @Slf4j 22 | @Service 23 | public class EksMetricsService { 24 | public MetricWrapper getMetaData() { 25 | 26 | MetricWrapper metricWrapper = new MetricWrapper(); 27 | 28 | try { 29 | ApiClient client = ClientBuilder.cluster().build(); 30 | Configuration.setDefaultApiClient(client); 31 | 32 | BufferedReader reader = new BufferedReader(new FileReader("/var/run/secrets/kubernetes.io/serviceaccount/namespace")); 33 | String namespaceName = reader.readLine(); 34 | log.info("Namespace: " + namespaceName); 35 | 36 | reader.close(); 37 | 38 | String podName = System.getenv("HOSTNAME"); 39 | log.info("Pod: " + podName); 40 | 41 | CoreV1Api api = new CoreV1Api(); 42 | V1Pod pod = api.readNamespacedPod(podName, namespaceName, null, null, null); 43 | 44 | OffsetDateTime podScheduled = null, podReady = null; 45 | 46 | for (V1PodCondition condition : Objects.requireNonNull(pod.getStatus()).getConditions()) { 47 | if (condition.getType().equals("PodScheduled")) { 48 | if (condition.getStatus().equals("True")) { 49 | podScheduled = condition.getLastTransitionTime(); 50 | } 51 | } else if (condition.getType().equals("Ready")) { 52 | if (condition.getStatus().equals("True")) { 53 | podReady = condition.getLastTransitionTime(); 54 | } 55 | } 56 | } 57 | 58 | if (podReady != null && podScheduled != null) { 59 | 60 | PodMetric podMetric = new PodMetric(podScheduled.toInstant(), podReady.toInstant(), podName); 61 | metricWrapper.setPodMetric(podMetric); 62 | 63 | return metricWrapper; 64 | 65 | } else 66 | log.info("Something is null"); 67 | } catch (ApiException exc) { 68 | log.error("Couldn't generate k8s client"); 69 | log.error(exc.getResponseBody()); 70 | 71 | return null; 72 | } catch (IOException exc) { 73 | exc.printStackTrace(); 74 | return null; 75 | } catch (NumberFormatException exc) { 76 | exc.printStackTrace(); 77 | return null; 78 | } 79 | 80 | return metricWrapper; 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/java/com/amazon/customerService/utils/TimingUtils.java: -------------------------------------------------------------------------------- 1 | package com.amazon.customerService.utils; 2 | 3 | import java.lang.management.ManagementFactory; 4 | import java.lang.management.RuntimeMXBean; 5 | import java.time.Duration; 6 | import java.time.Instant; 7 | 8 | import org.apache.commons.lang3.StringEscapeUtils; 9 | 10 | import com.amazon.customerService.config.AppConfig; 11 | import com.amazon.customerService.model.metrics.MetricWrapper; 12 | import com.amazon.customerService.service.EcsMetaDataService; 13 | import com.amazon.customerService.service.EksMetricsService; 14 | import com.fasterxml.jackson.core.JsonProcessingException; 15 | import com.fasterxml.jackson.databind.ObjectMapper; 16 | import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; 17 | 18 | import lombok.extern.slf4j.Slf4j; 19 | 20 | @Slf4j 21 | public class TimingUtils { 22 | 23 | public static void measureTime(Instant endTime) { 24 | RuntimeMXBean bean = ManagementFactory.getRuntimeMXBean(); 25 | Instant startTime = Instant.ofEpochMilli(bean.getStartTime()); 26 | Duration springBootStartTime = Duration.between(startTime, endTime); 27 | 28 | EcsMetaDataService ecsMetaDataService = new EcsMetaDataService(); 29 | EksMetricsService eksMetricsService = new EksMetricsService(); 30 | 31 | MetricWrapper metricWrapper = ecsMetaDataService.getMetaData(); 32 | 33 | if (metricWrapper == null) { 34 | metricWrapper = eksMetricsService.getMetaData(); 35 | } 36 | 37 | if (metricWrapper != null) { 38 | metricWrapper.setVersion(AppConfig.APPLICATION_VERSION); 39 | metricWrapper.setSpringBootStartDuration(springBootStartTime); 40 | metricWrapper.setSpringBootReadyTime(endTime); 41 | ObjectMapper mapper = new ObjectMapper() 42 | .registerModule(new JavaTimeModule()); 43 | 44 | try { 45 | String metricsJson = mapper.writeValueAsString(metricWrapper); 46 | log.info("Metrics: " + StringEscapeUtils.unescapeJson(metricsJson)); 47 | } catch (JsonProcessingException e) { 48 | log.error(e.getMessage()); 49 | } 50 | } 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/resources/application-local.properties: -------------------------------------------------------------------------------- 1 | amazon.dynamodb.endpoint=http://localhost:8000/ 2 | logging.level.root=DEBUG -------------------------------------------------------------------------------- /examples/springdemo/code/src/main/resources/application-prod.properties: -------------------------------------------------------------------------------- 1 | logging.level.root=INFO 2 | logging.level.com.amazon.customerService=DEBUG 3 | management.endpoint.health.probes.enabled=true 4 | management.health.readinessState.enabled=true -------------------------------------------------------------------------------- /examples/springdemo/code/src/test/java/com/amazon/customerService/repository/CustomerRepositoryTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2010-2022 Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"). 5 | * You may not use this file except in compliance with the License. 6 | * A copy of the License is located at 7 | * 8 | * http://aws.amazon.com/apache2.0 9 | * 10 | * or in the "license" file accompanying this file. This file is distributed 11 | * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 12 | * express or implied. See the License for the specific language governing 13 | * permissions and limitations under the License. 14 | */ 15 | 16 | package com.amazon.customerService.repository; 17 | 18 | import com.amazon.customerService.model.Customer; 19 | import org.junit.Assert; 20 | import org.junit.jupiter.api.*; 21 | import org.junit.jupiter.api.extension.ExtendWith; 22 | import org.springframework.beans.factory.annotation.Autowired; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | import org.springframework.test.context.ActiveProfiles; 25 | import org.springframework.test.context.TestPropertySource; 26 | import org.springframework.test.context.junit.jupiter.SpringExtension; 27 | import org.springframework.test.context.web.WebAppConfiguration; 28 | import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient; 29 | import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable; 30 | import software.amazon.awssdk.enhanced.dynamodb.TableSchema; 31 | 32 | import java.time.Instant; 33 | import java.util.List; 34 | import java.util.UUID; 35 | 36 | @ExtendWith(SpringExtension.class) 37 | @SpringBootTest 38 | @WebAppConfiguration 39 | @ActiveProfiles("local") 40 | @TestPropertySource(properties = { 41 | "amazon.dynamodb.endpoint=http://localhost:8000/"}) 42 | @TestInstance(TestInstance.Lifecycle.PER_CLASS) 43 | @TestMethodOrder(MethodOrderer.OrderAnnotation.class) 44 | @TestPropertySource(locations = "classpath:application-local.properties") 45 | public class CustomerRepositoryTest { 46 | 47 | @Autowired 48 | CustomerRepository repository; 49 | @Autowired 50 | private DynamoDbEnhancedClient dynamoDbEnhancedClient; 51 | private DynamoDbTable table; 52 | private Customer testCustomer; 53 | 54 | @BeforeAll 55 | public void setup() throws Exception { 56 | 57 | // Create the table locally 58 | 59 | table = dynamoDbEnhancedClient.table("Customer", 60 | TableSchema.fromBean(Customer.class)); 61 | 62 | testCustomer = createCustomer(); 63 | 64 | try { 65 | table.describeTable(); 66 | } catch (software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException exc) { 67 | // Table doesn't exist 68 | table.createTable(); 69 | } 70 | 71 | // Find and delete all customer entries 72 | List customerList = repository.findAll(); 73 | System.out.println("Customerlist: " + customerList); 74 | for (Customer customer : customerList) { 75 | System.out.println("Customer: " + customer); 76 | repository.deleteById(customer.getId()); 77 | } 78 | } 79 | 80 | private Customer createCustomer() { 81 | Customer customer = new Customer(); 82 | customer.setAccountNumber("111111"); 83 | customer.setEmail("test@test.com"); 84 | // customer.setRegDate(Instant.now()); 85 | customer.setName("John Doe"); 86 | 87 | UUID uuid = UUID.randomUUID(); 88 | String uuidAsString = uuid.toString(); 89 | 90 | customer.setId(uuidAsString); 91 | 92 | return customer; 93 | } 94 | 95 | @Test 96 | @Order(1) 97 | public void testCreate() { 98 | System.out.println("Adding customer: " + testCustomer); 99 | 100 | Customer savedCustomer = repository.save(testCustomer); 101 | Customer readCustomer = repository.findById(savedCustomer.getId()); 102 | 103 | Assert.assertEquals(savedCustomer, readCustomer); 104 | } 105 | 106 | @Test 107 | @Order(2) 108 | public void testRead() { 109 | String customerId = testCustomer.getId(); 110 | 111 | Customer tmpCustomer = repository.findById(customerId); 112 | Assert.assertEquals(testCustomer, tmpCustomer); 113 | } 114 | 115 | @Test 116 | @Order(3) 117 | public void testUpdate() { 118 | 119 | testCustomer.setName("NewName"); 120 | repository.save(testCustomer); 121 | 122 | Customer tmpCustomer = repository.findById(testCustomer.getId()); 123 | Assert.assertEquals(testCustomer.getName(), tmpCustomer.getName()); 124 | } 125 | 126 | @Test 127 | @Order(4) 128 | public void testDelete() { 129 | 130 | repository.deleteById(testCustomer.getId()); 131 | 132 | List customerList = repository.findAll(); 133 | Assert.assertEquals(0, customerList.size()); 134 | } 135 | 136 | @AfterAll 137 | public void tearDown() throws Exception { 138 | table.deleteTable(); 139 | } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /examples/springdemo/code/src/test/resources/container_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "DockerId": "ea32192c8553fbff06c9340478a2ff089b2bb5646fb718b4ee206641c9086d66", 3 | "Name": "curl", 4 | "DockerName": "ecs-curltest-24-curl-cca48e8dcadd97805600", 5 | "Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest", 6 | "ImageID": "sha256:d691691e9652791a60114e67b365688d20d19940dde7c4736ea30e660d8d3553", 7 | "Labels": { 8 | "com.amazonaws.ecs.cluster": "default", 9 | "com.amazonaws.ecs.container-name": "curl", 10 | "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/8f03e41243824aea923aca126495f665", 11 | "com.amazonaws.ecs.task-definition-family": "curltest", 12 | "com.amazonaws.ecs.task-definition-version": "24" 13 | }, 14 | "DesiredStatus": "RUNNING", 15 | "KnownStatus": "RUNNING", 16 | "Limits": { 17 | "CPU": 10, 18 | "Memory": 128 19 | }, 20 | "CreatedAt": "2020-10-02T00:15:07.620912337Z", 21 | "StartedAt": "2020-10-02T00:15:08.062559351Z", 22 | "Type": "NORMAL", 23 | "LogDriver": "awslogs", 24 | "LogOptions": { 25 | "awslogs-create-group": "true", 26 | "awslogs-group": "/ecs/metadata", 27 | "awslogs-region": "us-west-2", 28 | "awslogs-stream": "ecs/curl/8f03e41243824aea923aca126495f665" 29 | }, 30 | "ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/0206b271-b33f-47ab-86c6-a0ba208a70a9", 31 | "Networks": [ 32 | { 33 | "NetworkMode": "awsvpc", 34 | "IPv4Addresses": [ 35 | "10.0.2.100" 36 | ], 37 | "AttachmentIndex": 0, 38 | "MACAddress": "0e:9e:32:c7:48:85", 39 | "IPv4SubnetCIDRBlock": "10.0.2.0/24", 40 | "PrivateDNSName": "ip-10-0-2-100.us-west-2.compute.internal", 41 | "SubnetGatewayIpv4Address": "10.0.2.1/24" 42 | } 43 | ] 44 | } -------------------------------------------------------------------------------- /examples/springdemo/code/src/test/resources/task_response.json: -------------------------------------------------------------------------------- 1 | { 2 | "Cluster": "arn:aws:ecs:us-west-2:111122223333:cluster/default", 3 | "TaskARN": "arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3", 4 | "Family": "curltest", 5 | "Revision": "3", 6 | "DesiredStatus": "RUNNING", 7 | "KnownStatus": "RUNNING", 8 | "Limits": { 9 | "CPU": 0.25, 10 | "Memory": 512 11 | }, 12 | "PullStartedAt": "2020-10-08T20:47:16.053330955Z", 13 | "PullStoppedAt": "2020-10-08T20:47:19.592684631Z", 14 | "AvailabilityZone": "us-west-2a", 15 | "Containers": [ 16 | { 17 | "DockerId": "e9028f8d5d8e4f258373e7b93ce9a3c3-2495160603", 18 | "Name": "curl", 19 | "DockerName": "curl", 20 | "Image": "111122223333.dkr.ecr.us-west-2.amazonaws.com/curltest:latest", 21 | "ImageID": "sha256:25f3695bedfb454a50f12d127839a68ad3caf91e451c1da073db34c542c4d2cb", 22 | "Labels": { 23 | "com.amazonaws.ecs.cluster": "arn:aws:ecs:us-west-2:111122223333:cluster/default", 24 | "com.amazonaws.ecs.container-name": "curl", 25 | "com.amazonaws.ecs.task-arn": "arn:aws:ecs:us-west-2:111122223333:task/default/e9028f8d5d8e4f258373e7b93ce9a3c3", 26 | "com.amazonaws.ecs.task-definition-family": "curltest", 27 | "com.amazonaws.ecs.task-definition-version": "3" 28 | }, 29 | "DesiredStatus": "RUNNING", 30 | "KnownStatus": "RUNNING", 31 | "Limits": { 32 | "CPU": 10, 33 | "Memory": 128 34 | }, 35 | "CreatedAt": "2020-10-08T20:47:20.567813946Z", 36 | "StartedAt": "2020-10-08T20:47:20.567813946Z", 37 | "Type": "NORMAL", 38 | "Networks": [ 39 | { 40 | "NetworkMode": "awsvpc", 41 | "IPv4Addresses": [ 42 | "192.0.2.3" 43 | ], 44 | "IPv6Addresses": [ 45 | "2001:dB8:10b:1a00:32bf:a372:d80f:e958" 46 | ], 47 | "AttachmentIndex": 0, 48 | "MACAddress": "02:b7:20:19:72:39", 49 | "IPv4SubnetCIDRBlock": "192.0.2.0/24", 50 | "IPv6SubnetCIDRBlock": "2600:1f13:10b:1a00::/64", 51 | "DomainNameServers": [ 52 | "192.0.2.2" 53 | ], 54 | "DomainNameSearchList": [ 55 | "us-west-2.compute.internal" 56 | ], 57 | "PrivateDNSName": "ip-172-31-30-173.us-west-2.compute.internal", 58 | "SubnetGatewayIpv4Address": "192.0.2.0/24" 59 | } 60 | ], 61 | "ClockDrift": { 62 | "ClockErrorBound": 0.5458234999999999, 63 | "ReferenceTimestamp": "2021-09-07T16:57:44Z", 64 | "ClockSynchronizationStatus": "SYNCHRONIZED" 65 | }, 66 | "ContainerARN": "arn:aws:ecs:us-west-2:111122223333:container/1bdcca8b-f905-4ee6-885c-4064cb70f6e6", 67 | "LogOptions": { 68 | "awslogs-create-group": "true", 69 | "awslogs-group": "/ecs/containerlogs", 70 | "awslogs-region": "us-west-2", 71 | "awslogs-stream": "ecs/curl/e9028f8d5d8e4f258373e7b93ce9a3c3" 72 | }, 73 | "LogDriver": "awslogs" 74 | } 75 | ], 76 | "LaunchType": "FARGATE" 77 | } -------------------------------------------------------------------------------- /examples/springdemo/scripts/checkpoint.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # start the application 4 | echo Starting the application... 5 | ( echo 128 > /proc/sys/kernel/ns_last_pid ) 2>/dev/null || while [ $(cat /proc/sys/kernel/ns_last_pid) -lt 128 ]; do :; done; 6 | TABLE_NAME=springdemo-staging-customer 7 | nohup java -Dspring.profiles.active=prod -Dtable.name=${TABLE_NAME} -Dmode=${MODE} -Damazon.dynamodb.endpoint=${AMAZON_DYNAMO_DB_ENDPOINT} -XX:CRaCEngine=warp -XX:CRaCCheckpointTo=/opt/crac-files -jar /${SRVC_JAR_FILE_NAME} & 8 | 9 | # ensure the application started successfully 10 | echo Confirming the application started successfully... 11 | sleep 30 12 | echo nohup.out 13 | 14 | # warm up the application 15 | echo Warming up the application... 16 | curl http://localhost:8080/api/customers 17 | 18 | # request a checkpoint 19 | echo Taking a snapshot of the application using CRaC... 20 | mkdir /opt/logs/ 21 | jcmd ${SRVC_JAR_FILE_NAME} JDK.checkpoint >> /opt/logs/snapshot.log 22 | sleep 10 23 | 24 | # Waiting till the checkpoint is captured correctly 25 | i=0 26 | while [[ $i -lt 10 ]] 27 | do 28 | echo Waiting till the checkpoint is captured correctly... 29 | if ([ -f /opt/crac-files/core.img ]) 30 | then 31 | echo Checkpoint captured! 32 | exit 0 33 | break 34 | fi 35 | sleep 10 36 | ((i++)) 37 | done 38 | 39 | exit 1; -------------------------------------------------------------------------------- /examples/springdemo/scripts/run-service-crac-s3.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | echo 'Start time (before checkpoint files download from S3: '$(date +"%T.%3N") 3 | mkdir ${CRAC_CHECKPOINT_PATH} 4 | aws s3 sync s3://${CRAC_CHECKPOINT_S3} ${CRAC_CHECKPOINT_PATH} 5 | 6 | source /opt/scripts/run-service-crac.sh -------------------------------------------------------------------------------- /examples/springdemo/scripts/run-service-crac.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # run java 3 | echo 'Start time: '$(date +"%T.%3N") 4 | java -XX:CRaCEngine=warp -XX:CRaCRestoreFrom=${CRAC_CHECKPOINT_PATH} -Dtable.name=${TABLE_NAME} -Dmode=${MODE} -Damazon.dynamodb.endpoint=${AMAZON_DYNAMO_DB_ENDPOINT} -Daws.webIdentityTokenFile="${AWS_WEB_IDENTITY_TOKEN_FILE}" -Daws.roleArn="${AWS_ROLE_ARN}" 5 | 6 | # the code below is to keep the container running if the java process failed 7 | echo Executing an infinite loop to keep the container running... 8 | while true; do sleep 1; done -------------------------------------------------------------------------------- /examples/springdemo/scripts/run-service.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | # run java 3 | echo Starting the application... 4 | java -Dspring.profiles.active=prod -Dtable.name=${TABLE_NAME} -Dmode=${MODE} -Damazon.dynamodb.endpoint=${AMAZON_DYNAMO_DB_ENDPOINT} -jar /${SRVC_JAR_FILE_NAME} 5 | -------------------------------------------------------------------------------- /images/architecture-externalize-checkpoint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-eks-crac/9488e1961481c9351fdd94c3a449acb78e3bc98c/images/architecture-externalize-checkpoint.png -------------------------------------------------------------------------------- /images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aws-samples/aws-eks-crac/9488e1961481c9351fdd94c3a449acb78e3bc98c/images/architecture.png --------------------------------------------------------------------------------