Execute a command and read the output as YAML

def ext_pillar(minion_id,
               pillar,  # pylint: disable=W0613
               use_grain=False,
               minion_ids=None,
               tag_match_key=None,
               tag_match_value='asis',
               tag_list_key=None,
               tag_list_sep=';'):
    '''
    Execute a command and read the output as YAML
    '''
    valid_tag_match_value = ['uqdn', 'asis']

    # meta-data:instance-id
    grain_instance_id = __grains__.get('meta-data', {}).get('instance-id', None)
    if not grain_instance_id:
        # dynamic:instance-identity:document:instanceId
        grain_instance_id = \
            __grains__.get('dynamic', {}).get('instance-identity', {}).get('document', {}).get('instance-id', None)
    if grain_instance_id and re.search(r'^i-([0-9a-z]{17}|[0-9a-z]{8})$', grain_instance_id) is None:
        log.error('External pillar %s, instance-id \'%s\' is not valid for '
                  '\'%s\'', __name__, grain_instance_id, minion_id)
        grain_instance_id = None  # invalid instance id found, remove it from use.

    # Check AWS Tag restrictions .i.e. letters, spaces, and numbers and + - = . _ : / @
    if tag_match_key and re.match(r'[\w=.:/@-]+$', tag_match_key) is None:
        log.error('External pillar %s, tag_match_key \'%s\' is not valid ',
                  __name__, tag_match_key if isinstance(tag_match_key, six.text_type) else 'non-string')
        return {}

    if tag_match_key and tag_match_value not in valid_tag_match_value:
        log.error('External pillar %s, tag_value \'%s\' is not valid must be one '
                  'of %s', __name__, tag_match_value, ' '.join(valid_tag_match_value))
        return {}

    if not tag_match_key:
        base_msg = ('External pillar %s, querying EC2 tags for minion id \'%s\' '
                    'against instance-id', __name__, minion_id)
    else:
        base_msg = ('External pillar %s, querying EC2 tags for minion id \'%s\' '
                    'against instance-id or \'%s\' against \'%s\'', __name__, minion_id, tag_match_key, tag_match_value)

    log.debug(base_msg)
    find_filter = None
    find_id = None

    if re.search(r'^i-([0-9a-z]{17}|[0-9a-z]{8})$', minion_id) is not None:
        find_filter = None
        find_id = minion_id
    elif tag_match_key:
        if tag_match_value == 'uqdn':
            find_filter = {'tag:{0}'.format(tag_match_key): minion_id.split('.', 1)[0]}
        else:
            find_filter = {'tag:{0}'.format(tag_match_key): minion_id}
        if grain_instance_id:
            # we have an untrusted grain_instance_id, use it to narrow the search
            # even more. Combination will be unique even if uqdn is set.
            find_filter.update({'instance-id': grain_instance_id})
        # Add this if running state is not dependant on EC2Config
        # find_filter.update('instance-state-name': 'running')

    # no minion-id is instance-id and no suitable filter, try use_grain if enabled
    if not find_filter and not find_id and use_grain:
        if not grain_instance_id:
            log.debug('Minion-id is not in AWS instance-id formation, and there '
                      'is no instance-id grain for minion %s', minion_id)
            return {}
        if minion_ids is not None and minion_id not in minion_ids:
            log.debug('Minion-id is not in AWS instance ID format, and minion_ids '
                      'is set in the ec2_pillar configuration, but minion %s is '
                      'not in the list of allowed minions %s', minion_id, minion_ids)
            return {}
        find_id = grain_instance_id

    if not (find_filter or find_id):
        log.debug('External pillar %s, querying EC2 tags for minion id \'%s\' against '
                  'instance-id or \'%s\' against \'%s\' noughthing to match against',
                  __name__, minion_id, tag_match_key, tag_match_value)
        return {}

    myself = boto.utils.get_instance_metadata(timeout=0.1, num_retries=1)
    if not myself:
        log.info("%s: salt master not an EC2 instance, skipping", __name__)
        return {}

    # Get the Master's instance info, primarily the region
    (_, region) = _get_instance_info()

    # If the Minion's region is available, use it instead
    if use_grain:
        region = __grains__.get('ec2', {}).get('region', region)

    try:
        conn = boto.ec2.connect_to_region(region)
    except boto.exception.AWSConnectionError as exc:
        log.error('%s: invalid AWS credentials, %s', __name__, exc)
        return {}

    if conn is None:
        log.error('%s: Could not connect to region %s', __name__, region)
        return {}

    try:
        if find_id:
            instance_data = conn.get_only_instances(instance_ids=[find_id], dry_run=False)
        else:
            # filters and max_results can not be used togther.
            instance_data = conn.get_only_instances(filters=find_filter, dry_run=False)

    except boto.exception.EC2ResponseError as exc:
        log.error('%s failed with \'%s\'', base_msg, exc)
        return {}

    if not instance_data:
        log.debug('%s no match using \'%s\'', base_msg, find_id if find_id else find_filter)
        return {}

    # Find a active instance, i.e. ignore terminated and stopped instances
    active_inst = []
    for inst in range(0, len(instance_data)):
        if instance_data[inst].state not in ['terminated', 'stopped']:
            active_inst.append(inst)

    valid_inst = len(active_inst)
    if not valid_inst:
        log.debug('%s match found but not active \'%s\'', base_msg, find_id if find_id else find_filter)
        return {}

    if valid_inst > 1:
        log.error('%s multiple matches, ignored, using \'%s\'', base_msg, find_id if find_id else find_filter)
        return {}

    instance = instance_data[active_inst[0]]
    if instance.tags:
        ec2_tags = instance.tags
        ec2_tags_list = {}
        log.debug('External pillar %s, for minion id \'%s\', tags: %s', __name__, minion_id, instance.tags)
        if tag_list_key and isinstance(tag_list_key, list):
            for item in tag_list_key:
                if item in ec2_tags:
                    ec2_tags_list[item] = ec2_tags[item].split(tag_list_sep)
                    del ec2_tags[item]  # make sure its only in ec2_tags_list
                else:
                    ec2_tags_list[item] = []  # always return a result

        return {'ec2_tags': ec2_tags, 'ec2_tags_list': ec2_tags_list}
    return {}