Ensure an EC2 instance does not exist (is stopped and removed).

    .. versionchanged:: 2016.11.0

    name
        (string) - The name of the state definition.
    instance_name
        (string) - The name of the instance.
    instance_id
        (string) - The ID of the instance.
    release_eip
        (bool)   - Release any associated EIPs during termination.
    region
        (string) - Region to connect to.
    key
        (string) - Secret key to be used.
    keyid
        (string) - Access key to be used.
    profile
        (variable) - A dict with region, key and keyid, or a pillar key (string)
        that contains a dict with region, key and keyid.
    filters
        (dict) - A dict of additional filters to use in matching the instance to
        delete.

    YAML example fragment:

    .. code-block:: yaml

        - filters:
            vpc-id: vpc-abcdef12

def instance_absent(name, instance_name=None, instance_id=None,
                    release_eip=False, region=None, key=None, keyid=None,
                    profile=None, filters=None):
    '''
    Ensure an EC2 instance does not exist (is stopped and removed).

    .. versionchanged:: 2016.11.0

    name
        (string) - The name of the state definition.
    instance_name
        (string) - The name of the instance.
    instance_id
        (string) - The ID of the instance.
    release_eip
        (bool)   - Release any associated EIPs during termination.
    region
        (string) - Region to connect to.
    key
        (string) - Secret key to be used.
    keyid
        (string) - Access key to be used.
    profile
        (variable) - A dict with region, key and keyid, or a pillar key (string)
        that contains a dict with region, key and keyid.
    filters
        (dict) - A dict of additional filters to use in matching the instance to
        delete.

    YAML example fragment:

    .. code-block:: yaml

        - filters:
            vpc-id: vpc-abcdef12
    '''
    ### TODO - Implement 'force' option??  Would automagically turn off
    ###        'disableApiTermination', as needed, before trying to delete.
    ret = {'name': name,
           'result': True,
           'comment': '',
           'changes': {}
          }
    running_states = ('pending', 'rebooting', 'running', 'stopping', 'stopped')

    if not instance_id:
        try:
            instance_id = __salt__['boto_ec2.get_id'](name=instance_name if instance_name else name,
                                                      region=region, key=key, keyid=keyid,
                                                      profile=profile, in_states=running_states,
                                                      filters=filters)
        except CommandExecutionError as e:
            ret['result'] = None
            ret['comment'] = ("Couldn't determine current status of instance "
                              "{0}.".format(instance_name or name))
            return ret

    instances = __salt__['boto_ec2.find_instances'](instance_id=instance_id, region=region,
                                                    key=key, keyid=keyid, profile=profile,
                                                    return_objs=True, filters=filters)
    if not instances:
        ret['result'] = True
        ret['comment'] = 'Instance {0} is already gone.'.format(instance_id)
        return ret
    instance = instances[0]

    ### Honor 'disableApiTermination' - if you want to override it, first use set_attribute() to turn it off
    no_can_do = __salt__['boto_ec2.get_attribute']('disableApiTermination', instance_id=instance_id,
                                                   region=region, key=key, keyid=keyid, profile=profile)
    if no_can_do.get('disableApiTermination') is True:
        ret['result'] = False
        ret['comment'] = 'Termination of instance {0} via the API is disabled.'.format(instance_id)
        return ret

    if __opts__['test']:
        ret['comment'] = 'The instance {0} is set to be deleted.'.format(name)
        ret['result'] = None
        return ret

    r = __salt__['boto_ec2.terminate'](instance_id=instance_id, name=instance_name, region=region,
                                       key=key, keyid=keyid, profile=profile)
    if not r:
        ret['result'] = False
        ret['comment'] = 'Failed to terminate instance {0}.'.format(instance_id)
        return ret

    ret['changes']['old'] = {'instance_id': instance_id}
    ret['changes']['new'] = None

    if release_eip:
        ip = getattr(instance, 'ip_address', None)
        if ip:
            base_args = {'region': region, 'key': key, 'keyid': keyid, 'profile': profile}
            public_ip = None
            alloc_id = None
            assoc_id = None
            if getattr(instance, 'vpc_id', None):
                r = __salt__['boto_ec2.get_eip_address_info'](addresses=ip, **base_args)
                if r and 'allocation_id' in r[0]:
                    alloc_id = r[0]['allocation_id']
                    assoc_id = r[0].get('association_id')
                else:
                    # I /believe/ this situation is impossible but let's hedge our bets...
                    ret['result'] = False
                    ret['comment'] = "Can't determine AllocationId for address {0}.".format(ip)
                    return ret
            else:
                public_ip = instance.ip_address

            if assoc_id:
                # Race here - sometimes the terminate above will already have dropped this
                if not __salt__['boto_ec2.disassociate_eip_address'](association_id=assoc_id,
                                                                     **base_args):
                    log.warning("Failed to disassociate EIP %s.", ip)

            if __salt__['boto_ec2.release_eip_address'](allocation_id=alloc_id, public_ip=public_ip,
                                                        **base_args):
                log.info("Released EIP address %s", public_ip or r[0]['public_ip'])
                ret['changes']['old']['public_ip'] = public_ip or r[0]['public_ip']
            else:
                ret['result'] = False
                ret['comment'] = "Failed to release EIP {0}.".format(ip)
                return ret

    return ret