Esempio n. 1
0
    def join(self, values=None, dcname=None, username=None, password=None):
        '''Join and reconfigure the system according to the values specified in the dict given as
		option named "values".'''

        # get old and new values
        orgValues = util.load_values()
        values = values or {}

        # determine new system role
        oldrole = orgValues.get('server/role', '')
        newrole = values.get('server/role', oldrole)

        # create a status file that indicates that save has been triggered
        util.create_status_file()

        def _thread(obj, username, password):
            # acquire the lock until the scripts have been executed
            self._finishedResult = False
            obj._finishedLock.acquire()
            try:
                self._progressParser.reset()

                # write the profile file and run setup scripts
                util.auto_complete_values_for_join(values)

                # on unjoined DC master the nameserver must be set to the external nameserver
                if newrole == 'domaincontroller_master' and not orgValues.get(
                        'joined'):
                    for i in range(1, 4):
                        # overwrite these values only if they are set, because the UMC module
                        # will save only changed values
                        if values.get('dns/forwarder%d' % i):
                            values['nameserver%d' % i] = values.get(
                                'dns/forwarder%d' % i)

                MODULE.info('saving profile values')
                util.write_profile(values)

                # unjoined DC master (that is not being converted to a basesystem) -> run the join script
                MODULE.info('runnning system setup join script')
                util.run_joinscript(self._progressParser,
                                    values,
                                    username,
                                    password,
                                    dcname,
                                    lang=str(self.locale))

                # done :)
                self._finishedResult = True

                return True
            finally:
                obj._finishedLock.release()

        def _finished(thread, result):
            if self.__keep_alive_request:
                self.finished(self.__keep_alive_request.id, None)
                self.__keep_alive_request = None

            if isinstance(result, BaseException):
                msg = ''.join(thread.trace + traceback.format_exception_only(
                    *thread.exc_info[:2]))
                MODULE.warn('Exception during saving the settings: %s' %
                            (msg, ))
                self._progressParser.current.errors.append(
                    _('Encountered unexpected error during setup process: %s')
                    % (result, ))
                self._progressParser.current.critical = True
                self._finishedResult = True

        thread = notifier.threads.Simple(
            'join', notifier.Callback(_thread, self, username, password),
            _finished)
        thread.run()
        return
