Example #1
0
	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)
Example #2
0
    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)
Example #3
0
	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)
Example #4
0
        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()
Example #5
0
		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()
Example #6
0
	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)
Example #7
0
	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)
Example #8
0
    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)
Example #9
0
    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)
Example #10
0
    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, 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)