saltstack/salt

View on GitHub
salt/states/win_dns_client.py

Summary

Maintainability
F
4 days
Test Coverage
# -*- coding: utf-8 -*-
'''
Module for configuring DNS Client on Windows systems
'''
from __future__ import absolute_import, unicode_literals, print_function


def __virtual__():
    '''
    Load if the module win_dns_client is loaded
    '''
    return 'win_dns_client' if 'win_dns_client.add_dns' in __salt__ else False


def dns_exists(name, servers=None, interface='Local Area Connection', replace=False):
    '''
    Configure the DNS server list in the specified interface

    Example:

    .. code-block:: yaml

        config_dns_servers:
          win_dns_client.dns_exists:
            - replace: True #remove any servers not in the "servers" list, default is False
            - servers:
              - 8.8.8.8
              - 8.8.8.9
    '''
    ret = {'name': name,
           'result': True,
           'changes': {'Servers Reordered': [], 'Servers Added': [], 'Servers Removed': []},
           'comment': ''}

    if __opts__['test']:
        ret['comment'] = 'DNS Servers are set to be updated'
        ret['result'] = None
    else:
        ret['comment'] = 'DNS Servers have been updated'

    # Validate syntax
    if not isinstance(servers, list):
        ret['result'] = False
        ret['comment'] = 'servers entry is not a list !'
        return ret

    # Do nothing is already configured
    configured_list = __salt__['win_dns_client.get_dns_servers'](interface)
    if configured_list == servers:
        ret['comment'] = '{0} are already configured'.format(servers)
        ret['changes'] = {}
        ret['result'] = True
        return ret

    # add the DNS servers
    for i, server in enumerate(servers):
        if __opts__['test']:
            if server in configured_list:
                if configured_list.index(server) != i:
                    ret['changes']['Servers Reordered'].append(server)
            else:
                ret['changes']['Servers Added'].append(server)
        else:
            if not __salt__['win_dns_client.add_dns'](server, interface, i + 1):
                ret['comment'] = (
                        'Failed to add {0} as DNS server number {1}'
                        ).format(server, i + 1)
                ret['result'] = False
                ret['changes'] = {}
                return ret
            else:
                if server in configured_list:
                    if configured_list.index(server) != i:
                        ret['changes']['Servers Reordered'].append(server)
                else:
                    ret['changes']['Servers Added'].append(server)

    # remove dns servers that weren't in our list
    if replace:
        for i, server in enumerate(configured_list):
            if server not in servers:
                if __opts__['test']:
                    ret['changes']['Servers Removed'].append(server)
                else:
                    if not __salt__['win_dns_client.rm_dns'](server, interface):
                        ret['comment'] = (
                                'Failed to remove {0} from DNS server list').format(server)
                        ret['result'] = False
                        return ret
                    else:
                        ret['changes']['Servers Removed'].append(server)

    return ret


def dns_dhcp(name, interface='Local Area Connection'):
    '''
    Configure the DNS server list from DHCP Server
    '''
    ret = {'name': name,
           'result': True,
           'changes': {},
           'comment': ''}

    # Check the config
    config = __salt__['win_dns_client.get_dns_config'](interface)
    if config == 'dhcp':
        ret['comment'] = '{0} already configured with DNS from DHCP'.format(
                interface)
        return ret
    else:
        ret['changes'] = {'dns': 'configured from DHCP'}

    if __opts__['test']:
        ret['result'] = None
        return ret

    # change the configuration
    ret['result'] = __salt__['win_dns_client.dns_dhcp'](interface)
    if not ret['result']:
        ret['changes'] = {}
        ret['comment'] = (
                'Could not configure "{0}" DNS servers from DHCP'
                ).format(interface)

    return ret


