def create_infra()

in right_size_your_sagemaker_endpoints/api_helper.py [0:0]


def create_infra(project_name, account_id, region):
    """
    Creates AWS Lambda and API Gateway for load testing.
    
    This function is called by the notebook to create an AWS Lambda function
    and an API gateway endpoint that we use to perform the load testing. 
    
    Inputs:
    project_name - unique identifier that's tagged to all resources
    account_id - notebook users's AWS account ID
    region - AWS region to deploy the resources in.
    
    Output:
    API Gateway endpoint URL.
    """    
    ## SETUP THE ROLES AND POLICIES
    
    # Create role that can be assumed by Lambda
    trust_policy = {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }

    role = iam_client.create_role(
        RoleName=f"LambdaRoleToInvokeSageMakerEndpoint{project_name}",
        AssumeRolePolicyDocument=json.dumps(trust_policy),
        Description="Role for Lambda function to invoke SageMaker endpoints",
    )

    # Create policy for the role, allowing Lambda to invoke SageMaker endpoint
    policy_doc = {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "logs:CreateLogGroup",
                    "logs:CreateLogStream",
                    "logs:PutLogEvents",
                    "sagemaker:InvokeEndpoint"
                ],
                "Resource": [
                    "arn:aws:logs:*:*:*",
                    "arn:aws:sagemaker:*:*:*"
                ],
                "Effect": "Allow"
            }
        ]
    }

    policy = iam_client.create_policy(
        PolicyName=f"LambdaSageMakerAccessPolicy{project_name}",
        PolicyDocument=json.dumps(policy_doc)
    )

    # Attach policy to role
    response = iam_resource.Role(role['Role']['RoleName']).attach_policy(PolicyArn=policy['Policy']['Arn'])
    
    LambdaRoleArn = role['Role']['Arn']
    
    time.sleep(10)
    
    ## SETUP AND DEPLOY LAMBDA FUNCTION
    
    # Zip the request prediction code
    with ZipFile('lambda_function.zip', 'w') as zip:
        zip.write('lambda_index.py')
    
    # Create the lambda
    response = lambda_client.create_function(
        FunctionName=f'request-predictions-{project_name}',
        Runtime='python3.8',
        Role=LambdaRoleArn,
        Handler='lambda_index.lambda_handler',
        Code={
            'ZipFile': open('./lambda_function.zip', 'rb').read()
        },
        Description='Function to invoke endpoint and return predictions',
        Timeout=60,
        MemorySize=128
    )
    
    lambda_arn = response['FunctionArn']
    lambda_name = response['FunctionName']
    
    # Create rest api
    rest_api = api_client.create_rest_api(
        name=f'ImageClassifier-{project_name}'
    )
    rest_api_id = rest_api["id"]

    # Get the rest api's root id
    root_resource_id = api_client.get_resources(
        restApiId=rest_api_id
    )['items'][0]['id']

    # Create an api resource
    api_resource = api_client.create_resource(
        restApiId=rest_api_id,
        parentId=root_resource_id,
        pathPart='ImageClassifier'
    )

    api_resource_id = api_resource['id']

    # Add a post method to the rest api resource
    api_method = api_client.put_method(
        restApiId=rest_api_id,
        resourceId=api_resource_id,
        httpMethod='POST',
        authorizationType='NONE'
    )

    lambda_uri = f"arn:aws:apigateway:{region}:lambda:path/2015-03-31/functions/{lambda_arn}/invocations"
    
    
    # Add integrations for mapping SageMaker and Lambda HTTP response codes to API gateway HTTP response codes
    put_integration = api_client.put_integration(
        restApiId=rest_api_id,
        resourceId=api_resource_id,
        httpMethod='POST',
        type='AWS',
        integrationHttpMethod='POST',
        uri=lambda_uri)

    put_method_res = api_client.put_method_response(
        restApiId=rest_api_id,
        resourceId=api_resource_id,
        httpMethod='POST',
        statusCode='200',
        responseModels={'application/json': 'Empty'}
    )

    put_integration_response = api_client.put_integration_response(
        restApiId=rest_api_id,
        resourceId=api_resource_id,
        httpMethod='POST',
        statusCode='200',
        responseTemplates={"application/json": ""}
    )

    put_integration_response = api_client.put_integration_response(
        restApiId=rest_api_id,
        resourceId=api_resource_id,
        httpMethod='POST',
        statusCode='400',
        selectionPattern='Invalid*',
        responseTemplates={"application/json": ""}
    )
        
    put_integration_response = api_client.put_integration_response(
        restApiId=rest_api_id,
        resourceId=api_resource_id,
        httpMethod='POST',
        statusCode='500',
        selectionPattern='Internal*',
        responseTemplates={"application/json": ""}
    )
    
    # Deploy to a stage
    deployment = api_client.create_deployment(
        restApiId=rest_api_id,
        stageName='dev',
      )

    # API gateway needs permissions to invoke the lambda function
    lambda_api_response = lambda_client.add_permission(
        FunctionName=lambda_name,
        StatementId='api-gateway-invoke',
        Action='lambda:InvokeFunction',
        Principal='apigateway.amazonaws.com',
        SourceArn=f"arn:aws:execute-api:{region}:{account_id}:{rest_api_id}/*/POST/ImageClassifier"
    )
    
    api_url = f"https://{rest_api_id}.execute-api.{region}.amazonaws.com/dev/ImageClassifier"
    
    print("API GATEWAY URL: url = "+ f"{api_url}")
    
    return api_url