def join(self, request): '''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 = request.options.get('values', {}) # determine new system role oldrole = orgValues.get('server/role', '') newrole = values.get('server/role', oldrole) if newrole == 'basesystem' or orgValues.get('joined'): raise Exception( _('Base systems and already joined systems cannot be joined.') ) def _thread(request, 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.pre_save(values, orgValues) # 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, username, password ) # done :) self._finishedResult = True # we should do a cleanup now self._cleanup_required = True return True finally: obj._finishedLock.release() def _finished( thread, result ): if isinstance( result, BaseException ): MODULE.warn( 'Exception during saving the settings: %s' % str( result ) ) thread = notifier.threads.Simple( 'save', notifier.Callback( _thread, request, self, request.options.get('username'), request.options.get('password')),_finished ) thread.run() self.finished(request.id, True)
def save(self, request): '''Reconfigures 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 = request.options.get('values', {}) def _thread(request, obj): # 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 orgValues = util.load_values() util.pre_save(values, orgValues) MODULE.info('saving profile values') util.write_profile(values) if not values: MODULE.error('No property "values" given for save().') return False # in case of changes of the IP address, restart UMC server and web server # for this we ignore changes of virtual or non-default devices MODULE.info('Check whether ip addresses have been changed') restart = False for ikey, ival in values.iteritems(): if RE_IPV4.match(ikey) or RE_IPV6_DEFAULT.match( ikey) or RE_SSL.match(ikey): restart = True break MODULE.info('Restart servers: %s' % restart) # on a joined system or on a basesystem, we can run the setup scripts MODULE.info('runnning system setup scripts') util.run_scripts(self._progressParser, restart) # done :) self._finishedResult = True return True finally: obj._finishedLock.release() def _finished(thread, result): if isinstance(result, BaseException): MODULE.warn('Exception during saving the settings: %s' % str(result)) thread = notifier.threads.Simple( 'save', notifier.Callback(_thread, request, self), _finished) thread.run() self.finished(request.id, True)
def save(self, request): '''Reconfigures 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 = request.options.get('values', {}) def _thread(request, obj): # 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 orgValues = util.load_values() util.pre_save(values, orgValues) MODULE.info('saving profile values') util.write_profile(values) if not values: MODULE.error( 'No property "values" given for save().' ) return False # in case of changes of the IP address, restart UMC server and web server # for this we ignore changes of virtual or non-default devices MODULE.info('Check whether ip addresses have been changed') restart = False for ikey, ival in values.iteritems(): if RE_IPV4.match(ikey) or RE_IPV6_DEFAULT.match(ikey) or RE_SSL.match(ikey): restart = True break MODULE.info('Restart servers: %s' % restart) # on a joined system or on a basesystem, we can run the setup scripts MODULE.info('runnning system setup scripts') util.run_scripts( self._progressParser, restart ) # done :) self._finishedResult = True return True finally: obj._finishedLock.release() def _finished( thread, result ): if isinstance( result, BaseException ): MODULE.warn( 'Exception during saving the settings: %s' % str( result ) ) thread = notifier.threads.Simple( 'save', notifier.Callback( _thread, request, self ), _finished ) thread.run() self.finished(request.id, True)
def _thread(request, obj): # 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 orgValues = util.load_values() util.pre_save(values, orgValues) MODULE.info('saving profile values') util.write_profile(values) if not values: MODULE.error('No property "values" given for save().') return False # in case of changes of the IP address, restart UMC server and web server # for this we ignore changes of virtual or non-default devices MODULE.info('Check whether ip addresses have been changed') restart = False for ikey, ival in values.iteritems(): if RE_IPV4.match(ikey) or RE_IPV6_DEFAULT.match( ikey) or RE_SSL.match(ikey): restart = True break MODULE.info('Restart servers: %s' % restart) # on a joined system or on a basesystem, we can run the setup scripts MODULE.info('runnning system setup scripts') util.run_scripts(self._progressParser, restart) # done :) self._finishedResult = True return True finally: obj._finishedLock.release()
def _thread(request, obj): # 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 orgValues = util.load_values() util.pre_save(values, orgValues) MODULE.info('saving profile values') util.write_profile(values) if not values: MODULE.error( 'No property "values" given for save().' ) return False # in case of changes of the IP address, restart UMC server and web server # for this we ignore changes of virtual or non-default devices MODULE.info('Check whether ip addresses have been changed') restart = False for ikey, ival in values.iteritems(): if RE_IPV4.match(ikey) or RE_IPV6_DEFAULT.match(ikey) or RE_SSL.match(ikey): restart = True break MODULE.info('Restart servers: %s' % restart) # on a joined system or on a basesystem, we can run the setup scripts MODULE.info('runnning system setup scripts') util.run_scripts( self._progressParser, restart ) # done :) self._finishedResult = True return True finally: obj._finishedLock.release()
def validate(self, request): '''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 = request.options.get('values', {}) orgValues = util.load_values() # determine new system role newrole = values.get('server/role', orgValues.get('server/role','')) # 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): messages.append({ 'key': key, 'valid': False, 'message': message }) # system role _check('server/role', lambda x: not(orgValues.get('joined')) or (orgValues.get('server/role') == values.get('server/role')), _('The system role may not change on a system that has already joined to domain.')) # basis components = RE_SPACE.split(values.get('components', '')) packages = set(reduce(lambda x, y: x + y, [ i.split(':') for i in components ])) _check('hostname', util.is_hostname, _('The hostname is not a valid fully qualified domain name in lowercase (e.g. host.example.com).')) _check('hostname', lambda x: len(x) <= 13, _('A valid NetBIOS name can not be longer than 13 characters. If Samba is installed, the hostname should be shortened.'), critical=('univention-samba' in packages or 'univention-samba4' in packages)) _check('domainname', util.is_domainname, _("Please enter a valid fully qualified domain name in lowercase (e.g. host.example.com).")) hostname = allValues.get('hostname') domainname = allValues.get('domainname') if len(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.")) _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) < 14, _("The length of the windows domain name needs to be smaller than 14 characters.")) _check('windows/domain', util.is_windowsdomainname, _("The windows domain name is not valid.")) _check('ldap/base', lambda x: x.find(' ') == -1, _("The LDAP base may not contain any blanks (e.g., dc=test,dc=net).")) _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 for ikey, iname in [('ssl/state', _('State')), ('ssl/locality', _('Location'))]: _check(ikey, lambda x: len(x) <= 128, _('The following value is too long, only 128 characters allowed: %s') % iname) for ikey, iname in [('ssl/organization', _('Organization')), ('ssl/organizationalunit', _('Business unit')), ('ssl/email', _('Email address'))]: _check(ikey, lambda x: len(x) <= 64, _('The following value is too long, only 64 characters allowed: %s') % iname) _check('ssl/email', lambda x: x.find('@') >= 0, _("Please enter a valid email address")) # net # validate all ipv4 addresses and there netmask checkedIpv4 = set() for ikey, ival in values.iteritems(): if not ival: continue m = RE_IPV4.match(ikey) if m: # get the parts iname, idev, ivirt, itype = m.groups() # have we already tested this device? addressKey = 'interfaces/%s/address' % iname maskKey = 'interfaces/%s/netmask' % iname if addressKey in checkedIpv4: continue checkedIpv4.add(addressKey) # make sure that address and netmask are correct virtStr = '' if ivirt: virtStr = _(' (virtual)') if not util.is_ipv4addr(allValues.get(addressKey)): _append(addressKey, _('IPv4 address is not valid [%s%s]: "%s"') % (idev, virtStr, allValues.get(addressKey))) elif not allValues.get(maskKey) or not util.is_ipv4netmask('%s/%s' % (allValues.get(addressKey), allValues.get(maskKey))): _append(maskKey, _('IPv4 netmask is not valid [%s%s]: "%s"') % (idev, virtStr, allValues.get(maskKey, ''))) # validate all ipv6 addresses, their prefix, and identifier checkedIpv6 = set() for ikey, ival in values.iteritems(): if not ival: continue m = RE_IPV6.match(ikey) if m: # get the parts idev, iid, itype = m.groups() # have we already tested this device? addressKey = 'interfaces/%s/ipv6/%s/address' % (idev, iid) prefixKey = 'interfaces/%s/ipv6/%s/prefix' % (idev, iid) if addressKey in checkedIpv6: continue checkedIpv6.add(addressKey) # make sure that the ID is correct if not RE_IPV6_ID.match(iid): _append(addressKey, _('The specified IPv6 identifier may only consist of letters and numbers: %s') % iid) # make sure that address and prefix are correct if not util.is_ipv6addr(allValues.get(addressKey)): _append(addressKey, _('IPv6 address is not valid [%s]: %s') % (idev, allValues.get(addressKey))) if not allValues.get(prefixKey) or not util.is_ipv6netmask('%s/%s' % (allValues.get(addressKey), allValues.get(prefixKey))): _append(prefixKey, _('IPv6 prefix is not valid [%s]: %s') % (idev, allValues.get(prefixKey, ''))) # 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 (%s) is not valid: %s') % (iname, jval)) # 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', '')) # check global network settings isSetIpv4 = False ipv4HasAddress = False ipv4HasDynamic = False devIpv4VirtualDevices = set() isSetIpv6 = False ipv6HasAddress = False hasIpv6DefaultDevices = True ipv6HasDynamic = False tmpUCR = univention.config_registry.ConfigRegistry() devIpv6HasDefaultID = {} for ikey, ival in allValues.iteritems(): m = RE_IPV6_ADDRESS.match(ikey) if m: idev, iid = m.groups() # see whether the device is in the dict if idev not in devIpv6HasDefaultID: devIpv6HasDefaultID[idev] = False # identifier 'default' devIpv6HasDefaultID[idev] |= (iid == 'default') # ipv6 address ipv6HasAddress |= util.is_ipv6addr(ival) # ipv4 address if RE_IPV4_ADDRESS.match(ikey): ipv4HasAddress |= util.is_ipv4addr(ival) # dynamic ipv4 ipv4HasDynamic |= bool(RE_IPV4_DYNAMIC.match(ikey) and ival in ('dynamic', 'dhcp')) # dynamic ipv6 if RE_IPV6_DYNAMIC.match(ikey): tmpUCR[ikey] = ival; if tmpUCR.is_true(ikey): ipv6HasDynamic = True # ipv6 configuration if RE_IPV6.match(ikey) and ival: isSetIpv6 = True # ipv4 configuration m = RE_IPV4.match(ikey) if m and ival: isSetIpv4 = True # check whether this entry is a virtual device idev, ivirt = m.groups()[1:3] if ivirt: devIpv4VirtualDevices.add(idev) # check whether all virtual devices have a real device that is defined for idev in devIpv4VirtualDevices: mask = allValues.get('interfaces/%s/netmask' % idev) address = allValues.get('interfaces/%s/address' % idev) if not mask or not address or not util.is_ipv4netmask('%s/%s' % (address, mask)): _append('interfaces/%s/address' % idev, _('A virtual device cannot be specified alone: %s') % idev) break # check whether all devices have a default entry for idev, iset in devIpv6HasDefaultID.iteritems(): hasIpv6DefaultDevices &= iset # global checks if not (isSetIpv4 or ipv4HasDynamic) and not (isSetIpv6 or ipv6HasDynamic): _append('interfaces/eth0/address', _('At least one network device (either IPv4 or IPv6) needs to be configured.')) if isSetIpv6 and not hasIpv6DefaultDevices: _append('interfaces/eth0/ipv6/default/address', _('A default entry with the identifier "default" needs to be specified for each network device.')) if newrole in ['domaincontroller_master', 'domaincontroller_backup', 'domaincontroller_slave', 'memberserver'] and isSetIpv4 and not ipv4HasAddress: _append('interfaces/eth0/address', _('At least one IPv4 address needs to be specified.')) if not ipv4HasDynamic and not ipv6HasDynamic and not allValues.get('nameserver1') and not allValues.get('nameserver2') and not allValues.get('nameserver3'): _append('nameserver1', _('At least one domain name server needs to be given if DHCP or SLAAC is not specified.')) # 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.')) self.finished(request.id, messages)
def load(self, request): '''Return a dict with all necessary values for system-setup read from the current status of the system.''' values = util.load_values() self.finished(request.id, values)
def validate(self, request): '''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 = request.options.get('values', {}) orgValues = util.load_values() # determine new system role newrole = values.get('server/role', orgValues.get('server/role', '')) # 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): messages.append({'key': key, 'valid': False, 'message': message}) # system role _check( 'server/role', lambda x: not (orgValues.get('joined')) or (orgValues.get('server/role') == values.get('server/role')), _('The system role may not change on a system that has already joined to domain.' )) # basis components = RE_SPACE.split(values.get('components', '')) packages = set( reduce(lambda x, y: x + y, [i.split(':') for i in components])) _check( 'hostname', util.is_hostname, _('The hostname is not a valid fully qualified domain name in lowercase (e.g. host.example.com).' )) _check( 'hostname', lambda x: len(x) <= 13, _('A valid NetBIOS name can not be longer than 13 characters. If Samba is installed, the hostname should be shortened.' ), critical=('univention-samba' in packages or 'univention-samba4' in packages)) _check( 'domainname', util.is_domainname, _("Please enter a valid fully qualified domain name in lowercase (e.g. host.example.com)." )) hostname = allValues.get('hostname') domainname = allValues.get('domainname') if len(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.")) _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) < 14, _("The length of the windows domain name needs to be smaller than 14 characters." )) _check('windows/domain', util.is_windowsdomainname, _("The windows domain name is not valid.")) _check( 'ldap/base', lambda x: x.find(' ') == -1, _("The LDAP base may not contain any blanks (e.g., dc=test,dc=net)." )) _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 for ikey, iname in [('ssl/state', _('State')), ('ssl/locality', _('Location'))]: _check( ikey, lambda x: len(x) <= 128, _('The following value is too long, only 128 characters allowed: %s' ) % iname) for ikey, iname in [('ssl/organization', _('Organization')), ('ssl/organizationalunit', _('Business unit')), ('ssl/email', _('Email address'))]: _check( ikey, lambda x: len(x) <= 64, _('The following value is too long, only 64 characters allowed: %s' ) % iname) _check('ssl/email', lambda x: x.find('@') >= 0, _("Please enter a valid email address")) # net # validate all ipv4 addresses and there netmask checkedIpv4 = set() for ikey, ival in values.iteritems(): if not ival: continue m = RE_IPV4.match(ikey) if m: # get the parts iname, idev, ivirt, itype = m.groups() # have we already tested this device? addressKey = 'interfaces/%s/address' % iname maskKey = 'interfaces/%s/netmask' % iname if addressKey in checkedIpv4: continue checkedIpv4.add(addressKey) # make sure that address and netmask are correct virtStr = '' if ivirt: virtStr = _(' (virtual)') if not util.is_ipv4addr(allValues.get(addressKey)): _append( addressKey, _('IPv4 address is not valid [%s%s]: "%s"') % (idev, virtStr, allValues.get(addressKey))) elif not allValues.get(maskKey) or not util.is_ipv4netmask( '%s/%s' % (allValues.get(addressKey), allValues.get(maskKey))): _append( maskKey, _('IPv4 netmask is not valid [%s%s]: "%s"') % (idev, virtStr, allValues.get(maskKey, ''))) # validate all ipv6 addresses, their prefix, and identifier checkedIpv6 = set() for ikey, ival in values.iteritems(): if not ival: continue m = RE_IPV6.match(ikey) if m: # get the parts idev, iid, itype = m.groups() # have we already tested this device? addressKey = 'interfaces/%s/ipv6/%s/address' % (idev, iid) prefixKey = 'interfaces/%s/ipv6/%s/prefix' % (idev, iid) if addressKey in checkedIpv6: continue checkedIpv6.add(addressKey) # make sure that the ID is correct if not RE_IPV6_ID.match(iid): _append( addressKey, _('The specified IPv6 identifier may only consist of letters and numbers: %s' ) % iid) # make sure that address and prefix are correct if not util.is_ipv6addr(allValues.get(addressKey)): _append( addressKey, _('IPv6 address is not valid [%s]: %s') % (idev, allValues.get(addressKey))) if not allValues.get(prefixKey) or not util.is_ipv6netmask( '%s/%s' % (allValues.get(addressKey), allValues.get(prefixKey))): _append( prefixKey, _('IPv6 prefix is not valid [%s]: %s') % (idev, allValues.get(prefixKey, ''))) # 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 (%s) is not valid: %s') % (iname, jval)) # 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', '')) # check global network settings isSetIpv4 = False ipv4HasAddress = False ipv4HasDynamic = False devIpv4VirtualDevices = set() isSetIpv6 = False ipv6HasAddress = False hasIpv6DefaultDevices = True ipv6HasDynamic = False tmpUCR = univention.config_registry.ConfigRegistry() devIpv6HasDefaultID = {} for ikey, ival in allValues.iteritems(): m = RE_IPV6_ADDRESS.match(ikey) if m: idev, iid = m.groups() # see whether the device is in the dict if idev not in devIpv6HasDefaultID: devIpv6HasDefaultID[idev] = False # identifier 'default' devIpv6HasDefaultID[idev] |= (iid == 'default') # ipv6 address ipv6HasAddress |= util.is_ipv6addr(ival) # ipv4 address if RE_IPV4_ADDRESS.match(ikey): ipv4HasAddress |= util.is_ipv4addr(ival) # dynamic ipv4 ipv4HasDynamic |= bool( RE_IPV4_DYNAMIC.match(ikey) and ival in ('dynamic', 'dhcp')) # dynamic ipv6 if RE_IPV6_DYNAMIC.match(ikey): tmpUCR[ikey] = ival if tmpUCR.is_true(ikey): ipv6HasDynamic = True # ipv6 configuration if RE_IPV6.match(ikey) and ival: isSetIpv6 = True # ipv4 configuration m = RE_IPV4.match(ikey) if m and ival: isSetIpv4 = True # check whether this entry is a virtual device idev, ivirt = m.groups()[1:3] if ivirt: devIpv4VirtualDevices.add(idev) # check whether all virtual devices have a real device that is defined for idev in devIpv4VirtualDevices: mask = allValues.get('interfaces/%s/netmask' % idev) address = allValues.get('interfaces/%s/address' % idev) if not mask or not address or not util.is_ipv4netmask( '%s/%s' % (address, mask)): _append( 'interfaces/%s/address' % idev, _('A virtual device cannot be specified alone: %s') % idev) break # check whether all devices have a default entry for idev, iset in devIpv6HasDefaultID.iteritems(): hasIpv6DefaultDevices &= iset # global checks if not (isSetIpv4 or ipv4HasDynamic) and not (isSetIpv6 or ipv6HasDynamic): _append( 'interfaces/eth0/address', _('At least one network device (either IPv4 or IPv6) needs to be configured.' )) if isSetIpv6 and not hasIpv6DefaultDevices: _append( 'interfaces/eth0/ipv6/default/address', _('A default entry with the identifier "default" needs to be specified for each network device.' )) if newrole in [ 'domaincontroller_master', 'domaincontroller_backup', 'domaincontroller_slave', 'memberserver' ] and isSetIpv4 and not ipv4HasAddress: _append('interfaces/eth0/address', _('At least one IPv4 address needs to be specified.')) if not ipv4HasDynamic and not ipv6HasDynamic and not allValues.get( 'nameserver1') and not allValues.get( 'nameserver2') and not allValues.get('nameserver3'): _append( 'nameserver1', _('At least one domain name server needs to be given if DHCP or SLAAC is not specified.' )) # 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.' )) self.finished(request.id, messages)
def join(self, request): '''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 = request.options.get('values', {}) # determine new system role oldrole = orgValues.get('server/role', '') newrole = values.get('server/role', oldrole) if newrole == 'basesystem' or orgValues.get('joined'): raise Exception( _('Base systems and already joined systems cannot be joined.')) def _thread(request, 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.pre_save(values, orgValues) # 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, username, password) # done :) self._finishedResult = True # we should do a cleanup now self._cleanup_required = True return True finally: obj._finishedLock.release() def _finished(thread, result): if isinstance(result, BaseException): MODULE.warn('Exception during saving the settings: %s' % str(result)) thread = notifier.threads.Simple( 'save', notifier.Callback(_thread, request, self, request.options.get('username'), request.options.get('password')), _finished) thread.run() self.finished(request.id, True)
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).' )) _check( 'hostname', lambda x: len(x) <= 13, _('A valid NetBIOS name can not be longer than 13 characters. If Samba is installed, the hostname should be shortened.' ), critical=(ad_member or 'univention-samba' in packages or 'univention-samba4' in packages)) _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 }) def guess_domain(obj): 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: return guessed_domain 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() for obj in [values, ucr]: guessed_domain = guess_domain(obj) if guessed_domain: # communicate guessed domainname to frontend messages.append({ 'valid': True, 'key': 'domainname', 'value': guessed_domain, }) break else: 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
def join(self, values=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, 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): MODULE.warn('Exception during saving the settings: %s\n%s' % (result, ''.join( traceback.format_exception(*thread.exc_info)))) 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
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)