# -*- coding: utf-8 -*- from collections import Counter from typing import Any, Dict, List import boto3 from logzero import logger from chaosaws import aws_client from chaosaws.types import AWSResponse from chaoslib.exceptions import FailedActivity from chaoslib.types import Configuration, Secrets __all__ = ["targets_health_count", "all_targets_healthy"] def targets_health_count(tg_names: List[str], configuration: Configuration = None, secrets: Secrets = None) -> AWSResponse: """ Count of healthy/unhealthy targets per targetgroup """ if not tg_names: raise FailedActivity( "Non-empty list of target groups is required") client = aws_client('elbv2', configuration, secrets) return get_targets_health_count(tg_names=tg_names, client=client) def all_targets_healthy(tg_names: List[str], configuration: Configuration = None, secrets: Secrets = None) -> AWSResponse: """ Return true/false based on if all targets for listed target groups are healthy """ if not tg_names: raise FailedActivity( "Non-empty list of target groups is required") client = aws_client('elbv2', configuration, secrets) logger.debug("Checking if all targets are healthy for targets: {}" .format(str(tg_names))) tg_arns = get_target_group_arns(tg_names=tg_names, client=client) tg_health = get_targets_health_description(tg_arns=tg_arns, client=client) result = True for tg in tg_health: time_to_break = False for health_descr in tg_health[tg]['TargetHealthDescriptions']: if health_descr['TargetHealth']['State'] != 'healthy': result = False time_to_break = True break if time_to_break: break return result ############################################################################### # Private functions ############################################################################### def get_target_group_arns(tg_names: List[str], client: boto3.client) -> Dict: """ Return list of target group ARNs based on list of target group names return structure: { "TargetGroupName": "TargetGroupArn", .... } """ logger.debug("Target group name(s): {} Looking for ARN" .format(str(tg_names))) res = client.describe_target_groups(Names=tg_names) tg_arns = {} for tg in res['TargetGroups']: tg_arns[tg['TargetGroupName']] = tg['TargetGroupArn'] logger.debug("Target groups ARNs: {}".format(str(tg_arns))) return tg_arns def get_targets_health_description(tg_arns: Dict, client: boto3.client) -> Dict: """ Return TargetHealthDescriptions by targetgroups Structure: { "TargetGroupName": { "TargetGroupArn": value, "TargetHealthDescriptions": TargetHealthDescriptions[] }, .... } """ logger.debug("Target group ARN: {} Getting health descriptions" .format(str(tg_arns))) tg_health_descr = {} for tg in tg_arns: tg_health_descr[tg] = {} tg_health_descr[tg]['TargetGroupArn'] = tg_arns[tg] tg_health_descr[tg]['TargetHealthDescriptions'] = \ client.describe_target_health(TargetGroupArn=tg_arns[tg])[ 'TargetHealthDescriptions'] logger.debug("Health descriptions for target group(s) are: {}" .format(str(tg_health_descr))) return tg_health_descr def get_targets_health_count(tg_names: List[str], client: boto3.client) -> Dict: """ Return number of healthy/unhealthy targets per target group Structure: { "TargetGroupName": { "healthy": 3, "unhealthy": 1 }, .... } """ logger.debug("Looking for number of health targets for targetgroups: {}" .format(str(tg_names))) tg_arns = get_target_group_arns(tg_names=tg_names, client=client) tg_health = get_targets_health_description(tg_arns=tg_arns, client=client) tg_targets_health_count = {} for tg in tg_health: cnt = Counter() for health_descr in tg_health[tg]['TargetHealthDescriptions']: cnt[health_descr['TargetHealth']['State']] += 1 tg_targets_health_count[tg] = dict(cnt) logger.debug("Healthy targets by targetgroup: {}" .format(str(tg_targets_health_count))) return tg_targets_health_count