|
| 1 | +import datetime |
| 2 | +import json |
| 3 | +import os |
| 4 | +from importlib.metadata import version |
| 5 | + |
| 6 | +import boto3 |
| 7 | + |
| 8 | +from aws_lambda_powertools import Logger, Metrics, Tracer |
| 9 | + |
| 10 | +logger = Logger(service="version-track") |
| 11 | +tracer = Tracer() |
| 12 | +metrics = Metrics(namespace="powertools-layer-canary", service="PowertoolsLayerCanary") |
| 13 | + |
| 14 | +layer_arn = os.getenv("POWERTOOLS_LAYER_ARN") |
| 15 | +powertools_version = os.getenv("POWERTOOLS_VERSION") |
| 16 | +stage = os.getenv("LAYER_PIPELINE_STAGE") |
| 17 | +event_bus_arn = os.getenv("VERSION_TRACKING_EVENT_BUS_ARN") |
| 18 | + |
| 19 | + |
| 20 | +def handler(event): |
| 21 | + logger.info("Running checks") |
| 22 | + check_envs() |
| 23 | + verify_powertools_version() |
| 24 | + send_notification() |
| 25 | + return True |
| 26 | + |
| 27 | + |
| 28 | +@logger.inject_lambda_context(log_event=True) |
| 29 | +def on_event(event, context): |
| 30 | + request_type = event["RequestType"] |
| 31 | + # we handle only create events, because we recreate the canary on each run |
| 32 | + if request_type == "Create": |
| 33 | + return on_create(event) |
| 34 | + |
| 35 | + return "Nothing to be processed" |
| 36 | + |
| 37 | + |
| 38 | +def on_create(event): |
| 39 | + props = event["ResourceProperties"] |
| 40 | + logger.info("create new resource with properties %s" % props) |
| 41 | + handler(event) |
| 42 | + |
| 43 | + |
| 44 | +def check_envs(): |
| 45 | + logger.info('Checking required envs ["POWERTOOLS_LAYER_ARN", "AWS_REGION", "STAGE"]') |
| 46 | + if not layer_arn: |
| 47 | + raise ValueError("POWERTOOLS_LAYER_ARN is not set. Aborting...") |
| 48 | + if not powertools_version: |
| 49 | + raise ValueError("POWERTOOLS_VERSION is not set. Aborting...") |
| 50 | + if not stage: |
| 51 | + raise ValueError("LAYER_PIPELINE_STAGE is not set. Aborting...") |
| 52 | + if not event_bus_arn: |
| 53 | + raise ValueError("VERSION_TRACKING_EVENT_BUS_ARN is not set. Aborting...") |
| 54 | + logger.info("All envs configured, continue...") |
| 55 | + |
| 56 | + |
| 57 | +def verify_powertools_version() -> None: |
| 58 | + """ |
| 59 | + fetches the version that we import from the powertools layer and compares |
| 60 | + it with expected version set in environment variable, which we pass during deployment. |
| 61 | + :raise ValueError if the expected version is not the same as the version we get from the layer |
| 62 | + """ |
| 63 | + logger.info("Checking Powertools version in library...") |
| 64 | + current_version = version("aws_lambda_powertools") |
| 65 | + if powertools_version != current_version: |
| 66 | + raise ValueError( |
| 67 | + f'Expected powertoosl version is "{powertools_version}", but layer contains version "{current_version}"' |
| 68 | + ) |
| 69 | + logger.info(f"Current Powertools version is: {current_version}") |
| 70 | + |
| 71 | + |
| 72 | +def send_notification(): |
| 73 | + """ |
| 74 | + sends an event to version tracking event bridge |
| 75 | + """ |
| 76 | + event = { |
| 77 | + "Time": datetime.datetime.now(), |
| 78 | + "Source": "powertools.layer.canary", |
| 79 | + "EventBusName": event_bus_arn, |
| 80 | + "DetailType": "deployment", |
| 81 | + "Detail": json.dumps( |
| 82 | + { |
| 83 | + "id": "powertools-python", |
| 84 | + "stage": stage, |
| 85 | + "region": os.environ["AWS_REGION"], |
| 86 | + "version": powertools_version, |
| 87 | + "layerArn": layer_arn, |
| 88 | + } |
| 89 | + ), |
| 90 | + } |
| 91 | + |
| 92 | + logger.info(f"sending notification event: {event}") |
| 93 | + |
| 94 | + client = boto3.client("events", region_name="eu-central-1") |
| 95 | + resp = client.put_events(Entries=[event]) |
| 96 | + logger.info(resp) |
| 97 | + if resp["FailedEntryCount"] != 0: |
| 98 | + logger.error(resp) |
| 99 | + raise ValueError("Failed to send deployment notification to version tracking") |
0 commit comments