Esempio n. 2
0
    def validate(self, values=None, flavor=None):
        '''Validate the specified values given in the dict as option named "values".
		Return a dict (with variable names as key) of dicts with the structure:
		{ "valid": True/False, "message": "..." }'''

        # init variables
        messages = []
        values = values or {}
        orgValues = util.load_values()
        is_wizard_mode = flavor == 'wizard'

        # determine new system role
        newrole = values.get('server/role', orgValues.get('server/role', ''))
        ad_member = values.get('ad/member', orgValues.get('ad/member', ''))

        # mix original and new values
        allValues = copy.copy(values)
        for ikey, ival in orgValues.iteritems():
            if ikey not in allValues:
                allValues[ikey] = ival

        # helper functions
        # TODO: 'valid' is not correctly evaluated in frontend
        # i.e. if valid you may continue without getting message
        def _check(key, check, message, critical=True):
            if key not in values:
                return
            if not check(values[key]):
                messages.append({
                    'message': message,
                    'valid': not critical,
                    'key': key
                })

        def _append(key, message):
            MODULE.warn('Validation failed for key %s: %s' % (key, message))
            messages.append({'key': key, 'valid': False, 'message': message})

        # host and domain name
        packages = set(values.get('components', []))
        _check(
            'hostname', util.is_hostname,
            _('The hostname or the hostname part of the fully qualified domain name is invalid. Please go back to the host setting and make sure, that the hostname only contains letter (a-zA-Z) and digits (0-9).'
              ))

        hostname_length_critical = ad_member or 'univention-samba' in packages or 'univention-samba4' in packages
        appliance_str = _('the UCS system')
        if ucr['umc/web/appliance/name']:
            appliance_str = _('the %s appliance') % (
                ucr['umc/web/appliance/name'], )
        hostname_length_message = _(
            'A valid NetBIOS name can not be longer than 13 characters. If Samba is installed, the hostname should be shortened.'
        ) if hostname_length_critical else _(
            'The hostname %s is longer than 13 characters. It will not be possible to install an Active Directory compatible Domaincontroller (Samba 4) or UCS@school. The hostname cannot be changed after the installation of %s. It is recommended to shorten the hostname to maximal 13 characters.'
        ) % (
            values.get('hostname', ''),
            appliance_str,
        )
        _check('hostname',
               lambda x: len(x) <= 13,
               hostname_length_message,
               critical=hostname_length_critical)

        _check(
            'domainname', util.is_domainname,
            _("Please enter a valid fully qualified domain name (e.g. host.example.com)."
              ))
        hostname = allValues.get('hostname', '')
        domainname = allValues.get('domainname', '')
        if hostname or domainname:
            if len('%s%s' % (hostname, domainname)) >= 63:
                _append(
                    'domainname',
                    _('The length of fully qualified domain name is greater than 63 characters.'
                      ))
            if hostname == domainname.split('.')[0]:
                _append('domainname', _("Hostname is equal to domain name."))
        if is_wizard_mode and not util.is_system_joined():
            if newrole == 'domaincontroller_master' and not values.get(
                    'domainname'):
                _append(
                    'domainname',
                    _("No fully qualified domain name has been specified for the system."
                      ))
            elif not values.get('hostname'):
                _append('hostname',
                        _("No hostname has been specified for the system."))

        # windows domain
        _check(
            'windows/domain', lambda x: x == x.upper(),
            _("The windows domain name can only consist of upper case characters."
              ))
        _check(
            'windows/domain', lambda x: len(x) <= 15,
            _("The windows domain name cannot be longer than 15 characters."))
        _check('windows/domain', util.is_windowsdomainname,
               _("The windows domain name is not valid."))

        # LDAP base
        _check(
            'ldap/base', util.is_ldap_base,
            _("The LDAP base may neither contain blanks nor any special characters. Its structure needs to consist of at least two relative distinguished names (RDN) which may only use the attribute tags 'dc', 'cn', 'c', 'o', or 'l' (e.g., dc=test,dc=net)."
              ))

        # root password
        _check(
            'root_password', lambda x: len(x) >= 8,
            _("The root password is too short. For security reasons, your password must contain at least 8 characters."
              ))
        _check('root_password', util.is_ascii,
               _("The root password may only contain ascii characters."))

        # ssl + email
        labels = {
            'ssl/country': _('Country'),
            'ssl/state': _('State'),
            'ssl/locality': _('Location'),
            'ssl/organization': _('Organization'),
            'organization': _('Organization'),
            'ssl/organizationalunit': _('Business unit'),
            'ssl/email': _('Email address'),
            'email_address': _('Email address'),
            'ssl/common': _('Common name for the root SSL certificate'),
        }
        for maxlenth, keys in [
            (2, ('ssl/country', )), (128, (
                'ssl/state',
                'ssl/locality',
            )),
            (64, ('organization', 'ssl/organization', 'ssl/organizationalunit',
                  'ssl/email', 'email_address', 'ssl/common'))
        ]:
            for ikey in keys:
                _check(
                    ikey, lambda x: len(x) <= maxlenth,
                    _('The following value is too long, only %(max)s characters allowed: %(name)s'
                      ) % {
                          'max': maxlenth,
                          'name': labels[ikey]
                      })

        for ikey in ('ssl/country', 'ssl/state', 'ssl/locality',
                     'ssl/organization', 'ssl/organizationalunit', 'ssl/email',
                     'ssl/common'):
            for table in (stringprep.in_table_c21_c22, stringprep.in_table_a1,
                          stringprep.in_table_c8, stringprep.in_table_c3,
                          stringprep.in_table_c4, stringprep.in_table_c5,
                          lambda c: c == u'\ufffd'):
                _check(
                    ikey, lambda x: not any(map(table, unicode(x))),
                    _('The value for %s contains invalid characters.') %
                    (labels[ikey], ))

        _check('ssl/country', lambda x: len(x) == 2,
               _('Country must be a country code consisting of 2 characters.'))
        for ikey in ['ssl/email', 'email_address']:
            _check(ikey, lambda x: x.find('@') > 0,
                   _("Please enter a valid email address"))

        # net
        try:
            interfaces = network.Interfaces()
            interfaces.from_dict(allValues.get('interfaces', {}))
            interfaces.check_consistency()
        except network.DeviceError as exc:
            _append('interfaces', str(exc))

        # validate the primary network interface
        _check('interfaces/primary', lambda x: not x or x in interfaces,
               _('The primary network device must exist.'))

        # check nameservers
        for ikey, iname in [('nameserver[1-3]', _('Domain name server')),
                            ('dns/forwarder[1-3]', _('External name server'))]:
            reg = re.compile('^(%s)$' % ikey)
            for jkey, jval in values.iteritems():
                if reg.match(jkey):
                    if not values.get(jkey):
                        # allow empty value
                        continue
                    _check(
                        jkey, util.is_ipaddr,
                        _('The specified IP address (%(name)s) is not valid: %(value)s'
                          ) % {
                              'name': iname,
                              'value': jval
                          })

        if is_wizard_mode and not util.is_system_joined() and (
                newrole not in ['domaincontroller_master', 'basesystem']
                or ad_member):
            if all(nameserver in values and not values[nameserver]
                   for nameserver in ('nameserver1', 'nameserver2',
                                      'nameserver3')):
                # 'nameserver1'-key exists → widget is displayed → = not in UCS/debian installer mode
                if not any(interface.ip4dynamic or interface.ip6dynamic
                           for interface in interfaces.values()):
                    _append('nameserver1',
                            _('A domain name server needs to be specified.'))
                    # _append('nameserver1', _('At least one domain name server needs to be given if DHCP or SLAAC is not specified.'))

            # see whether the domain can be determined automatically
            ucr.load()
            guessed_domain = None
            for obj in [values, ucr]:
                for nameserver in ('nameserver1', 'nameserver2',
                                   'nameserver3'):
                    nameserver = obj.get(nameserver)
                    if nameserver:
                        guessed_domain = None
                        if obj.get('ad/member') and obj.get('ad/address'):
                            try:
                                ad_domain_info = lookup_adds_dc(
                                    obj.get('ad/address'),
                                    ucr={'nameserver1': nameserver})
                            except failedADConnect:
                                pass
                            else:
                                guessed_domain = ad_domain_info['Domain']
                        else:
                            guessed_domain = util.get_ucs_domain(nameserver)
                        if guessed_domain:
                            differing_domain_name = values.get(
                                'domainname') and values['domainname'].lower(
                                ) != guessed_domain.lower()
                            if differing_domain_name:
                                _append(
                                    'domainname',
                                    _('The specified domain name is different to the %s domain name found via the configured DNS server: %s'
                                      ) % (
                                          _('Active Directory')
                                          if ad_member else _('UCS'),
                                          guessed_domain,
                                      ))
                            else:
                                # communicate guessed domainname to frontend
                                messages.append({
                                    'valid': True,
                                    'key': 'domainname',
                                    'value': guessed_domain,
                                })
                            break
                if guessed_domain:
                    break
            if not guessed_domain:
                if not values.get('domainname'):
                    _append(
                        'domainname',
                        _('Cannot automatically determine the domain. Please specify the server\'s fully qualified domain name.'
                          ))

                if values.get('nameserver1') and values.get('start/join'):
                    _append(
                        'nameserver1',
                        _('The specified nameserver %s is not part of a valid UCS domain.'
                          ) % (values['nameserver1'], ))

        # check gateways
        if values.get('gateway'):  # allow empty value
            _check(
                'gateway', util.is_ipv4addr,
                _('The specified gateway IPv4 address is not valid: %s') %
                values.get('gateway'))
        if values.get('ipv6/gateway'):  # allow empty value
            _check(
                'ipv6/gateway', util.is_ipv6addr,
                _('The specified gateway IPv6 address is not valid: %s') %
                values.get('ipv6/gateway'))

        # proxy
        _check(
            'proxy/http', util.is_proxy,
            _('The specified proxy address is not valid (e.g., http://10.201.1.1:8080): %s'
              ) % allValues.get('proxy/http', ''))

        # software checks
        if 'univention-virtual-machine-manager-node-kvm' in packages and 'univention-virtual-machine-manager-node-xen' in packages:
            _append(
                'components',
                _('It is not possible to install KVM and XEN components on one system. Please select only one of these components.'
                  ))
        if 'univention-samba' in packages and 'univention-samba4' in packages:
            _append(
                'components',
                _('It is not possible to install Samba 3 and Samba 4 on one system. Please select only one of these components.'
                  ))

        return messages
Esempio n. 3
0
    def load(self):
        '''Return a dict with all necessary values for system-setup read from the current
		status of the system.'''
        return util.load_values(self.locale.language)