#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
#
import time

from botocore.exceptions import ClientError

from . import exception_utils
from . import cleanup_utils


def __log_group_exists(cleaner, log_group_name_prefix):
    """
    Verifies if a log exists. This is should be replaced once logs supports Waiter objects for log deletion.
    :param cleaner: A Cleaner object from the main cleanup.py script
    :param log_group_name_prefix: Can be retrieved from the boto3 describe_log_groups() with
    response['logGroups']['logGroupName']
    :return: True if the log exists, False if it doesn't exist or an error occurs.
    """
    try:
        response = cleaner.logs.describe_log_groups(logGroupNamePrefix=log_group_name_prefix)
        if not len(response['logGroups']):
            return False
    except KeyError:
        print("      ERROR: Unexpected KeyError trying to search for key 'logGroups' in log group {}"
              .format(log_group_name_prefix))
    except ClientError as err:
        print("      ERROR: Unexpected error occurred when checking if log group {0} exists due to {1}"
              .format(log_group_name_prefix, exception_utils.message(err)))
        return False
    else:
        return True


def delete_log_groups(cleaner):
    """
    Deletes all logs from the client. It will construct a list of resources, delete them, then wait for
    each deletion.
    :param cleaner: A Cleaner object from the main cleanup.py script
    :return: None
    """
    print('\n\nlooking for cloudwatch log groups starting with one of {}'.format(cleaner.describe_prefixes()))
    log_group_name_list = []

    # Construct list
    try:
        log_group_paginator = cleaner.logs.get_paginator('describe_log_groups')
        log_group_paginator = log_group_paginator.paginate()

        for page in log_group_paginator:
            for log_group in page['logGroups']:
                log_group_name = log_group['logGroupName']
                prefix_name = log_group_name.replace('/aws/lambda/', '')
                if cleaner.has_prefix(prefix_name):
                    print('  found log {}'.format(log_group_name))
                    log_group_name_list.append(log_group_name)
    except KeyError as e:
        print("      ERROR: Unexpected KeyError while deleting cloudwatch log groups. {}".format(
            exception_utils.message(e)))
        return
    except ClientError as e:
        print("      ERROR: Unexpected error for paginator for the cloudwatch client. {}".format(
            exception_utils.message(e)))
        return

    # Delete log groups
    for log_group_name in log_group_name_list:
        try:
            print('  deleting log group {0}'.format(log_group_name))
            cleaner.logs.delete_log_group(logGroupName=log_group_name)
        except ClientError as e:
            print('      ERROR. Failed to delete log group {0} due to {1}'.format(log_group_name,
                                                                                  exception_utils.message(e)))
            cleaner.add_to_failed_resources("cloudwatch logs", log_group_name)

    # Wait for log groups to be deleted
    for log_group_name in log_group_name_list:
        try:
            cleanup_utils.wait_for(lambda: not __log_group_exists(cleaner, log_group_name),
                                   attempts=cleaner.wait_attempts,
                                   interval=cleaner.wait_interval,
                                   timeout_exception=cleanup_utils.WaitError)
        except cleanup_utils.WaitError:
            print('      ERROR. Log group {0} was not deleted after timeout'.format(log_group_name))
            cleaner.add_to_failed_resources("cloudwatch logs", log_group_name)
        except ClientError as e:
            if e.response["Error"]["Code"] == "TooManyRequestsException":
                print('    too many requests, sleeping...')
                time.sleep(cleaner.wait_interval)
            else:
                print("      ERROR: Unexpected error occurred waiting for logs {0} to delete due to {1}".format(
                    log_group_name, exception_utils.message(e)))
                cleaner.add_to_failed_resources("cloudwatch logs", log_group_name)

#
# All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
# its licensors.
#
# For complete copyright and license terms please see the LICENSE at the root of this
# distribution (the "License"). All use of this software is governed by the License,
# or, if provided, by the license below or the license accompanying this file. Do not
# remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
#
import time

from botocore.exceptions import ClientError

from . import exception_utils
from . import cleanup_utils


