def evaluate_compliance()

in python/AMI_OUTDATED_CHECK/AMI_OUTDATED_CHECK.py [0:0]


def evaluate_compliance(event, configuration_item, valid_rule_parameters):
    """Form the evaluation(s) to be return to Config Rules

    Return either:
    None -- when no result needs to be displayed
    a string -- either COMPLIANT, NON_COMPLIANT or NOT_APPLICABLE
    a dictionary -- the evaluation dictionary, usually built by build_evaluation_from_config_item()
    a list of dictionary -- a list of evaluation dictionary , usually built by build_evaluation()

    Keyword arguments:
    event -- the event variable given in the lambda handler
    configuration_item -- the configurationItem dictionary in the invokingEvent
    valid_rule_parameters -- the output of the evaluate_parameters() representing validated
        parameters of the Config Rule

    Advanced Notes:
    1 -- if a resource is deleted and generate a configuration change with ResourceDeleted status,
        the Boilerplate code will put a NOT_APPLICABLE on this resource automatically.
    2 -- if a None or a list of dictionary is returned, the old evaluation(s) which are not
        returned in the new evaluation list are returned as NOT_APPLICABLE by the Boilerplate code
    3 -- if None or an empty string, list or dict is returned, the Boilerplate code will put a
        "shadow" evaluation to feedback that the evaluation took place properly
    """
    ec2_client = get_client('ec2', event)
    evaluations = []

    if configuration_item:
        ami_result = ec2_client.describe_images(
            ImageIds=[configuration_item['configuration']['imageId']]
        )
        print(ami_result)
        if ami_result['Images']:
            #print("AMI result:")
            #print(ami_result)
            status, annotation = evaluate_image(
                ami_result['Images'][0],
                configuration_item['configuration']['instanceId'],
                valid_rule_parameters
            )
            evaluations.append(
                build_evaluation_from_config_item(
                    configuration_item,
                    status,
                    annotation=annotation
                )
            )
        else:
            #Scenario 1 : No Private AMI for the Instance
            evaluations.append(
                build_evaluation_from_config_item(
                    configuration_item,
                    "NOT_APPLICABLE",
                    ""
                )
            )
    else:
        # First get all of the instances, paging through them if we have to.
        image_id_array = []
        instance_array = []

        instance_results = ec2_client.describe_instances()
        while True:
            for res in instance_results['Reservations']:
                for instance in res['Instances']:
                    image_id_array.append(instance['ImageId'])
                    instance_array.append(instance)
            if 'NextToken' in instance_results:
                next_token = instance_results['NextToken']
                instance_results = ec2_client.describe_instances(NextToken=next_token)
            else:
                break
        print(image_id_array)
        print(instance_array)

        # Use set() to get a list of just the unique image ID's.
        unique_image_ids = set(image_id_array)

        print(unique_image_ids)

        # Make as few API calls as possible to get the AMI data.  A simpler loop in
        # which we calling the EC2 API for every instance would be easier, but would
        # result in a _lot_ more API activity and could cause throttling.

        # Create a lookup dict so that we can evaluate compliance for each instance.
        image_lookup = {}

        image_results = ec2_client.describe_images(
            ImageIds=list(unique_image_ids)
        )
        while True:
            for image in image_results['Images']:
                image_lookup[image['ImageId']] = image

            if 'NextToken' in image_results:
                next_token = image_results['NextToken']
                image_results = ec2_client.describe_images(
                    ImageIds=list(unique_image_ids),
                    NextToken=next_token
                )
            else:
                break

        print(image_lookup)

        # Now loop through the instances again and determine the compliance status,
        # appending it to our evaluations list.
        for instance in instance_array:
            if instance['ImageId'] in image_lookup:
                status, annotation = evaluate_image(
                    image_lookup[instance['ImageId']],
                    instance['InstanceId'],
                    valid_rule_parameters
                )
                evaluations.append(
                    build_evaluation(
                        instance['InstanceId'],
                        status,
                        event,
                        "AWS::EC2::Instance",
                        annotation
                    )
                )
            else:
                #Scenario 1 : No Private AMIs in the account then no resources in scope
                evaluations.append(
                    build_evaluation(
                        instance['InstanceId'],
                        'NOT_APPLICABLE',
                        event,
                        "AWS::EC2::Instance"
                    )
                )

    return evaluations