From ca3c96a7bfedc06571d35b04ff9f722861e2ff18 Mon Sep 17 00:00:00 2001 From: "venkatesh.devendran" Date: Sat, 3 Feb 2024 04:08:54 +0530 Subject: [PATCH 1/5] feat: free tier setup for evaluators --- lib/aws/ec2.ts | 9 +++-- lib/aws/rds.ts | 16 ++++---- lib/aws/sdk_userdata.sh | 71 ++++++++++++++++++++++++++++++++++++ lib/aws/stack.ts | 81 ++++++++++++++++++++++++++++++++++++----- lib/aws/userdata.sh | 27 +++++++++++--- 5 files changed, 178 insertions(+), 26 deletions(-) create mode 100644 lib/aws/sdk_userdata.sh diff --git a/lib/aws/ec2.ts b/lib/aws/ec2.ts index 906c1a11..715f04a8 100644 --- a/lib/aws/ec2.ts +++ b/lib/aws/ec2.ts @@ -6,7 +6,7 @@ export class EC2Instance { private readonly instance: ec2.Instance; sg: ec2.SecurityGroup; - constructor(scope: Construct , vpc: ec2.Vpc, config: EC2Config ) { + constructor(scope: Construct , vpc: ec2.Vpc, config: EC2Config, executeAfter?: ec2.Instance ) { let id = config.id; let sg; let keyName; @@ -18,7 +18,7 @@ export class EC2Instance { sg = new ec2.SecurityGroup(scope, sg_id, { securityGroupName: sg_id, vpc: vpc, - allowAllOutbound: false, + allowAllOutbound: true, }); } this.sg = sg; @@ -33,7 +33,6 @@ export class EC2Instance { keyName = awsKeyPair.keyName; } - this.instance = new ec2.Instance(scope, id, { vpc, keyName: keyName, @@ -46,6 +45,10 @@ export class EC2Instance { associatePublicIpAddress: config.associatePublicIpAddress, }); + if (executeAfter){ + this.instance.node.addDependency(executeAfter); + } + // make this identifier name to be 'StandaloneUrl' - refer to install.sh // new cdk.CfnOutput(scope, '', { // value: "http://"+this.instance.instancePublicIp+"/health", diff --git a/lib/aws/rds.ts b/lib/aws/rds.ts index 53b517fd..ed712d05 100644 --- a/lib/aws/rds.ts +++ b/lib/aws/rds.ts @@ -67,14 +67,14 @@ export class DataBaseConstruct { ), publiclyAccessible: true, }), - readers: [ - ClusterInstance.provisioned("Reader Instance", { - instanceType: InstanceType.of( - rds_config.reader_instance_class, - rds_config.reader_instance_size - ), - }), - ], + // readers: [ + // ClusterInstance.provisioned("Reader Instance", { + // instanceType: InstanceType.of( + // rds_config.reader_instance_class, + // rds_config.reader_instance_size + // ), + // }), + // ], vpc, vpcSubnets: { subnetType: SubnetType.PUBLIC }, engine, diff --git a/lib/aws/sdk_userdata.sh b/lib/aws/sdk_userdata.sh new file mode 100644 index 00000000..66a8b056 --- /dev/null +++ b/lib/aws/sdk_userdata.sh @@ -0,0 +1,71 @@ +#!/bin/bash + +sudo yum update -y +sudo yum install docker -y +sudo yum install jq -y +sudo service docker start +sudo usermod -a -G docker ec2-user +sudo yum groupinstall -y "Development Tools" +export LC_ALL=en_US.UTF-8 + +# start a simple http server to serve the Hyperswitch SDK +backend_url={{router_host}} +hyperswitch_client_url=$(curl ifconfig.me) + +cd / +# pull the compiled Hyperswitch SDK from the S3 bucket +sudo curl https://hyperswitch-bucket.s3.amazonaws.com/data.zip --output data.zip +sudo unzip -o data.zip + +# Replace the backend_url and hyperswitch_client_url in the SDK +sudo find /data -type f -name "*.js" -exec sed -i "s/backend_url/$backend_url/g" {} \; +sudo find /data -type f -name "*.js" -exec sed -i "s/hyperswitch_client_url/$hyperswitch_client_url/g" {} \; + +# folder structure the SDK and serve it using a simple http server +cd / +sudo mkdir -p sdk/{{version}}/{{sub_version}} +sudo mv /data/* /sdk/{{version}}/{{sub_version}} +cd /sdk +nohup python -m SimpleHTTPServer 9090 > /dev/null 2>&1 & +cd / + + + +# Hyperswitch Demo APP [Frontend application] +# Create a merchant and get the keys. +# Required for the frontend application to communicate with the backend application +export MERCHANT_ID=$(curl --silent --location --request POST 'http://{{router_host}}/user/signup' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "email": "itisatest@gmail.com", + "password": "admin" + }' | jq -r '.merchant_id') + +export HYPERSWITCH_PUBLISHABLE_KEY=$(curl --silent --location --request GET 'http://{{router_host}}/accounts/'$MERCHANT_ID \ + --header 'Accept: application/json' \ + --header 'api-key: '{{admin_api_key}} | jq -r '.publishable_key') + +export HYPERSWITCH_SECRET_KEY=$(curl --silent --location --request POST 'http://{{router_host}}/api_keys/'$MERCHANT_ID \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --header 'api-key: '{{admin_api_key}} \ + --data-raw '{"name":"API Key 1","description":null,"expiration":"2038-01-19T03:14:08.000Z"}' | jq -r '.api_key') + +export CONNECTOR_KEY=$(curl --silent --location --request POST 'http://{{router_host}}/account/'$MERCHANT_ID'/connectors' \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --header 'api-key: '{{admin_api_key}} \ + --data-raw '{"connector_type":"fiz_operations","connector_name":"stripe_test","connector_account_details":{"auth_type":"HeaderKey","api_key":"test_key"},"test_mode":true,"disabled":false,"payment_methods_enabled":[{"payment_method":"card","payment_method_types":[{"payment_method_type":"credit","card_networks":["Visa","Mastercard"],"minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"debit","card_networks":["Visa","Mastercard"],"minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true}]},{"payment_method":"pay_later","payment_method_types":[{"payment_method_type":"klarna","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"affirm","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"afterpay_clearpay","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true}]}],"metadata":{"city":"NY","unit":"245"},"connector_webhook_details":{"merchant_secret":"MyWebhookSecret"}}' ) + + +cat << EOF >> .env +MERCHANT_ID=$MERCHANT_ID +HYPERSWITCH_PUBLISHABLE_KEY=$HYPERSWITCH_PUBLISHABLE_KEY +HYPERSWITCH_SECRET_KEY=$HYPERSWITCH_SECRET_KEY +CONNECTOR_KEY=$CONNECTOR_KEY +HYPERSWITCH_SERVER_URL=http://$backend_url:80 +HYPERSWITCH_CLIENT_URL=http://$hyperswitch_client_url:9090/0.16.7/v0 +EOF + +docker pull juspaydotin/hyperswitch-web:v1.0.10 +docker run --env-file .env -p 5252:5252 juspaydotin/hyperswitch-web:v1.0.10 \ No newline at end of file diff --git a/lib/aws/stack.ts b/lib/aws/stack.ts index 0ab9c1e6..d08821e6 100644 --- a/lib/aws/stack.ts +++ b/lib/aws/stack.ts @@ -41,6 +41,7 @@ export class AWSStack extends cdk.Stack { let isStandalone = scope.node.tryGetContext("test") || false; if (isStandalone) { + // Deploying Router and Control center application in a single EC2 instance let hyperswitch_ec2 = new EC2Instance( this, vpc.vpc, @@ -50,14 +51,55 @@ export class AWSStack extends cdk.Stack { elasticache.sg.addIngressRule(hyperswitch_ec2.sg, ec2.Port.tcp(6379)); hyperswitch_ec2.sg.addEgressRule(rds.sg, ec2.Port.tcp(5432)); hyperswitch_ec2.sg.addEgressRule(elasticache.sg, ec2.Port.tcp(6379)); - hyperswitch_ec2.sg.addIngressRule( + hyperswitch_ec2.sg.addIngressRule( // To access the Router ec2.Peer.ipv4("0.0.0.0/0"), ec2.Port.tcp(80), ); - hyperswitch_ec2.sg.addIngressRule( + hyperswitch_ec2.sg.addIngressRule( // To access the Control Center + ec2.Peer.ipv4("0.0.0.0/0"), + ec2.Port.tcp(9000), + ); + hyperswitch_ec2.sg.addIngressRule( // To SSH into the instance ec2.Peer.ipv4("0.0.0.0/0"), ec2.Port.tcp(22), ); + + // Deploying SDK and Demo app in a single EC2 instance + let hyperswitch_sdk_ec2 = new EC2Instance( + this, + vpc.vpc, + get_standalone_sdk_ec2_config(config, hyperswitch_ec2), + hyperswitch_ec2.getInstance(), + ); + + // create an security group for the SDK and add rules to access the router and demo app with port 1234 after the hyperswitch_sdk_ec2 is created + hyperswitch_sdk_ec2.sg.addIngressRule( // To access the SDK + ec2.Peer.ipv4("0.0.0.0/0"), + ec2.Port.tcp(9090), + ); + hyperswitch_sdk_ec2.sg.addIngressRule( // To Access Demo APP + ec2.Peer.ipv4("0.0.0.0/0"), + ec2.Port.tcp(5252), + ); + hyperswitch_sdk_ec2.sg.addIngressRule( // To SSH into the instance + ec2.Peer.ipv4("0.0.0.0/0"), + ec2.Port.tcp(22), + ); + + new cdk.CfnOutput(this, "router url", { + value: "http://" + hyperswitch_ec2.getInstance().instancePublicIp + "/health" + }); + new cdk.CfnOutput(this, "control_center", { + value: "http://" + hyperswitch_ec2.getInstance().instancePublicIp + ":9000" + "\nFor login, use email id as 'itisatest@gmail.com' and password is test1234" + }); + new cdk.CfnOutput(this, "sdk assets link", { + value: "http://" + hyperswitch_sdk_ec2.getInstance().instancePublicIp + ":9090" + }); + new cdk.CfnOutput(this, "demo app", { + value: "http://" + hyperswitch_sdk_ec2.getInstance().instancePublicIp + ":5252" + }); + + } else { const aws_arn = scope.node.tryGetContext("aws_arn"); const is_root_user = aws_arn.includes(":root"); @@ -122,17 +164,36 @@ function update_config(config: Config, db_host: string, redis_host: string) { function get_standalone_ec2_config(config: Config) { let customData = readFileSync("lib/aws/userdata.sh", "utf8") - .replace("{{redis_host}}", config.hyperswitch_ec2.redis_host) + .replaceAll("{{redis_host}}", config.hyperswitch_ec2.redis_host) .replaceAll("{{db_host}}", config.hyperswitch_ec2.db_host) - .replace("{{password}}", config.rds.password) - .replace("{{admin_api_key}}", config.hyperswitch_ec2.admin_api_key) - .replace("{{db_username}}", config.rds.db_user) - .replace("{{db_name}}", config.rds.db_name); + .replaceAll("{{password}}", config.rds.password) + .replaceAll("{{admin_api_key}}", config.hyperswitch_ec2.admin_api_key) + .replaceAll("{{db_username}}", config.rds.db_user) + .replaceAll("{{db_name}}", config.rds.db_name); let ec2_config: EC2Config = { - id: "hyperswitch_standalone_ec2", + id: "hyperswitch_standalone_app_cc_ec2", instanceType: ec2.InstanceType.of( - ec2.InstanceClass.T3, - ec2.InstanceSize.MEDIUM, + ec2.InstanceClass.T2, + ec2.InstanceSize.MICRO, + ), + machineImage: new ec2.AmazonLinuxImage(), + vpcSubnets: { subnetGroupName: SubnetNames.PublicSubnet }, + userData: ec2.UserData.custom(customData), + }; + return ec2_config; +} + +function get_standalone_sdk_ec2_config(config: Config, hyperswitch_ec2: EC2Instance) { + let customData = readFileSync("lib/aws/sdk_userdata.sh", "utf8") + .replaceAll("{{router_host}}", hyperswitch_ec2.getInstance().instancePublicIp) + .replaceAll("{{admin_api_key}}", config.hyperswitch_ec2.admin_api_key) + .replaceAll("{{version}}", "0.16.7") + .replaceAll("{{sub_version}}", "v0"); + let ec2_config: EC2Config = { + id: "hyperswitch_standalone_sdk_demo_ec2", + instanceType: ec2.InstanceType.of( + ec2.InstanceClass.T2, + ec2.InstanceSize.MICRO, ), machineImage: new ec2.AmazonLinuxImage(), vpcSubnets: { subnetGroupName: SubnetNames.PublicSubnet }, diff --git a/lib/aws/userdata.sh b/lib/aws/userdata.sh index 18ae10b4..c03c3edf 100644 --- a/lib/aws/userdata.sh +++ b/lib/aws/userdata.sh @@ -5,19 +5,36 @@ sudo yum install docker -y sudo service docker start sudo usermod -a -G docker ec2-user -docker pull juspaydotin/hyperswitch-router:beta +# Installing Hyperswitch Router application [Backend application] -curl https://raw.githubusercontent.com/juspay/hyperswitch/v1.55.0/config/development.toml > production.toml +docker pull juspaydotin/hyperswitch-router:v1.105.0-standalone + +curl https://raw.githubusercontent.com/juspay/hyperswitch/v1.105.0/config/development.toml > production.toml cat << EOF >> .env ROUTER__REDIS__HOST={{redis_host}} ROUTER__MASTER_DATABASE__HOST={{db_host}} -ROUTER__REPLICA_DATABASE__HOST={{db_host}} -ROUTER__SERVER__HOST=0.0.0.0 ROUTER__MASTER_DATABASE__USERNAME={{db_username}} ROUTER__MASTER_DATABASE__PASSWORD={{password}} ROUTER__MASTER_DATABASE__DBNAME={{db_name}} +ROUTER__REPLICA_DATABASE__HOST={{db_host}} +ROUTER__REPLICA_DATABASE__USERNAME={{db_username}} +ROUTER__REPLICA_DATABASE__PASSWORD={{password}} +ROUTER__REPLICA_DATABASE__DBNAME={{db_name}} +ROUTER__SERVER__HOST=0.0.0.0 ROUTER__SERVER__BASE_URL=$(curl ifconfig.me) ROUTER__SECRETS__ADMIN_API_KEY={{admin_api_key}} EOF -docker run --env-file .env -p 80:8080 -v `pwd`/:/local/config juspaydotin/hyperswitch-router:beta ./router -f /local/config/production.toml \ No newline at end of file +docker run -d --env-file .env -p 80:8080 -v `pwd`/:/local/config juspaydotin/hyperswitch-router:v1.105.0-standalone ./router -f /local/config/production.toml + + +# Installing Hyperswitch control center + +docker pull juspaydotin/hyperswitch-control-center:v1.17.0 + +cat << EOF >> .env +apiBaseUrl=http://$(curl ifconfig.me):80 +sdkBaseUrl=http://$(curl ifconfig.me):80 +EOF + +docker run -d --env-file .env -p 9000:9000 juspaydotin/hyperswitch-control-center:v1.17.0 From 3f12dc512babf8c58232e42db0a5b1627e3f0e73 Mon Sep 17 00:00:00 2001 From: "venkatesh.devendran" Date: Thu, 8 Feb 2024 13:31:14 +0530 Subject: [PATCH 2/5] fix: free-tier name change --- lib/aws/stack.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/aws/stack.ts b/lib/aws/stack.ts index d08821e6..a0e0ebab 100644 --- a/lib/aws/stack.ts +++ b/lib/aws/stack.ts @@ -39,7 +39,7 @@ export class AWSStack extends cdk.Stack { locker = new LockerSetup(this, vpc.vpc, config.locker); } - let isStandalone = scope.node.tryGetContext("test") || false; + let isStandalone = scope.node.tryGetContext("free_tier") || false; if (isStandalone) { // Deploying Router and Control center application in a single EC2 instance let hyperswitch_ec2 = new EC2Instance( From fb5a2e0b735afbcf0c5aed9b8c01fe481b6a04d8 Mon Sep 17 00:00:00 2001 From: "venkatesh.devendran" Date: Thu, 8 Feb 2024 15:59:27 +0530 Subject: [PATCH 3/5] fix: free-tier rebase with main --- lib/aws/rds.ts | 167 ++++++++++++++++++++++++++++++++++++++++++++++- lib/aws/stack.ts | 6 +- 2 files changed, 168 insertions(+), 5 deletions(-) diff --git a/lib/aws/rds.ts b/lib/aws/rds.ts index ed712d05..fa6539a9 100644 --- a/lib/aws/rds.ts +++ b/lib/aws/rds.ts @@ -29,8 +29,9 @@ export class DataBaseConstruct { sg: SecurityGroup; db_cluster: DatabaseCluster; password: string; + bucket: cdk.aws_s3.Bucket; - constructor(scope: Construct, rds_config: RDSConfig, vpc: Vpc) { + constructor(scope: Construct, rds_config: RDSConfig, vpc: Vpc, isStandalone: boolean) { const engine = DatabaseClusterEngine.auroraPostgres({ version: AuroraPostgresEngineVersion.VER_13_7, }); @@ -90,8 +91,170 @@ export class DataBaseConstruct { this.db_cluster = db_cluster; + // For standalone deployment, create a bucket to store the schema and migration code + if (isStandalone) { + const schemaBucket = new Bucket(scope, "SchemaBucket", { + removalPolicy: RemovalPolicy.DESTROY, + blockPublicAccess: new s3.BlockPublicAccess({ + blockPublicAcls: false, + }), + publicReadAccess: true, + autoDeleteObjects: true, + bucketName: + "hyperswitch-schema-" + + cdk.Aws.ACCOUNT_ID + "-" + + process.env.CDK_DEFAULT_REGION + }); + + this.bucket = schemaBucket; + + const uploadSchemaAndMigrationCode = `import boto3 +import urllib3 +import json + +SUCCESS = "SUCCESS" +FAILED = "FAILED" + +http = urllib3.PoolManager() + + +def send(event, context, responseStatus, responseData, physicalResourceId=None, noEcho=False, reason=None): + responseUrl = event['ResponseURL'] + + responseBody = { + 'Status' : responseStatus, + 'Reason' : reason or "See the details in CloudWatch Log Stream: {}".format(context.log_stream_name), + 'PhysicalResourceId' : physicalResourceId or context.log_stream_name, + 'StackId' : event['StackId'], + 'RequestId' : event['RequestId'], + 'LogicalResourceId' : event['LogicalResourceId'], + 'NoEcho' : noEcho, + 'Data' : responseData } + json_responseBody = json.dumps(responseBody) + + print("Response body:") + print(json_responseBody) + + headers = { + 'content-type' : '', + 'content-length' : str(len(json_responseBody)) + } + + try: + response = http.request('PUT', responseUrl, headers=headers, body=json_responseBody) + print("Status code:", response.status) + + except Exception as e: + + print("send(..) failed executing http.request(..):", e) + +def upload_file_from_url(url, bucket, key): + s3=boto3.client('s3') + http=urllib3.PoolManager() + s3.upload_fileobj(http.request('GET', url,preload_content=False), bucket, key) + s3.upload_fileobj + +def lambda_handler(event, context): + try: + # Call the upload_file_from_url function to upload two files to S3 + if event['RequestType'] == 'Create': + upload_file_from_url("https://hyperswitch-bucket.s3.amazonaws.com/migration_runner.zip", "hyperswitch-schema-${process.env.CDK_DEFAULT_ACCOUNT}-${process.env.CDK_DEFAULT_REGION}", "migration_runner.zip") + upload_file_from_url("https://hyperswitch-bucket.s3.amazonaws.com/schema.sql", "hyperswitch-schema-${process.env.CDK_DEFAULT_ACCOUNT}-${process.env.CDK_DEFAULT_REGION}", "schema.sql") + upload_file_from_url("https://hyperswitch-bucket.s3.amazonaws.com/locker-schema.sql", "hyperswitch-schema-${process.env.CDK_DEFAULT_ACCOUNT}-${process.env.CDK_DEFAULT_REGION}", "locker-schema.sql") + send(event, context, SUCCESS, { "message" : "Files uploaded successfully"}) + else: + send(event, context, SUCCESS, { "message" : "No action required"}) + except Exception as e: # Use 'Exception as e' to properly catch and define the exception variable + # Handle exceptions and return an error message + send(event, context, FAILED, {"message": str(e)}) + return str(e) + # Return a success message + return '{ "status": 200, "message": "success" }' + ` + + const lambdaRole = new Role(scope, "SchemaUploadLambdaRole", { + assumedBy: new ServicePrincipal("lambda.amazonaws.com"), + }); + + lambdaRole.addToPolicy( + new PolicyStatement({ + actions: [ + "ec2:CreateNetworkInterface", + "ec2:DescribeNetworkInterfaces", + "ec2:DeleteNetworkInterface", + "ec2:AttachNetworkInterface", + "ec2:DetachNetworkInterface", + "secretsmanager:GetSecretValue", + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents", + "s3:GetObject", + "s3:PutObject" + ], + resources: ["*", schemaBucket.bucketArn + "/*"], + }) + ); + + const lambdaSecurityGroup = new SecurityGroup( + scope, + "LambdaSecurityGroup", + { + vpc, + allowAllOutbound: true, + } + ); + + db_security_group.addIngressRule( + lambdaSecurityGroup, + Port.tcp(rds_config.port) + ); + + const initializeUploadFunction = new Function(scope, "initializeUploadFunction", { + runtime: Runtime.PYTHON_3_9, + handler: "index.lambda_handler", + code: Code.fromInline(uploadSchemaAndMigrationCode), + timeout: Duration.minutes(15), + role: lambdaRole, + }); + + + const initializeDbTriggerCustomResource = new cdk.CustomResource(scope, 'InitializeDbTriggerCustomResource', { + serviceToken: initializeUploadFunction.functionArn, + }); + + const initializeDBFunction = new Function(scope, "InitializeDBFunction", { + runtime: Runtime.PYTHON_3_9, + handler: "index.db_handler", + code: Code.fromBucket(schemaBucket, "migration_runner.zip"), + environment: { + DB_SECRET_ARN: secret.secretArn, + SCHEMA_BUCKET: schemaBucket.bucketName, + SCHEMA_FILE_KEY: "schema.sql", + }, + vpc: vpc, + securityGroups: [lambdaSecurityGroup], + timeout: Duration.minutes(15), + role: lambdaRole, + }); + + new triggers.Trigger(scope, "initializeUploadTrigger", { + handler: initializeUploadFunction, + timeout: Duration.minutes(15), + invocationType: triggers.InvocationType.EVENT, + }).executeBefore(); + + new triggers.Trigger(scope, "InitializeDBTrigger", { + handler: initializeDBFunction, + timeout: Duration.minutes(15), + invocationType: triggers.InvocationType.REQUEST_RESPONSE, + }).executeAfter(db_cluster); + + initializeDBFunction.node.addDependency(initializeDbTriggerCustomResource); + } + } + addClient( peer: ISecurityGroup, port: number, @@ -101,4 +264,4 @@ export class DataBaseConstruct { this.sg.addIngressRule(peer, Port.tcp(port), description, remote_rule); peer.addEgressRule(this.sg, Port.tcp(port), description, remote_rule); } -} +} \ No newline at end of file diff --git a/lib/aws/stack.ts b/lib/aws/stack.ts index a0e0ebab..e0d80796 100644 --- a/lib/aws/stack.ts +++ b/lib/aws/stack.ts @@ -21,11 +21,12 @@ export class AWSStack extends cdk.Stack { // }, stackName: config.stack.name, }); + let isStandalone = scope.node.tryGetContext("free_tier") || false; let vpc = new Vpc(this, config.vpc); let subnets = new SubnetStack(this, vpc.vpc, config); let elasticache = new ElasticacheStack(this, config, vpc.vpc); - let rds = new DataBaseConstruct(this, config.rds, vpc.vpc); + let rds = new DataBaseConstruct(this, config.rds, vpc.vpc, isStandalone ); rds.sg.addIngressRule(ec2.Peer.ipv4("0.0.0.0/0"), ec2.Port.tcp(5432)); // this has to be moved to standalone and for production it should be internal jump config = update_config( @@ -39,7 +40,6 @@ export class AWSStack extends cdk.Stack { locker = new LockerSetup(this, vpc.vpc, config.locker); } - let isStandalone = scope.node.tryGetContext("free_tier") || false; if (isStandalone) { // Deploying Router and Control center application in a single EC2 instance let hyperswitch_ec2 = new EC2Instance( @@ -90,7 +90,7 @@ export class AWSStack extends cdk.Stack { value: "http://" + hyperswitch_ec2.getInstance().instancePublicIp + "/health" }); new cdk.CfnOutput(this, "control_center", { - value: "http://" + hyperswitch_ec2.getInstance().instancePublicIp + ":9000" + "\nFor login, use email id as 'itisatest@gmail.com' and password is test1234" + value: "http://" + hyperswitch_ec2.getInstance().instancePublicIp + ":9000" + "\nFor login, use email id as 'itisatest@gmail.com' and password is admin" }); new cdk.CfnOutput(this, "sdk assets link", { value: "http://" + hyperswitch_sdk_ec2.getInstance().instancePublicIp + ":9090" From 6fd162c7c7fdc17ed1d9d5846cdaf0b11f272f4b Mon Sep 17 00:00:00 2001 From: Nitesh Balla Date: Mon, 12 Feb 2024 13:36:18 +0530 Subject: [PATCH 4/5] refactor: differentiate configs if it is a standalone deployment --- install.sh | 411 ++++++++++++++++++++++++++--------------------- lib/aws/rds.ts | 21 +-- lib/aws/stack.ts | 11 +- 3 files changed, 240 insertions(+), 203 deletions(-) diff --git a/install.sh b/install.sh index 9d60faea..7e9c8961 100644 --- a/install.sh +++ b/install.sh @@ -10,19 +10,20 @@ reset=$(tput sgr0) white=$(tput setaf 7) term_width=$(tput cols) box_width=60 -padding="$(printf '%*s' $(( (term_width - box_width) / 2 )) '')" +padding="$(printf '%*s' $(((term_width - box_width) / 2)) '')" box_line="$(printf '%*s' $box_width '')" box_line="${box_line// /-}" +# Function to display error messages in red +display_error() { + echo "${bold}${red}$1${reset}" +} + # Checking for AWS credentials if [[ -z "$AWS_ACCESS_KEY_ID" || -z "$AWS_SECRET_ACCESS_KEY" || -z "$AWS_SESSION_TOKEN" ]]; then display_error "Missing AWS credentials. Please configure the AWS CLI with your credentials." exit 1 fi -# Function to display error messages in red -display_error() { - echo "${bold}${red}$1${reset}" -} echo echo "${green}##########################################${reset}" @@ -46,7 +47,7 @@ show_loader() { # Check for Node.js echo "Checking for Node.js..." -if ! command -v node &> /dev/null; then +if ! command -v node &>/dev/null; then echo "Node.js could not be found. Please install node js 18 or above." exit 1 fi @@ -59,14 +60,14 @@ if [ "$version" -lt 18 ]; then fi echo "Node.js version is valid." - # Install AWS CDK echo "Installing AWS CDK..." -npm install -g aws-cdk & show_loader "Installing AWS CDK..." +npm install -g aws-cdk & +show_loader "Installing AWS CDK..." echo "AWS CDK is installed successfully." # Check for AWS CDK -if ! command -v cdk &> /dev/null; then +if ! command -v cdk &>/dev/null; then echo "AWS CDK could not be found. Please rerun 'bash install.sh' with Sudo access and ensure the command is available within the \$PATH" exit 1 fi @@ -74,42 +75,47 @@ fi # Determine OS and run respective dependency script os=$(uname) case "$os" in - "Linux") +"Linux") echo "Detecting operating system: Linux" - (bash linux_deps.sh & show_loader "Running Linux dependencies script...") + ( + bash linux_deps.sh & + show_loader "Running Linux dependencies script..." + ) ;; - "Darwin") +"Darwin") echo "Detecting operating system: macOS" - (bash mac_deps.sh & show_loader "Running macOS dependencies script...") + ( + bash mac_deps.sh & + show_loader "Running macOS dependencies script..." + ) ;; - *) +*) echo "Unsupported operating system." exit 1 ;; esac # Check if AWS CLI installation was successful -if ! command -v aws &> /dev/null; then +if ! command -v aws &>/dev/null; then echo "AWS CLI could not be found. Please rerun 'bash install.sh' with Sudo access and ensure the command is available within the $PATH" exit 1 fi echo "Dependency installation completed." +fetch_details() { + # Trying to retrieve AWS account owner's details + if ! AWS_ACCOUNT_DETAILS_JSON=$(aws sts get-caller-identity 2>&1); then + display_error "Unable to obtain AWS caller identity: $AWS_ACCOUNT_DETAILS_JSON" + display_error "Check if your AWS credentials are expired and you have appropriate permissions." + exit 1 + fi -fetch_details(){ -# Trying to retrieve AWS account owner's details -if ! AWS_ACCOUNT_DETAILS_JSON=$(aws sts get-caller-identity 2>&1); then - display_error "Unable to obtain AWS caller identity: $AWS_ACCOUNT_DETAILS_JSON" - display_error "Check if your AWS credentials are expired and you have appropriate permissions." - exit 1 -fi - -# Extracting and displaying account details -AWS_ACCOUNT_ID=$(echo "$AWS_ACCOUNT_DETAILS_JSON" | jq -r '.Account') -AWS_USER_ID=$(echo "$AWS_ACCOUNT_DETAILS_JSON" | jq -r '.UserId') -AWS_ARN=$(echo "$AWS_ACCOUNT_DETAILS_JSON" | jq -r '.Arn') -AWS_ROLE=$(aws sts get-caller-identity --query 'Arn' --output text | cut -d '/' -f 2) + # Extracting and displaying account details + AWS_ACCOUNT_ID=$(echo "$AWS_ACCOUNT_DETAILS_JSON" | jq -r '.Account') + AWS_USER_ID=$(echo "$AWS_ACCOUNT_DETAILS_JSON" | jq -r '.UserId') + AWS_ARN=$(echo "$AWS_ACCOUNT_DETAILS_JSON" | jq -r '.Arn') + AWS_ROLE=$(aws sts get-caller-identity --query 'Arn' --output text | cut -d '/' -f 2) } show_loader "Fetching AWS account details" & @@ -140,15 +146,20 @@ print_line "Role: ${bold}$AWS_ROLE${reset}" echo echo "${padding}${box_line}" - echo # Ask consent to proceed with the aws account while true; do read -r -p "Do you want to proceed with the above AWS account? [y/n]: " yn case $yn in - [Yy]* ) echo "Proceeding with AWS account $AWS_ACCOUNT_ID"; break;; - [Nn]* ) echo "Exiting..."; exit;; - * ) echo "Please answer yes or no [y/n].";; + [Yy]*) + echo "Proceeding with AWS account $AWS_ACCOUNT_ID" + break + ;; + [Nn]*) + echo "Exiting..." + exit + ;; + *) echo "Please answer yes or no [y/n]." ;; esac done @@ -156,7 +167,7 @@ done echo "Checking dependencies..." # Check for Node.js -if ! command -v node &> /dev/null; then +if ! command -v node &>/dev/null; then echo "Node.js could not be found. Please install node js 18 or above." exit 1 fi @@ -200,9 +211,15 @@ get_user_choice() { while true; do read -r -p "Enter your choice [1-2]: " INSTALLATION_MODE case $INSTALLATION_MODE in - 1) echo "Free Tier option selected."; break;; - 2) echo "Production Ready option selected."; break;; - *) echo "Invalid choice. Please enter 1 or 2.";; + 1) + echo "Free Tier option selected." + break + ;; + 2) + echo "Production Ready option selected." + break + ;; + *) echo "Invalid choice. Please enter 1 or 2." ;; esac done } @@ -217,10 +234,10 @@ show_install_options get_user_choice check_if_element_is_preset_in_array() { - local e match="$1" - shift - for e; do [[ "$e" == "$match" ]] && return 0; done - return 1 + local e match="$1" + shift + for e; do [[ "$e" == "$match" ]] && return 0; done + return 1 } if [[ -z "$AWS_DEFAULT_REGION" ]]; then @@ -237,36 +254,36 @@ fi # Prompt for region and check if it's enabled while true; do - AVAILABLE_REGIONS_JSON=$(aws ec2 describe-regions --query 'Regions[].RegionName' --output text 2>&1) + AVAILABLE_REGIONS_JSON=$(aws ec2 describe-regions --query 'Regions[].RegionName' --output text 2>&1) - if [[ $AVAILABLE_REGIONS_JSON == *"UnauthorizedOperation"* ]]; then - display_error "Error: Unauthorized operation. You do not have permission to perform 'ec2:DescribeRegions'." - display_error "Contact your AWS administrator to obtain the necessary permissions." - exit 1 - elif [[ $AVAILABLE_REGIONS_JSON == *"supported format"* ]]; then - display_error "Error: Invalid region format. Please enter a valid region code (e.g. us-east-1)." - else - # Convert the region list into an array - AVAILABLE_REGIONS=($AVAILABLE_REGIONS_JSON) - - # Check if AWS_DEFAULT_REGION is in the list of available regions - if [[ " ${AVAILABLE_REGIONS[*]} " =~ " $AWS_DEFAULT_REGION " ]]; then - echo "Region $AWS_DEFAULT_REGION is enabled for your account." - break + if [[ $AVAILABLE_REGIONS_JSON == *"UnauthorizedOperation"* ]]; then + display_error "Error: Unauthorized operation. You do not have permission to perform 'ec2:DescribeRegions'." + display_error "Contact your AWS administrator to obtain the necessary permissions." + exit 1 + elif [[ $AVAILABLE_REGIONS_JSON == *"supported format"* ]]; then + display_error "Error: Invalid region format. Please enter a valid region code (e.g. us-east-1)." else - display_error "Error: Region $AWS_DEFAULT_REGION is not enabled for your account or invalid region code." + # Convert the region list into an array + AVAILABLE_REGIONS=($AVAILABLE_REGIONS_JSON) + + # Check if AWS_DEFAULT_REGION is in the list of available regions + if [[ " ${AVAILABLE_REGIONS[*]} " =~ " $AWS_DEFAULT_REGION " ]]; then + echo "Region $AWS_DEFAULT_REGION is enabled for your account." + break + else + display_error "Error: Region $AWS_DEFAULT_REGION is not enabled for your account or invalid region code." + fi fi - fi - # Prompt for region again - echo "Please enter the AWS region to deploy the services: " - read -r AWS_DEFAULT_REGION + # Prompt for region again + echo "Please enter the AWS region to deploy the services: " + read -r AWS_DEFAULT_REGION done export LOG_FILE="cdk.services.log" function echoLog() { - echo "$1" | tee -a $LOG_FILE + echo "$1" | tee -a $LOG_FILE } echo @@ -276,33 +293,35 @@ echo "${blue}##########################################${reset}" echo check_root_user() { - AWS_ARN=$(aws sts get-caller-identity --output json | jq -r .Arn ) - if [[ $AWS_ARN == *":root"* ]]; then - echo "ROOT user is not recommended. Please create a new user with AdministratorAccess and use their Access Token." - exit 1 - fi + AWS_ARN=$(aws sts get-caller-identity --output json | jq -r .Arn) + if [[ $AWS_ARN == *":root"* ]]; then + echo "ROOT user is not recommended. Please create a new user with AdministratorAccess and use their Access Token." + exit 1 + fi } REQUIRED_POLICIES=("AdministratorAccess") # Add other necessary policies to this array # Check if the current user is a root user echo "Verifying that you're not using the AWS root account..." echo "(For security reasons, it's best to avoid using the root account.)" -(check_root_user) & show_loader "Verifying root user status" +(check_root_user) & +show_loader "Verifying root user status" check_iam_policies() { - USER_POLICIES=$(aws iam list-attached-role-policies --role-name "$AWS_ROLE" --output json | jq -r '.AttachedPolicies[].PolicyName') - for policy in "${REQUIRED_POLICIES[@]}"; do - if ! echo "$USER_POLICIES" | grep -q "$policy"; then - echo "Required policy $policy is not attached to your user. Please attach this policy." - exit 1 - fi - done - echo "All necessary permissions are in place." + USER_POLICIES=$(aws iam list-attached-role-policies --role-name "$AWS_ROLE" --output json | jq -r '.AttachedPolicies[].PolicyName') + for policy in "${REQUIRED_POLICIES[@]}"; do + if ! echo "$USER_POLICIES" | grep -q "$policy"; then + echo "Required policy $policy is not attached to your user. Please attach this policy." + exit 1 + fi + done + echo "All necessary permissions are in place." } # Check for specific IAM policies echo "Checking for necessary IAM policies..." -(check_iam_policies) & show_loader "Verifying IAM policies" +(check_iam_policies) & +show_loader "Verifying IAM policies" echo echo "${blue}##########################################${reset}" @@ -310,7 +329,6 @@ echo "${blue} Configure Credentials of the Application ${reset}" echo "${blue}##########################################${reset}" echo - validate_password() { local password=$1 @@ -392,123 +410,142 @@ while true; do fi done - if [[ "$INSTALLATION_MODE" == 2 ]]; then -echo "Do you want to deploy the Card Vault? [y/n]: " -read -r CARD_VAULT - -LOCKER="" -if [[ "$CARD_VAULT" == "y" ]]; then - # Instructions for Card Vault Master Key - echo "${bold}${red}If you require the Card Vault, create a master key as described below.${reset}" - echo "${bold}${yellow}To generate the master key, use the utility at: https://github.com/juspay/hyperswitch-card-vault${reset}" - echo "${bold}${yellow}With cargo installed, run: cargo install --git https://github.com/juspay/hyperswitch-card-vault --bin utils --root . && ./bin/utils master-key && rm ./bin/utils && rmdir ./bin${reset}" - - # Prompt for Encrypted Master Key - echo "Enter your encrypted master key:" - read -r -s MASTER_KEY - LOCKER+="-c master_key=$MASTER_KEY " - # Prompt for Locker DB Password - while true; do - echo "Please enter the password for your RDS instance (Minimum 8 characters; includes [A-Z], [a-z], [0-9]): " - read -r -s LOCKER_DB_PASS - if validate_password "$LOCKER_DB_PASS"; then - break - fi - done - LOCKER+="-c locker_pass=$LOCKER_DB_PASS " -fi + echo "Do you want to deploy the Card Vault? [y/n]: " + read -r CARD_VAULT + + LOCKER="" + if [[ "$CARD_VAULT" == "y" ]]; then + # Instructions for Card Vault Master Key + echo "${bold}${red}If you require the Card Vault, create a master key as described below.${reset}" + echo "${bold}${yellow}To generate the master key, use the utility at: https://github.com/juspay/hyperswitch-card-vault${reset}" + echo "${bold}${yellow}With cargo installed, run: cargo install --git https://github.com/juspay/hyperswitch-card-vault --bin utils --root . && ./bin/utils master-key && rm ./bin/utils && rmdir ./bin${reset}" + + # Prompt for Encrypted Master Key + echo "Enter your encrypted master key:" + read -r -s MASTER_KEY + LOCKER+="-c master_key=$MASTER_KEY " + # Prompt for Locker DB Password + while true; do + echo "Please enter the password for your RDS instance (Minimum 8 characters; includes [A-Z], [a-z], [0-9]): " + read -r -s LOCKER_DB_PASS + if validate_password "$LOCKER_DB_PASS"; then + break + fi + done + LOCKER+="-c locker_pass=$LOCKER_DB_PASS " + fi -echo "${blue}#########################################${reset}" -echo "${blue} Deploying Hyperswitch Services${reset}" -echo "${blue}#########################################${reset}" -# Deploy the EKS Cluster -npm install -export JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION=true -if ! cdk bootstrap aws://$AWS_ACCOUNT_ID/$AWS_DEFAULT_REGION -c aws_arn=$AWS_ARN; then - BUCKET_NAME=cdk-hnb659fds-assets-$AWS_ACCOUNT_ID-$AWS_DEFAULT_REGION - ROLE_NAME=cdk-hnb659fds-cfn-exec-role-$AWS_ACCOUNT_ID-$AWS_DEFAULT_REGION - aws s3api delete-objects --bucket $BUCKET_NAME --delete "$(aws s3api list-object-versions --bucket $BUCKET_NAME --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')" 2>/dev/null - aws s3api delete-objects --bucket $BUCKET_NAME --delete "$(aws s3api list-object-versions --bucket $BUCKET_NAME --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')" 2>/dev/null - aws s3 rm s3://$BUCKET_NAME --recursive 2>/dev/null - aws s3api delete-bucket --bucket $BUCKET_NAME 2>/dev/null - for policy_arn in $(aws iam list-attached-role-policies --role-name $ROLE_NAME --query 'AttachedPolicies[].PolicyArn' --output text); do - aws iam detach-role-policy --role-name $ROLE_NAME --policy-arn $policy_arn 2>/dev/null - done - aws iam delete-role --role-name $ROLE_NAME 2>/dev/null - cdk bootstrap aws://$AWS_ACCOUNT_ID/$AWS_DEFAULT_REGION -c aws_arn=$AWS_ARN -fi -if cdk deploy --require-approval never -c db_pass=$DB_PASS -c admin_api_key=$ADMIN_API_KEY -c aws_arn=$AWS_ARN -c master_enc_key=$MASTER_ENC_KEY $LOCKER ; then - # Wait for the EKS Cluster to be deployed - echo `aws eks create-addon --cluster-name hs-eks-cluster --addon-name amazon-cloudwatch-observability` - aws eks update-kubeconfig --region "$AWS_DEFAULT_REGION" --name hs-eks-cluster - # Deploy Load balancer and Ingress - echo "##########################################" - sleep 10 - APP_HOST=$(kubectl get ingress hyperswitch-alb-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') - LOGS_HOST=$(kubectl get ingress hyperswitch-logs-alb-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') - CONTROL_CENTER_HOST=$(kubectl get ingress hyperswitch-control-center-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') - SDK_WEB_HOST=$(kubectl get ingress hypers-v1-hyperswitchsdk -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') - SDK_HOST=$(kubectl get ingress hyperswitch-sdk-demo-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') - SDK_URL=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='HyperLoaderUrl'].OutputValue" --output text) - - # Deploy the hyperswitch application with the load balancer host name - helm repo add hs https://juspay.github.io/hyperswitch-helm - export MERCHANT_ID=$(curl --silent --location --request POST 'http://'$APP_HOST'/user/signup' \ - --header 'Content-Type: application/json' \ - --data-raw '{ + echo "${blue}#########################################${reset}" + echo "${blue} Deploying Hyperswitch Services${reset}" + echo "${blue}#########################################${reset}" + # Deploy the EKS Cluster + npm install + export JSII_SILENCE_WARNING_UNTESTED_NODE_VERSION=true + if ! cdk bootstrap aws://$AWS_ACCOUNT_ID/$AWS_DEFAULT_REGION -c aws_arn=$AWS_ARN; then + BUCKET_NAME=cdk-hnb659fds-assets-$AWS_ACCOUNT_ID-$AWS_DEFAULT_REGION + ROLE_NAME=cdk-hnb659fds-cfn-exec-role-$AWS_ACCOUNT_ID-$AWS_DEFAULT_REGION + aws s3api delete-objects --bucket $BUCKET_NAME --delete "$(aws s3api list-object-versions --bucket $BUCKET_NAME --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')" 2>/dev/null + aws s3api delete-objects --bucket $BUCKET_NAME --delete "$(aws s3api list-object-versions --bucket $BUCKET_NAME --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')" 2>/dev/null + aws s3 rm s3://$BUCKET_NAME --recursive 2>/dev/null + aws s3api delete-bucket --bucket $BUCKET_NAME 2>/dev/null + for policy_arn in $(aws iam list-attached-role-policies --role-name $ROLE_NAME --query 'AttachedPolicies[].PolicyArn' --output text); do + aws iam detach-role-policy --role-name $ROLE_NAME --policy-arn $policy_arn 2>/dev/null + done + aws iam delete-role --role-name $ROLE_NAME 2>/dev/null + cdk bootstrap aws://$AWS_ACCOUNT_ID/$AWS_DEFAULT_REGION -c aws_arn=$AWS_ARN + fi + if cdk deploy --require-approval never -c db_pass=$DB_PASS -c admin_api_key=$ADMIN_API_KEY -c aws_arn=$AWS_ARN -c master_enc_key=$MASTER_ENC_KEY $LOCKER; then + # Wait for the EKS Cluster to be deployed + echo $(aws eks create-addon --cluster-name hs-eks-cluster --addon-name amazon-cloudwatch-observability) + aws eks update-kubeconfig --region "$AWS_DEFAULT_REGION" --name hs-eks-cluster + # Deploy Load balancer and Ingress + echo "##########################################" + sleep 10 + APP_HOST=$(kubectl get ingress hyperswitch-alb-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + LOGS_HOST=$(kubectl get ingress hyperswitch-logs-alb-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + CONTROL_CENTER_HOST=$(kubectl get ingress hyperswitch-control-center-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + SDK_WEB_HOST=$(kubectl get ingress hypers-v1-hyperswitchsdk -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + SDK_HOST=$(kubectl get ingress hyperswitch-sdk-demo-ingress -n hyperswitch -o jsonpath='{.status.loadBalancer.ingress[0].hostname}') + SDK_URL=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='HyperLoaderUrl'].OutputValue" --output text) + + # Deploy the hyperswitch application with the load balancer host name + helm repo add hs https://juspay.github.io/hyperswitch-helm + export MERCHANT_ID=$(curl --silent --location --request POST 'http://'$APP_HOST'/user/signup' \ + --header 'Content-Type: application/json' \ + --data-raw '{ "email": "test@gmail.com", "password": "admin" }' | jq -r '.merchant_id') - export PUB_KEY=$(curl --silent --location --request GET 'http://'$APP_HOST'/accounts/'$MERCHANT_ID \ - --header 'Accept: application/json' \ - --header 'api-key: '$ADMIN_API_KEY | jq -r '.publishable_key') - export API_KEY=$(curl --silent --location --request POST 'http://'$APP_HOST'/api_keys/'$MERCHANT_ID \ - --header 'Content-Type: application/json' \ - --header 'Accept: application/json' \ - --header 'api-key: '$ADMIN_API_KEY \ - --data-raw '{"name":"API Key 1","description":null,"expiration":"2038-01-19T03:14:08.000Z"}' | jq -r '.api_key') - export CONNECTOR_KEY=$(curl --silent --location --request POST 'http://'$APP_HOST'/account/'$MERCHANT_ID'/connectors' \ - --header 'Content-Type: application/json' \ - --header 'Accept: application/json' \ - --header 'api-key: '$ADMIN_API_KEY \ - --data-raw '{"connector_type":"fiz_operations","connector_name":"stripe_test","connector_account_details":{"auth_type":"HeaderKey","api_key":"test_key"},"test_mode":true,"disabled":false,"payment_methods_enabled":[{"payment_method":"card","payment_method_types":[{"payment_method_type":"credit","card_networks":["Visa","Mastercard"],"minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"debit","card_networks":["Visa","Mastercard"],"minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true}]},{"payment_method":"pay_later","payment_method_types":[{"payment_method_type":"klarna","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"affirm","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"afterpay_clearpay","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true}]}],"metadata":{"city":"NY","unit":"245"},"connector_webhook_details":{"merchant_secret":"MyWebhookSecret"}}' ) - printf "##########################################\nPlease wait for the application to deploy \n##########################################" - helm get values -n hyperswitch hypers-v1 > values.yaml - helm upgrade --install hypers-v1 hs/hyperswitch-helm --set "application.dashboard.env.apiBaseUrl=http://$APP_HOST,application.sdk.env.hyperswitchPublishableKey=$PUB_KEY,application.sdk.env.hyperswitchSecretKey=$API_KEY,application.sdk.env.hyperswitchServerUrl=http://$APP_HOST,application.sdk.env.hyperSwitchClientUrl=$SDK_URL,application.dashboard.env.sdkBaseUrl=$SDK_URL/HyperLoader.js,application.server.server_base_url=http://$APP_HOST,hyperswitchsdk.autoBuild.buildParam.envSdkUrl=http://$SDK_WEB_HOST,hyperswitchsdk.autoBuild.buildParam.envBackendUrl=http://$APP_HOST,services.router.host=http://$APP_HOST" -n hyperswitch -f values.yaml - sleep 10 - echoLog "--------------------------------------------------------------------------------" - echoLog "$bold Service Host$reset" - echoLog "--------------------------------------------------------------------------------" - echoLog "$green HyperloaderJS Hosted at $blue"https://$SDK_WEB_HOST/0.16.7/v0/HyperLoader.js"$reset" - echoLog "$green App server running on $blue"http://$APP_HOST"$reset" - echoLog "$green Logs server running on $blue"http://$LOGS_HOST"$reset, Login with $YELLOW username: admin, password: admin$reset , Please change on startup" - echoLog "$green Control center server running on $blue"http://$CONTROL_CENTER_HOST"$reset, Login with $YELLOW Email: test@gmail.com, password: admin$reset , Please change on startup" - echoLog "$green Hyperswitch Demo Store running on $blue"http://$SDK_HOST"$reset" - echoLog "--------------------------------------------------------------------------------" - echoLog "##########################################" - echo "$blue Please run 'cat cdk.services.log' to view the services details again"$reset - if [[ "$CARD_VAULT" == "y" ]]; then - sh ./unlock_locker.sh - fi - exit 0 -fi + export PUB_KEY=$(curl --silent --location --request GET 'http://'$APP_HOST'/accounts/'$MERCHANT_ID \ + --header 'Accept: application/json' \ + --header 'api-key: '$ADMIN_API_KEY | jq -r '.publishable_key') + export API_KEY=$(curl --silent --location --request POST 'http://'$APP_HOST'/api_keys/'$MERCHANT_ID \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --header 'api-key: '$ADMIN_API_KEY \ + --data-raw '{"name":"API Key 1","description":null,"expiration":"2038-01-19T03:14:08.000Z"}' | jq -r '.api_key') + export CONNECTOR_KEY=$(curl --silent --location --request POST 'http://'$APP_HOST'/account/'$MERCHANT_ID'/connectors' \ + --header 'Content-Type: application/json' \ + --header 'Accept: application/json' \ + --header 'api-key: '$ADMIN_API_KEY \ + --data-raw '{"connector_type":"fiz_operations","connector_name":"stripe_test","connector_account_details":{"auth_type":"HeaderKey","api_key":"test_key"},"test_mode":true,"disabled":false,"payment_methods_enabled":[{"payment_method":"card","payment_method_types":[{"payment_method_type":"credit","card_networks":["Visa","Mastercard"],"minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"debit","card_networks":["Visa","Mastercard"],"minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true}]},{"payment_method":"pay_later","payment_method_types":[{"payment_method_type":"klarna","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"affirm","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true},{"payment_method_type":"afterpay_clearpay","payment_experience":"redirect_to_url","minimum_amount":1,"maximum_amount":68607706,"recurring_enabled":true,"installment_payment_enabled":true}]}],"metadata":{"city":"NY","unit":"245"},"connector_webhook_details":{"merchant_secret":"MyWebhookSecret"}}') + printf "##########################################\nPlease wait for the application to deploy \n##########################################" + helm get values -n hyperswitch hypers-v1 >values.yaml + helm upgrade --install hypers-v1 hs/hyperswitch-helm --set "application.dashboard.env.apiBaseUrl=http://$APP_HOST,application.sdk.env.hyperswitchPublishableKey=$PUB_KEY,application.sdk.env.hyperswitchSecretKey=$API_KEY,application.sdk.env.hyperswitchServerUrl=http://$APP_HOST,application.sdk.env.hyperSwitchClientUrl=$SDK_URL,application.dashboard.env.sdkBaseUrl=$SDK_URL/HyperLoader.js,application.server.server_base_url=http://$APP_HOST,hyperswitchsdk.autoBuild.buildParam.envSdkUrl=http://$SDK_WEB_HOST,hyperswitchsdk.autoBuild.buildParam.envBackendUrl=http://$APP_HOST,services.router.host=http://$APP_HOST" -n hyperswitch -f values.yaml + sleep 10 + echoLog "--------------------------------------------------------------------------------" + echoLog "$bold Service Host$reset" + echoLog "--------------------------------------------------------------------------------" + echoLog "$green HyperloaderJS Hosted at $blue"https://$SDK_WEB_HOST/0.16.7/v0/HyperLoader.js"$reset" + echoLog "$green App server running on $blue"http://$APP_HOST"$reset" + echoLog "$green Logs server running on $blue"http://$LOGS_HOST"$reset, Login with $YELLOW username: admin, password: admin$reset , Please change on startup" + echoLog "$green Control center server running on $blue"http://$CONTROL_CENTER_HOST"$reset, Login with $YELLOW Email: test@gmail.com, password: admin$reset , Please change on startup" + echoLog "$green Hyperswitch Demo Store running on $blue"http://$SDK_HOST"$reset" + echoLog "--------------------------------------------------------------------------------" + echoLog "##########################################" + echo "$blue Please run 'cat cdk.services.log' to view the services details again"$reset + if [[ "$CARD_VAULT" == "y" ]]; then + sh ./unlock_locker.sh + fi + exit 0 + fi else -echo "${blue}#########################################${reset}" -echo "${blue} Deploying Hyperswitch Services${reset}" -echo "${blue}#########################################${reset}" -echo -echo "Hyperswitch is being deployed in standalone mode. Please wait for the deployment to complete." - -npm install -cdk bootstrap aws://$AWS_ACCOUNT_ID/$AWS_DEFAULT_REGION -c aws_arn=$AWS_ARN -if cdk deploy --require-approval never -c test=true ; then - STANDALONE_HOST=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='StandaloneUrl'].OutputValue" --output text) - echoLog "--------------------------------------------------------------------------------" - echoLog "$bold EC2 Instance IP Host $blue"$STANDALONE_HOST"$reset" - echoLog "--------------------------------------------------------------------------------" -fi + echo "${blue}#########################################${reset}" + echo "${blue} Deploying Hyperswitch Services${reset}" + echo "${blue}#########################################${reset}" + echo + echo "Hyperswitch is being deployed in standalone mode. Please wait for the deployment to complete." + + npm install + if ! cdk bootstrap aws://$AWS_ACCOUNT_ID/$AWS_DEFAULT_REGION -c aws_arn=$AWS_ARN; then + BUCKET_NAME=cdk-hnb659fds-assets-$AWS_ACCOUNT_ID-$AWS_DEFAULT_REGION + ROLE_NAME=cdk-hnb659fds-cfn-exec-role-$AWS_ACCOUNT_ID-$AWS_DEFAULT_REGION + aws s3api delete-objects --bucket $BUCKET_NAME --delete "$(aws s3api list-object-versions --bucket $BUCKET_NAME --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')" 2>/dev/null + aws s3api delete-objects --bucket $BUCKET_NAME --delete "$(aws s3api list-object-versions --bucket $BUCKET_NAME --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')" 2>/dev/null + aws s3 rm s3://$BUCKET_NAME --recursive 2>/dev/null + aws s3api delete-bucket --bucket $BUCKET_NAME 2>/dev/null + for policy_arn in $(aws iam list-attached-role-policies --role-name $ROLE_NAME --query 'AttachedPolicies[].PolicyArn' --output text); do + aws iam detach-role-policy --role-name $ROLE_NAME --policy-arn $policy_arn 2>/dev/null + done + aws iam delete-role --role-name $ROLE_NAME 2>/dev/null + cdk bootstrap aws://$AWS_ACCOUNT_ID/$AWS_DEFAULT_REGION -c aws_arn=$AWS_ARN + fi + if cdk deploy -c aws_arn=$AWS_ARN -c free_tier=true -c db_pass=$DB_PASS -c admin_api_key=$ADMIN_API_KEY ; then + STANDALONE_HOST=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='StandaloneURL'].OutputValue" --output text) + CONTROL_CENTER_HOST=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='ControlCenterURL'].OutputValue" --output text) + SDK_HOST=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='SdkAssetsURL'].OutputValue" --output text) + DEMO_APP=$(aws cloudformation describe-stacks --stack-name hyperswitch --query "Stacks[0].Outputs[?OutputKey=='DemoApp'].OutputValue" --output text) + echoLog "--------------------------------------------------------------------------------" + echoLog "$bold Service Host$reset" + echoLog "--------------------------------------------------------------------------------" + echoLog "$green Standalone Hosted at $blue"$STANDALONE_HOST"$reset" + echoLog "$green Control center server running on $blue"$CONTROL_CENTER_HOST"$reset" + echoLog "$green SDK Hosted at $blue"$SDK_HOST"$reset" + echoLog "$green Hyperswitch Demo Store running on $blue"$DEMO_APP"$reset" + echoLog "--------------------------------------------------------------------------------" + fi fi diff --git a/lib/aws/rds.ts b/lib/aws/rds.ts index fa6539a9..1b9bc837 100644 --- a/lib/aws/rds.ts +++ b/lib/aws/rds.ts @@ -66,18 +66,19 @@ export class DataBaseConstruct { rds_config.writer_instance_class, rds_config.writer_instance_size ), - publiclyAccessible: true, + publiclyAccessible: isStandalone, }), - // readers: [ - // ClusterInstance.provisioned("Reader Instance", { - // instanceType: InstanceType.of( - // rds_config.reader_instance_class, - // rds_config.reader_instance_size - // ), - // }), - // ], + readers: isStandalone ? [] : + [ + ClusterInstance.provisioned("Reader Instance", { + instanceType: InstanceType.of( + rds_config.reader_instance_class, + rds_config.reader_instance_size + ), + }), + ], vpc, - vpcSubnets: { subnetType: SubnetType.PUBLIC }, + vpcSubnets: { subnetType: isStandalone ? SubnetType.PUBLIC : SubnetType.PRIVATE_WITH_EGRESS }, engine, port: rds_config.port, securityGroups: [db_security_group], diff --git a/lib/aws/stack.ts b/lib/aws/stack.ts index e0d80796..d6ce9991 100644 --- a/lib/aws/stack.ts +++ b/lib/aws/stack.ts @@ -21,8 +21,7 @@ export class AWSStack extends cdk.Stack { // }, stackName: config.stack.name, }); - let isStandalone = scope.node.tryGetContext("free_tier") || false; - + let isStandalone = (scope.node.tryGetContext("free_tier") == "true") || false; let vpc = new Vpc(this, config.vpc); let subnets = new SubnetStack(this, vpc.vpc, config); let elasticache = new ElasticacheStack(this, config, vpc.vpc); @@ -86,16 +85,16 @@ export class AWSStack extends cdk.Stack { ec2.Port.tcp(22), ); - new cdk.CfnOutput(this, "router url", { + new cdk.CfnOutput(this, "StandaloneURL", { value: "http://" + hyperswitch_ec2.getInstance().instancePublicIp + "/health" }); - new cdk.CfnOutput(this, "control_center", { + new cdk.CfnOutput(this, "ControlCenterURL", { value: "http://" + hyperswitch_ec2.getInstance().instancePublicIp + ":9000" + "\nFor login, use email id as 'itisatest@gmail.com' and password is admin" }); - new cdk.CfnOutput(this, "sdk assets link", { + new cdk.CfnOutput(this, "SdkAssetsURL", { value: "http://" + hyperswitch_sdk_ec2.getInstance().instancePublicIp + ":9090" }); - new cdk.CfnOutput(this, "demo app", { + new cdk.CfnOutput(this, "DemoApp", { value: "http://" + hyperswitch_sdk_ec2.getInstance().instancePublicIp + ":5252" }); From 37d91ffefdbf122110b19b13375e1beb8db1735f Mon Sep 17 00:00:00 2001 From: "venkatesh.devendran" Date: Mon, 12 Feb 2024 15:21:32 +0530 Subject: [PATCH 5/5] fix: use mock locker --- lib/aws/userdata.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/aws/userdata.sh b/lib/aws/userdata.sh index c03c3edf..48c81fd6 100644 --- a/lib/aws/userdata.sh +++ b/lib/aws/userdata.sh @@ -20,6 +20,7 @@ ROUTER__REPLICA_DATABASE__HOST={{db_host}} ROUTER__REPLICA_DATABASE__USERNAME={{db_username}} ROUTER__REPLICA_DATABASE__PASSWORD={{password}} ROUTER__REPLICA_DATABASE__DBNAME={{db_name}} +ROUTER__LOCKER__MOCK_LOCKER=true ROUTER__SERVER__HOST=0.0.0.0 ROUTER__SERVER__BASE_URL=$(curl ifconfig.me) ROUTER__SECRETS__ADMIN_API_KEY={{admin_api_key}}