Paradigm

ExSI is a framework that allows processing of a new syntax through a standardized API.

This API performs preprocessing on the common parameters of a URI in the AWS context (queryStringParameters).

1
2
3
4
5
6
7
8
9
API.post("api-exsi-backend", "/realize", {
    queryStringParameters: {
        boto_service: resource_service,
        boto_method: resource_action,
        account_id: account_id,
        region: region
    },
    body: body
})

The homepage of the ExSI user interface provides real-time status of your applications. After logging in with your Faro account, you can access URIs with parameters such as:

https://ef31m0bz7h.execute-api.eu-west-1.amazonaws.com/deployment/realize?boto_service=cloudwatch&boto_method=describe_alarms&account_id=269107856146&region=eu-west-1

The API’s preprocessing dynamically generates an enriched UI usable on the Front End of the SaaS application.

Framework Process 📗

The Front End dynamically generates the URI link.

React components update through the useEffect() method.

Components are displayed or hidden based on a conditional Display state, evaluated as a boolean in the render() method.

Callbacks are managed by two types of microservices:

Asynchronous Front-End microservices

Filter the Callback response and generate an enriched UI.

Example: Object.assign(target, source) and object.hasOwnProperty() stored in a React state.

Asynchronous Front-End + Back-End microservices

Handle both the Callback response and advanced DynamoDB filters.

DynamoDB filters are asynchronous and managed with complementary API Gateway calls triggered from the original Callback.

Synchronous calls without pre- or post-processing are managed by the application code (see SYNC TAGS in Lambda Functions).

First Origin Callback via API Gateway 📗

✨ Wizard method: mastering the magic ✨

import json
import boto3
import importlib

service = importlib.import_module("lambda_backend_realize_service")

def role_arn_to_session(**args):
    client_iam = boto3.client('sts')
    region = args.pop("Region")
    response_iam = client_iam.assume_role(**args)
    return boto3.Session(
        aws_access_key_id=response_iam['Credentials']['AccessKeyId'],
        aws_secret_access_key=response_iam['Credentials']['SecretAccessKey'],
        aws_session_token=response_iam['Credentials']['SessionToken'],
        region_name=region,
    )


def lambda_handler(event, context):
    boto_args = {}
    if "body" in event and event["body"] is not None:
        # ✨ event body mapping ✨
        boto_args = json.loads(event["body"])

    if 'account_id' not in event["queryStringParameters"]:
        return build_response(400, "You have to specify an account_id")

    if 'boto_service' not in event["queryStringParameters"]:
        return build_response(400, "You have to specify a boto_service")

    if 'boto_method' not in event["queryStringParameters"]:
        return build_response(400, "You have to specify a boto_method")

    region = event["queryStringParameters"].get('region', "eu-west-1")

    account_id = event["queryStringParameters"]['account_id']
    boto_service = event["queryStringParameters"]['boto_service']
    boto_method = event["queryStringParameters"]['boto_method']

    try:
        session = role_arn_to_session(
            RoleArn='arn:aws:iam::' + account_id + ':role/rol-exsi-access',
            RoleSessionName='SessionName',
            Region=region
        )

        boto_client = session.client(boto_service)
        # ✨ event body mapping with getattr method ✨
        call_result = getattr(boto_client, boto_method)(**boto_args)
        return build_response(200,
                              build_response_body(boto_service, boto_method,
                                                  boto_client, call_result))
    except Exception as err:
        print("EXSI_ERROR_400 - " + str(err))
        return build_response(400, err)


def build_response(status, body):
    return {
        'statusCode': status,
        'headers': {
            "Access-Control-Allow-Credentials": True,
            "Access-Control-Allow-Origin": "*"},
        'body': json.dumps(body, default=str)}


def build_response_body(boto_service, boto_method, boto_client, call_result):
    if boto_service == 'cloudwatch' and boto_method == 'describe_alarms':
        # ✨ filter the mapped event body ✨
        response = call_result
        alarms = response['MetricAlarms']
        while 'NextToken' in response:
            response = getattr(boto_client, boto_method)(NextToken=response['NextToken'])
            alarms.extend(response['MetricAlarms'])

        response = getattr(boto_client, boto_method)(AlarmTypes=['CompositeAlarm'])
        alarms.extend(response['CompositeAlarms'])
        while 'NextToken' in response:
            response = getattr(boto_client, boto_method)(
                AlarmTypes=['CompositeAlarm'], NextToken=response['NextToken'])
            alarms.extend(response['CompositeAlarms'])
        return service.filter_alarms_on_name_criteria(alarms, 'SECO')

    if boto_service == 'lambda' and boto_method == 'invoke':
        payload = call_result['Payload']
        payload_read = payload.read()
        return payload_read.decode()

    if boto_service == 'ecs' and boto_method == 'list_tasks':
        response = call_result
        tasks = response['taskArns']
        while 'nextToken' in response:
            response = getattr(boto_client, boto_method)(NextToken=response['nextToken'])
            tasks.extend(response['taskArns'])
    # ✨ return filtered mapped event body ✨
    return call_result

Framework Concept 📗

The following line of code is used in Python to dynamically invoke a method of an object:

call_result = getattr(boto_client, boto_method)(**boto_args)

Detailed Explanation

getattr(boto_client, boto_method)
getattr
is a built-in Python function to access an object attribute dynamically by name (string).
boto_client
is the AWS client (e.g., S3, EC2, CloudWatch).
boto_method
is a string containing the method name (e.g., "describe_alarms").
(**boto_args)
Passes a dictionary as keyword arguments to the method.
Example: {"AlarmNames": ["my-alarm"], "StateValue": "OK"}

Example

1
2
3
4
5
6
7
8
boto_client = boto3.client('cloudwatch')
boto_method = 'describe_alarms'
boto_args = {
    'AlarmNames': ['my-alarm'],
    'StateValue': 'OK'
}

call_result = getattr(boto_client, boto_method)(**boto_args)

This is equivalent to:

call_result = boto_client.describe_alarms(AlarmNames=['my-alarm'], StateValue='OK')

Use Case

This approach is useful when method names and parameters are determined at runtime, making the framework flexible for interacting with multiple AWS services in a generic way.