diff --git a/workshops/serverless-testing-workshop/demo-app/urs-ui.py b/workshops/serverless-testing-workshop/demo-app/urs-ui.py index 98bd26cb..40f230b5 100644 --- a/workshops/serverless-testing-workshop/demo-app/urs-ui.py +++ b/workshops/serverless-testing-workshop/demo-app/urs-ui.py @@ -12,16 +12,19 @@ import uuid import time import requests +import boto3 import streamlit as st from streamlit_js_eval import streamlit_js_eval # Initialize Contexts if 'api_endpoint_url' not in st.session_state: - if os.path.isfile("config.json"): - with open("config.json","r",encoding="utf-8") as f: - app_config = json.load(f) - st.session_state['api_endpoint_url'] = app_config["api_endpoint"].strip() - else: + try: + cfn_client = boto3.client('cloudformation') + response = cfn_client.describe_stacks(StackName=os.environ.get('BACKEND_STACK_NAME','urs-backend')) + for output in response['Stacks'][0]['Outputs']: + if output['OutputKey'] == 'ApiEndpoint': + st.session_state['api_endpoint_url'] = output['OutputValue'] + except: st.session_state['api_endpoint_url'] = "https://{APIGATEWAYID}.execute-api.{REGION}.amazonaws.com/Prod/" if 'unicorn_art' not in st.session_state: @@ -215,7 +218,7 @@ def update_unicorn_reserve_list(): key="api_endpoint_url", on_change=update_api_endpoint ) - + # File picker for uploading to the unicorn inventory uploaded_file = st.file_uploader("Choose a CSV file for the Unicorn Inventory.", type=["csv"]) if uploaded_file is not None: diff --git a/workshops/serverless-testing-workshop/template.yaml b/workshops/serverless-testing-workshop/template.yaml index 50d89b78..d97a6b0f 100644 --- a/workshops/serverless-testing-workshop/template.yaml +++ b/workshops/serverless-testing-workshop/template.yaml @@ -242,293 +242,6 @@ Resources: name: - !Ref UnicornInventoryBucket -################################################## -################################################## -##### demo-app (begin) -################################################## -################################################## - - # - # Networking - # VPC, 2 Public Subnets, S3/ECR/Cloudwatch Service Endpoints, Internet Gateway - # - - StreamlitVPC: - Type: AWS::EC2::VPC - Properties: - CidrBlock: 192.168.0.0/24 - EnableDnsHostnames : true - EnableDnsSupport : true - - StreamlitSubnet1: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref StreamlitVPC - CidrBlock: 192.168.0.0/25 - AvailabilityZone: !Sub "${AWS::Region}b" - - StreamlitSubnet2: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref StreamlitVPC - CidrBlock: 192.168.0.128/25 - AvailabilityZone: !Sub "${AWS::Region}c" - - StreamlitInternetGateway: - Type: AWS::EC2::InternetGateway - - StreamlitGatewayAttachment: - Type: AWS::EC2::VPCGatewayAttachment - Properties: - InternetGatewayId: !Ref StreamlitInternetGateway - VpcId: !Ref StreamlitVPC - - StreamlitSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: "Streamlit UI Security Group" - GroupName: !Sub "${AWS::StackName}-ds-sg" - SecurityGroupEgress: - - IpProtocol: tcp - FromPort: 0 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - Description: Allow outbound access - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: !Ref iECRStreamlitPort - ToPort: !Ref iECRStreamlitPort - CidrIp: 0.0.0.0/0 - Description: Inbound only on Streamlit port - VpcId: !Ref StreamlitVPC - - EndpointSecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: "Streamlit UI Endpoint Security Group" - GroupName: !Sub "${AWS::StackName}-ep-sg" - SecurityGroupEgress: - - IpProtocol: tcp - FromPort: 0 - ToPort: 65535 - CidrIp: 0.0.0.0/0 - Description: Allow outbound access - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 0 - ToPort: 65535 - SourceSecurityGroupId: !Ref StreamlitSecurityGroup - Description: Allow inbound from Streamlit sg only - VpcId: !Ref StreamlitVPC - - StreamlitRouteTable: - Type: 'AWS::EC2::RouteTable' - Properties: - VpcId: !Ref StreamlitVPC - - InternetGatewayRoute: - Type: AWS::EC2::Route - Properties: - GatewayId: !Ref StreamlitInternetGateway - RouteTableId: !Ref StreamlitRouteTable - DestinationCidrBlock: 0.0.0.0/0 - - SubnetRouteTableAssociation1: - Type: 'AWS::EC2::SubnetRouteTableAssociation' - Properties: - SubnetId: !Ref StreamlitSubnet1 - RouteTableId: !Ref StreamlitRouteTable - - SubnetRouteTableAssociation2: - Type: 'AWS::EC2::SubnetRouteTableAssociation' - Properties: - SubnetId: !Ref StreamlitSubnet2 - RouteTableId: !Ref StreamlitRouteTable - - StreamlitVPCEndpointECRApi: - Type: AWS::EC2::VPCEndpoint - Properties: - SecurityGroupIds: - - !Ref EndpointSecurityGroup - ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.api' - SubnetIds: - - !Ref StreamlitSubnet1 - - !Ref StreamlitSubnet2 - VpcEndpointType: Interface - VpcId: !Ref StreamlitVPC - PrivateDnsEnabled: true - - StreamlitVPCEndpointDocker: - Type: AWS::EC2::VPCEndpoint - Properties: - SecurityGroupIds: - - !Ref EndpointSecurityGroup - ServiceName: !Sub 'com.amazonaws.${AWS::Region}.ecr.dkr' - SubnetIds: - - !Ref StreamlitSubnet1 - - !Ref StreamlitSubnet2 - VpcEndpointType: Interface - VpcId: !Ref StreamlitVPC - PrivateDnsEnabled: true - - StreamlitVPCEndpointLogs: - Type: AWS::EC2::VPCEndpoint - Properties: - SecurityGroupIds: - - !Ref EndpointSecurityGroup - ServiceName: !Sub 'com.amazonaws.${AWS::Region}.logs' - SubnetIds: - - !Ref StreamlitSubnet1 - - !Ref StreamlitSubnet2 - VpcEndpointType: Interface - VpcId: !Ref StreamlitVPC - PrivateDnsEnabled: true - - StreamlitVPCEndpointS3: - Type: AWS::EC2::VPCEndpoint - Properties: - ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3' - VpcEndpointType: Gateway - VpcId: !Ref StreamlitVPC - RouteTableIds: - - !Ref StreamlitRouteTable - - LoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Subnets: - - !Ref StreamlitSubnet1 - - !Ref StreamlitSubnet2 - SecurityGroups: - - !Ref StreamlitSecurityGroup - - LoadBalancerListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - LoadBalancerArn: !Ref LoadBalancer - Port: !Ref iECRStreamlitPort - Protocol: HTTP - DefaultActions: - - Type: forward - TargetGroupArn: !Ref TargetGroup - - TargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - Name: !Sub "${AWS::StackName}-tg-http" - VpcId: !Ref StreamlitVPC - Port: !Ref iECRStreamlitPort - Protocol: HTTP - TargetType: ip - HealthCheckEnabled: true - HealthCheckIntervalSeconds: 60 - HealthCheckPath: "/_stcore/health" - HealthCheckPort: !Ref iECRStreamlitPort - HealthCheckProtocol: HTTP - TargetGroupAttributes: - - Key: stickiness.enabled - Value: "true" - - Key: stickiness.type - Value: lb_cookie - - Key: stickiness.lb_cookie.duration_seconds - Value: "86500" - - ECSTask: - Type: AWS::ECS::TaskDefinition - DependsOn: LoadBalancerListener - Properties: - RequiresCompatibilities: - - FARGATE - Cpu: '2048' - Memory: '4096' - NetworkMode: awsvpc - RuntimePlatform: - CpuArchitecture: "X86_64" - OperatingSystemFamily: "LINUX" - ExecutionRoleArn: !Ref ExecutionRole - TaskRoleArn: !Ref TaskRole - ContainerDefinitions: - - Name: "streamlit" - Image: !Sub "${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/docsearch-ecr" - MemoryReservation: 2048 - Cpu: 2048 - Memory: 4096 - Essential: true - PortMappings: - - ContainerPort: !Ref iECRStreamlitPort - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-create-group: "true" - awslogs-group: !Sub "/ecs/${AWS::StackName}-ECSTask" - awslogs-region: !Sub "${AWS::Region}" - awslogs-stream-prefix: "ecs" - - ECSCluster: - Type: 'AWS::ECS::Cluster' - Properties: - ClusterName: !Sub "${AWS::StackName}-cluster" - - ECSService: - Type: 'AWS::ECS::Service' - Properties: - Cluster: !Ref ECSCluster - TaskDefinition: !Ref ECSTask - DesiredCount: 1 - LaunchType: FARGATE - ServiceName: !Sub "${AWS::StackName}-svc" - SchedulingStrategy: "REPLICA" - LoadBalancers: - - ContainerName: "streamlit" - ContainerPort: !Ref iECRStreamlitPort - TargetGroupArn: !Ref TargetGroup - HealthCheckGracePeriodSeconds: 50 - NetworkConfiguration: - AwsvpcConfiguration: - AssignPublicIp: ENABLED - SecurityGroups: - - !Ref StreamlitSecurityGroup - Subnets: - - !Ref StreamlitSubnet1 - - !Ref StreamlitSubnet2 - - ExecutionRole: - Type: AWS::IAM::Role - Properties: - RoleName: !Sub "${AWS::StackName}-execution-role" - AssumeRolePolicyDocument: - Statement: - - Effect: Allow - Principal: - Service: ecs-tasks.amazonaws.com - Action: 'sts:AssumeRole' - Policies: - - PolicyName: root - PolicyDocument: - Version: "2012-10-17" - Statement: - - Effect: Allow - Action: - - "ecr:GetAuthorizationToken" - - "ecr:BatchCheckLayerAvailability" - - "ecr:GetDownloadUrlForLayer" - - "ecr:BatchGetImage" - - "logs:CreateLogStream" - - "logs:PutLogEvents" - - "logs:CreateLogGroup" - Resource: '*' - - TaskRole: - Type: AWS::IAM::Role - Properties: - RoleName: !Sub "${AWS::StackName}-task-role" - AssumeRolePolicyDocument: - Statement: - - Effect: Allow - Principal: - Service: ecs-tasks.amazonaws.com - Action: 'sts:AssumeRole' - Outputs: # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function # Find out more about other implicit resources you can reference within SAM @@ -548,6 +261,3 @@ Outputs: GetFileValidatorARN: Description: "ARN of the Lambda function required in the 'OPTIONAL: Invoke a Lambda function in the cloud' section." Value: !GetAtt FileValidator.Arn - oUiDnsName: - Description: Host UI web link name - Value: !Sub "http://${LoadBalancer.DNSName}:${iECRStreamlitPort}"