"""Lambda Functions for calculate SLA of O11y get cluster API available""" import json from datetime import datetime, timezone import pymysql import sliutil.connection import sliutil.string import sliutil.tidb import sliutil.time SLI_TABLE_NAME = "sli_o11y_shared_vm_available" SLA_TABLE_NAME = "sla_o11y_shared_vm_available" def lambda_handler(event, context): # pylint:disable=unused-argument """AWS Lambda Function Handler Parameters ---------- event: dict, required API Gateway Lambda Proxy Input Format Event doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-input-format # pylint:disable=line-too-long # noqa context: object, required Lambda Context runtime methods and attributes Context doc: https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html Returns ------ API Gateway Lambda Proxy Output Format: dict Return doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html # pylint:disable=line-too-long """ tidb_conn = sliutil.connection.get_tidb_connection() month_str = event.get("month", "") begin_ts, end_ts = sliutil.time.get_month_begin_end_ts(month=month_str) handler = Handler(connection=tidb_conn) handler.run(begin_ts=begin_ts, end_ts=end_ts) return { "statusCode": 200, "body": json.dumps( { "message": "hello world", # "location": ip.text.replace("\n", "") } ), } class Handler: """Handle metrics `o11y_shared_vm_api_available_count`""" def __init__(self, connection: pymysql.Connection) -> None: self.connection = connection def run(self, begin_ts: float, end_ts: float) -> None: """Calculate SLA of O11y get cluster API available from begin_ts to end_ts and save the results into a new table """ print(f"Start to calculate SLA, begin_ts: {begin_ts}, end_ts: {end_ts}") # regions = self.list_regions(begin_ts=begin_ts, end_ts=end_ts) # region_names = [region["region"] for region in regions] region_names = [ "ap-northeast-1", "ap-northeast-2", "ap-southeast-1", "asia-east1", "asia-northeast1", "asia-southeast1", "eu-central-1", "us-central1", "us-east-1", "us-east4", "us-west-2", "us-west1", ] results = self.search( begin_ts=begin_ts, end_ts=end_ts, regions=region_names, ) downtime_sla = {} for row in results: sla = 1 - row["downtime"] / sliutil.time.get_total_minutes_of_month( timestamp=begin_ts ) downtime_sla[row["region"]] = sla data = [] for region in region_names: data.append( ( region, sliutil.time.get_month_from_timestamp(timestamp=begin_ts), downtime_sla.get(region, 1), ) ) self.save(data=data) print("Finish calculate SLA") def search(self, begin_ts: float, end_ts: float, regions: list) -> list: """List downtime minutes from begin_ts to end_ts""" results = [] start = datetime.now(timezone.utc).timestamp() with self.connection.cursor() as cursor: for i in range(0, len(regions), 100): end = min(i + 100, len(regions)) sql = f""" SELECT region, COUNT(1) AS downtime FROM( SELECT region, FLOOR(timestamp / 60) * 60 as downtime_time FROM `{SLI_TABLE_NAME}` WHERE timestamp >= {begin_ts:.0f} AND timestamp <= {end_ts:.0f} AND increment > 0 AND region in ({sliutil.string.list_to_string(regions[i:end])}) GROUP BY region, downtime_time HAVING BIT_AND(status = "detect_failed") ORDER BY region ASC, downtime_time ASC ) cluster_downtime GROUP BY region """ # print("search, sql: ", sql) cursor.execute(sql) results.extend(cursor.fetchall()) end = datetime.now(timezone.utc).timestamp() print(f"search, take {end - start:.2f}s") return results def list_regions(self, begin_ts: float, end_ts: float) -> list: """List regions""" with self.connection.cursor() as cursor: sql = f""" SELECT DISTINCT region FROM `{SLI_TABLE_NAME}` WHERE timestamp >= {begin_ts:.0f} AND timestamp <= {end_ts:.0f} """ # print("search, sql: ", sql) cursor.execute(sql) result = cursor.fetchall() print(f"list o11 clusters, len: {len(result)}") return result def save(self, data: list) -> None: """Save data into table""" print(f"save data, len: {len(data)}") with self.connection.cursor() as cursor: sql = f""" INSERT INTO `{SLA_TABLE_NAME}` ( region, month, value ) VALUES (%s, %s, %s) ON DUPLICATE KEY UPDATE value=VALUES(value) """ cursor.executemany(sql, data) self.connection.commit()