def primary_suffix(name,
        suffix=None,
        updates=False):
    '''
    .. versionadded:: 2014.7.0

    Configure the global primary DNS suffix of a DHCP client.

    suffix : None
        The suffix which is advertised for this client when acquiring a DHCP lease
        When none is set, the explicitly configured DNS suffix will be removed.

    updates : False
        Allow syncing the DNS suffix with the AD domain when the client's AD domain membership changes

    .. code-block:: yaml

        primary_dns_suffix:
            win_dns_client.primary_suffix:
                - suffix: sub.domain.tld
                - updates: True
    '''

    ret = {
            'name': name,
            'changes': {},
            'result': True,
            'comment': 'No changes needed'
    }

    suffix = str(suffix)

    if not isinstance(updates, bool):
        ret['result'] = False
        ret['comment'] = '\'updates\' must be a boolean value'
        return ret

    # TODO: waiting for an implementation of
    # https://github.com/saltstack/salt/issues/6792 to be able to handle the
    # requirement for a reboot to actually apply this state.
    # Until then, this method will only be able to verify that the required
    # value has been written to the registry and rebooting needs to be handled
    # manually

    reg_data = {
            'suffix': {
                'hive': 'HKEY_LOCAL_MACHINE',
                'key': r'SYSTEM\CurrentControlSet\services\Tcpip\Parameters',
                'vname':  'NV Domain',
                'vtype': 'REG_SZ',
                'old':  None,
                'new':  suffix
            },
            'updates': {
                'hive': 'HKEY_LOCAL_MACHINE',
                'key': r'SYSTEM\CurrentControlSet\services\Tcpip\Parameters',
                'vname':  'SyncDomainWithMembership',
                'vtype': 'REG_DWORD',
                'old':  None,
                'new':  updates
            }
    }

    reg_data['suffix']['old'] = __utils__['reg.read_value'](
            reg_data['suffix']['hive'],
            reg_data['suffix']['key'],
            reg_data['suffix']['vname'],)['vdata']

    reg_data['updates']['old'] = bool(__utils__['reg.read_value'](
            reg_data['updates']['hive'],
            reg_data['updates']['key'],
            reg_data['updates']['vname'],)['vdata'])

    updates_operation = 'enabled' if reg_data['updates']['new'] else 'disabled'

    # No changes to suffix needed
    if reg_data['suffix']['new'] == reg_data['suffix']['old']:
        # No changes to updates policy needed
        if reg_data['updates']['new'] == reg_data['updates']['old']:
            return ret
        # Changes to update policy needed
        else:
            ret['comment'] = '{0} suffix updates'.format(updates_operation)
            ret['changes'] = {
                    'old': {
                        'updates': reg_data['updates']['old']},
                    'new': {
                        'updates': reg_data['updates']['new']}}
    # Changes to suffix needed
    else:
        # Changes to updates policy needed
        if reg_data['updates']['new'] != reg_data['updates']['old']:
            ret['comment'] = 'Updated primary DNS suffix ({0}) and {1} suffix updates'.format(suffix, updates_operation)
            ret['changes'] = {
                    'old': {
                        'suffix': reg_data['suffix']['old'],
                        'updates': reg_data['updates']['old']},
                    'new': {
                        'suffix': reg_data['suffix']['new'],
                        'updates': reg_data['updates']['new']}}
        # No changes to updates policy needed
        else:
            ret['comment'] = 'Updated primary DNS suffix ({0})'.format(suffix)
            ret['changes'] = {
                    'old': {
                        'suffix': reg_data['suffix']['old']},
                    'new': {
                        'suffix': reg_data['suffix']['new']}}

    suffix_result = __utils__['reg.set_value'](
            reg_data['suffix']['hive'],
            reg_data['suffix']['key'],
            reg_data['suffix']['vname'],
            reg_data['suffix']['new'],
            reg_data['suffix']['vtype'])

    updates_result = __utils__['reg.set_value'](
            reg_data['updates']['hive'],
            reg_data['updates']['key'],
            reg_data['updates']['vname'],
            reg_data['updates']['new'],
            reg_data['updates']['vtype'])

    ret['result'] = suffix_result & updates_result

    return ret