def valid_hacluster_config():
    '''
    Check that either vip or dns-ha is set. If dns-ha then one of os-*-hostname
    must be set.

    Note: ha-bindiface and ha-macastport both have defaults and will always
    be set. We only care that either vip or dns-ha is set.

    :returns: boolean: valid config returns true.
    raises: HAIncompatibileConfig if settings conflict.
    raises: HAIncompleteConfig if settings are missing.
    '''
    vip = config_get('vip')
    dns = config_get('dns-ha')
    if not(bool(vip) ^ bool(dns)):
        msg = ('HA: Either vip or dns-ha must be set but not both in order to '
               'use high availability')
        status_set('blocked', msg)
        raise HAIncorrectConfig(msg)

    # If dns-ha then one of os-*-hostname must be set
    if dns:
        dns_settings = ['os-internal-hostname', 'os-admin-hostname',
                        'os-public-hostname', 'os-access-hostname']
        # At this point it is unknown if one or all of the possible
        # network spaces are in HA. Validate at least one is set which is
        # the minimum required.
        for setting in dns_settings:
            if config_get(setting):
                log('DNS HA: At least one hostname is set {}: {}'
                    ''.format(setting, config_get(setting)),
                    level=DEBUG)
                return True

        msg = ('DNS HA: At least one os-*-hostname(s) must be set to use '
               'DNS HA')
        status_set('blocked', msg)
        raise HAIncompleteConfig(msg)

    log('VIP HA: VIP is set {}'.format(vip), level=DEBUG)
    return True
Check that either vip or dns-ha is set. If dns-ha then one of os-*-hostname
    must be set.

    Note: ha-bindiface and ha-macastport both have defaults and will always
    be set. We only care that either vip or dns-ha is set.

    :returns: boolean: valid config returns true.
    raises: HAIncompatibileConfig if settings conflict.
    raises: HAIncompleteConfig if settings are missing.