def __log_group_exists(cleaner, log_group_name_prefix):
    """
    Verifies if a log exists. This is should be replaced once logs supports Waiter objects for log deletion.
    :param cleaner: A Cleaner object from the main cleanup.py script
    :param log_group_name_prefix: Can be retrieved from the boto3 describe_log_groups() with
    response['logGroups']['logGroupName']
    :return: True if the log exists, False if it doesn't exist or an error occurs.
    """
    try:
        response = cleaner.logs.describe_log_groups(logGroupNamePrefix=log_group_name_prefix)
        if not len(response['logGroups']):
            return False
    except KeyError:
        print("      ERROR: Unexpected KeyError trying to search for key 'logGroups' in log group {}"
              .format(log_group_name_prefix))
    except ClientError as err:
        print("      ERROR: Unexpected error occurred when checking if log group {0} exists due to {1}"
              .format(log_group_name_prefix, exception_utils.message(err)))
        return False
    else:
        return True


def delete_log_groups(cleaner):
    """
    Deletes all logs from the client. It will construct a list of resources, delete them, then wait for
    each deletion.
    :param cleaner: A Cleaner object from the main cleanup.py script
    :return: None
    """
    print('\n\nlooking for cloudwatch log groups starting with one of {}'.format(cleaner.describe_prefixes()))
    log_group_name_list = []

    # Construct list
    try:
        log_group_paginator = cleaner.logs.get_paginator('describe_log_groups')
        log_group_paginator = log_group_paginator.paginate()

        for page in log_group_paginator:
            for log_group in page['logGroups']:
                log_group_name = log_group['logGroupName']
                prefix_name = log_group_name.replace('/aws/lambda/', '')
                if cleaner.has_prefix(prefix_name):
                    print('  found log {}'.format(log_group_name))
                    log_group_name_list.append(log_group_name)
    except KeyError as e:
        print("      ERROR: Unexpected KeyError while deleting cloudwatch log groups. {}".format(
            exception_utils.message(e)))
        return
    except ClientError as e:
        print("      ERROR: Unexpected error for paginator for the cloudwatch client. {}".format(
            exception_utils.message(e)))
        return

    # Delete log groups
    for log_group_name in log_group_name_list:
        try:
            print('  deleting log group {0}'.format(log_group_name))
            cleaner.logs.delete_log_group(logGroupName=log_group_name)
        except ClientError as e:
            print('      ERROR. Failed to delete log group {0} due to {1}'.format(log_group_name,
                                                                                  exception_utils.message(e)))
            cleaner.add_to_failed_resources("cloudwatch logs", log_group_name)

    # Wait for log groups to be deleted
    for log_group_name in log_group_name_list:
        try:
            cleanup_utils.wait_for(lambda: not __log_group_exists(cleaner, log_group_name),
                                   attempts=cleaner.wait_attempts,
                                   interval=cleaner.wait_interval,
                                   timeout_exception=cleanup_utils.WaitError)
        except cleanup_utils.WaitError:
            print('      ERROR. Log group {0} was not deleted after timeout'.format(log_group_name))
            cleaner.add_to_failed_resources("cloudwatch logs", log_group_name)
        except ClientError as e:
            if e.response["Error"]["Code"] == "TooManyRequestsException":
                print('    too many requests, sleeping...')
                time.sleep(cleaner.wait_interval)
            else:
                print("      ERROR: Unexpected error occurred waiting for logs {0} to delete due to {1}".format(
                    log_group_name, exception_utils.message(e)))
                cleaner.add_to_failed_resources("cloudwatch logs", log_group_name)

# # All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or # its licensors. # # For complete copyright and license terms please see the LICENSE at the root of this # distribution (the "License"). All use of this software is governed by the License, # or, if provided, by the license below or the license accompanying this file. Do not # remove or modify any license notices. This file is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # # Verifies if a log exists. This is should be replaced once logs supports Waiter objects for log deletion.     :param cleaner: A Cleaner object from the main cleanup.py script     :param log_group_name_prefix: Can be retrieved from the boto3 describe_log_groups() with     response['logGroups']['logGroupName']     :return: True if the log exists, False if it doesn't exist or an error occurs. Deletes all logs from the client. It will construct a list of resources, delete them, then wait for     each deletion.     :param cleaner: A Cleaner object from the main cleanup.py script     :return: None # Construct list # Delete log groups # Wait for log groups to be deleted