def users_remove(self, request): def _thread(request): partitions = [] success = True objects = [] # Determine different partitions for obj in request.options: partitions.append(obj['object'].split('@')[-1]) for partition in set(partitions): self._check_error(request, partition) # Remove user quota for obj in request.options: (unicode_user, partition) = obj['object'].split('@', 1) user = unicode_user.encode('utf-8') if tools.setquota(partition, user, 0, 0, 0, 0): objects.append({'id': obj['object'], 'success': False}) success = False else: objects.append({'id': obj['object'], 'success': True}) return {'objects': objects, 'success': success} thread = notifier.threads.Simple('Remove', notifier.Callback(_thread, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def users_set(self, request): def _thread(request): message = None success = True result = [] partition = request.options['partitionDevice'] unicode_user = request.options['user'] user = unicode_user.encode('utf-8') size_soft = request.options['sizeLimitSoft'] size_hard = request.options['sizeLimitHard'] file_soft = request.options['fileLimitSoft'] file_hard = request.options['fileLimitHard'] self._check_error(request, partition) failed = tools.setquota(partition, user, tools.byte2block(size_soft), tools.byte2block(size_hard), file_soft, file_hard) if failed: MODULE.error('Failed to modify quota settings for user %s ' 'on partition %s' % (user, partition)) message = _('Failed to modify quota settings for user %s on ' 'partition %s') % (user, partition) request.status = MODULE_ERR self.finished(request.id, None, message) message = _('Successfully set quota settings') return {'result': result, 'message': message, 'success': success} thread = notifier.threads.Simple( 'Set', notifier.Callback(_thread, request), notifier.Callback(self._thread_finished, request)) thread.run()
def stop(self, request): func = notifier.Callback(self._change_services, request.options, 'stop') thread = notifier.threads.Simple( 'services', func, notifier.Callback(self.thread_finished_callback, request)) thread.run()
def add(self, request): """Creates LDAP objects. requests.options = [ { 'options' : {}, 'object' : {} }, ... ] return: [ { '$dn$' : <LDAP DN>, 'success' : (True|False), 'details' : <message> }, ... ] """ def _thread(request): result = [] for obj in request.options: options = obj.get('options', {}) properties = obj.get('object', {}) module = self._get_module_by_request(request, object_type=options.get('objectType')) if '$labelObjectType$' in properties: del properties['$labelObjectType$'] try: dn = module.create(properties, container=options.get('container'), superordinate=options.get('superordinate')) result.append({'$dn$': dn, 'success': True}) except UDM_Error as e: result.append({'$dn$': e.dn, 'success': False, 'details': str(e)}) return result thread = notifier.threads.Simple('Get', notifier.Callback(_thread, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def put(self, request): """Modifies the given list of LDAP objects. requests.options = [ { 'options' : {}, 'object' : {} }, ... ] return: [ { '$dn$' : <LDAP DN>, 'success' : (True|False), 'details' : <message> }, ... ] """ def _thread(request): result = [] for obj in request.options: properties = obj.get('object') or {} ldap_dn = properties['$dn$'] module = get_module(request.flavor, ldap_dn) if module is None: if len(request.options) == 1: raise ObjectDoesNotExist(ldap_dn) result.append({'$dn$': ldap_dn, 'success': False, 'details': _('LDAP object does not exist.')}) continue MODULE.info('Modifying LDAP object %s' % (ldap_dn,)) if '$labelObjectType$' in properties: del properties['$labelObjectType$'] try: module.modify(properties) result.append({'$dn$': ldap_dn, 'success': True}) except UDM_Error as exc: result.append({'$dn$': ldap_dn, 'success': False, 'details': str(exc)}) return result thread = notifier.threads.Simple('Get', notifier.Callback(_thread, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def users_set(self, request): def _thread(request): partition = request.options['partitionDevice'] user = request.options['user'] if isinstance(user, unicode): user = user.encode('utf-8') size_soft = request.options['sizeLimitSoft'] size_hard = request.options['sizeLimitHard'] file_soft = request.options['fileLimitSoft'] file_hard = request.options['fileLimitHard'] self._check_error(request, partition) if tools.setquota(partition, user, tools.byte2block(size_soft), tools.byte2block(size_hard), file_soft, file_hard): raise UMC_Error( _('Failed to modify quota settings for user %(user)s on partition %(partition)s.' ) % { 'user': user, 'partition': partition }) return {'objects': [], 'success': True} thread = notifier.threads.Simple( 'Set', notifier.Callback(_thread, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def restart(self, request: 'Request') -> None: func = notifier.Callback(self._change_services, request.options, 'restart') thread = notifier.threads.Simple( 'services', func, notifier.Callback(self.thread_finished_callback, request)) thread.run()
def send(self, request): def _send_thread(sender, recipient, subject, message): MODULE.info('sending mail: thread running') # FIXME: contains header injection msg = u'From: ' + sender + u'\r\n' msg += u'To: ' + recipient + u'\r\n' msg += u'Subject: %s\r\n' % subject msg += u'\r\n' msg += message + u'\r\n' msg += u'\r\n' msg = msg.encode('latin1') server = smtplib.SMTP('localhost') server.set_debuglevel(0) server.sendmail(sender, recipient, msg) server.quit() return True func = notifier.Callback(_send_thread, request.options['sender'], request.options['recipient'], request.options['subject'], request.options['message']) MODULE.info('sending mail: starting thread') cb = notifier.Callback(self.thread_finished_callback, request) thread = notifier.threads.Simple('mailing', func, cb) thread.run()
def send(self, request): def _send_thread(sender, recipient, subject, message): MODULE.info('sending mail: thread running') msg = MIMENonMultipart('text', 'plain', charset='utf-8') cs = email.charset.Charset("utf-8") cs.body_encoding = email.charset.QP msg["Subject"] = subject msg["From"] = sender msg["To"] = recipient msg.set_payload(message, charset=cs) server = smtplib.SMTP('localhost') server.set_debuglevel(0) server.sendmail(sender, recipient, msg.as_string()) server.quit() return True func = notifier.Callback(_send_thread, request.options['sender'], request.options['recipient'], request.options['subject'], request.options['message']) MODULE.info('sending mail: starting thread') cb = notifier.Callback(self.thread_finished_callback, request) thread = notifier.threads.Simple('mailing', func, cb) thread.run()
def users_remove(self, request): def _thread(request): partitions = [] failed = [] # Determine different partitions for obj in request.options: partitions.append(obj['object'].split('@', 1)[-1]) for partition in set(partitions): self._check_error(request, partition) # Remove user quota for obj in request.options: (user, _, partition) = obj['object'].partition('@') if not isinstance(user, str): # Py2 user = user.encode('utf-8') if tools.setquota(partition, user, 0, 0, 0, 0): failed.append(user) if failed: raise UMC_Error( _('Could not remove the following user: %s') % ', '.join(failed)) thread = notifier.threads.Simple( 'Remove', notifier.Callback(_thread, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def users_remove(self, request): def _thread(request): partitions = [] message = None success = True result = [] # Determine different partitions for obj in request.options: partitions.append(obj['object'].split('@')[-1]) for partition in set(partitions): self._check_error(request, partition) # Remove user quota for obj in request.options: (unicode_user, partition) = obj['object'].split('@') user = unicode_user.encode('utf-8') failed = tools.setquota(partition, user, '0', '0', '0', '0') if failed: result.append({'id': obj['object'], 'success': False}) success = False else: result.append({'id': obj['object'], 'success': True}) if success: message = _('Successfully removed quota settings') return {'result': result, 'message': message, 'success': success} thread = notifier.threads.Simple( 'Remove', notifier.Callback(_thread, request), notifier.Callback(self._thread_finished, request)) thread.run()
def remove(self, request): """Removes the given list of LDAP objects. requests.options = [ { 'object' : <LDAP DN>, 'options' { 'cleanup' : (True|False), 'recursive' : (True|False) } }, ... ] return: [ { '$dn$' : <LDAP DN>, 'success' : (True|False), 'details' : <message> }, ... ] """ def _thread(request): result = [] for item in request.options: ldap_dn = item.get('object') options = item.get('options', {}) module = get_module(request.flavor, ldap_dn) if module is None: result.append({'$dn$': ldap_dn, 'success': False, 'details': _('LDAP object could not be identified')}) continue try: module.remove(ldap_dn, options.get('cleanup', False), options.get('recursive', False)) result.append({'$dn$': ldap_dn, 'success': True}) except UDM_Error as e: result.append({'$dn$': ldap_dn, 'success': False, 'details': str(e)}) return result thread = notifier.threads.Simple('Get', notifier.Callback(_thread, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def get(self, request): """Retrieves the given list of LDAP objects. Password property will be removed. requests.options = [ <LDAP DN>, ... ] return: [ { '$dn$' : <LDAP DN>, <object properties> }, ... ] """ MODULE.info('Starting thread for udm/get request') thread = notifier.threads.Simple('Get', notifier.Callback(self._get, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def handle_request_set_password(self, request): username = self._username password = request.options['password']['password'] new_password = request.options['password']['new_password'] CORE.info('Changing password of user %r' % (username,)) pam = PamAuth(str(self.i18n.locale)) change_password = notifier.Callback(pam.change_password, username, password, new_password) password_changed = notifier.Callback(self._password_changed, request, new_password) thread = threads.Simple('change_password', change_password, password_changed) thread.run()
def stop(self, request): if self.permitted('services/stop', request.options): message = {} message['success'] = _('Successfully stopped') message['failed'] = _('Stopping the following services failed:') cb = notifier.Callback(self._service_changed, request, message) func = notifier.Callback(self._run_it, request.options, 'stop') thread = notifier.threads.Simple('services', func, cb) thread.run() else: message = _('You are not permitted to run this command.') request.status = MODULE_ERR self.finished(request.id, None, message)
def _send_error(): # inform client res = Response(msg) res.status = SERVER_ERR_MODULE_FAILED # error connecting to module process res.message = status_description(res.status) self.result(res) # cleanup module mod.signal_disconnect('closed', notifier.Callback(self._socket_died)) mod.signal_disconnect('result', notifier.Callback(self.result)) mod.signal_disconnect('finished', notifier.Callback(self._mod_died)) proc = self.__processes.pop(mod.name, None) if proc: proc.__del__()
def restart(self, request): MODULE.error(str(request.arguments)) if self.permitted('services/restart', request.options): message = {} message['success'] = _('Successfully restarted') message['failed'] = _('Restarting the following services failed:') cb = notifier.Callback(self._service_changed, request, message) func = notifier.Callback(self._run_it, request.options, 'restart') thread = notifier.threads.Simple('services', func, cb) thread.run() else: message = _('You are not permitted to run this command.') request.status = MODULE_ERR self.finished(request.id, None, message)
def validate(self, request): """Validates the correctness of values for properties of the given object type. Therefor the syntax definition of the properties is used. requests.options = {} 'objectType' -- The UDM module name. If not available the flavor is used return: [ { 'property' : <name>, 'valid' : (True|False), 'details' : <message> }, ... ] """ def _thread(request): module = self._get_module_by_request(request) result = [] for property_name, value in request.options.get('properties').items(): # ignore special properties named like $.*$, e.g. $options$ if property_name.startswith('$') and property_name.endswith('$'): continue property_obj = module.get_property(property_name) if property_obj is None: raise UMC_OptionMissing(_('Property %s not found') % property_name) # check each element if 'value' is a list if isinstance(value, (tuple, list)) and property_obj.multivalue: subResults = [] subDetails = [] for ival in value: try: property_obj.syntax.parse(ival) subResults.append(True) subDetails.append('') except (udm_errors.valueInvalidSyntax, udm_errors.valueError, TypeError) as e: subResults.append(False) subDetails.append(str(e)) result.append({'property': property_name, 'valid': subResults, 'details': subDetails}) # otherwise we have a single value else: try: property_obj.syntax.parse(value) result.append({'property': property_name, 'valid': True}) except (udm_errors.valueInvalidSyntax, udm_errors.valueError) as e: result.append({'property': property_name, 'valid': False, 'details': str(e)}) return result thread = notifier.threads.Simple('Validate', notifier.Callback(_thread, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def packages_invoke(self, request): """ executes an installer action """ packages = request.options.get('packages') function = request.options.get('function') try: if self._working(): # make it multi-tab safe (same session many buttons to be clicked) raise LockError() with self.package_manager.locked(reset_status=True): not_found = [pkg_name for pkg_name in packages if self.package_manager.get_package(pkg_name) is None] self.finished(request.id, {'not_found': not_found}) if not not_found: def _thread(package_manager, function, packages): with package_manager.locked(set_finished=True): with package_manager.no_umc_restart(exclude_apache=True): if function == 'install': package_manager.install(*packages) else: package_manager.uninstall(*packages) def _finished(thread, result): if isinstance(result, BaseException): MODULE.warn('Exception during %s %s: %r' % (function, packages, str(result))) thread = notifier.threads.Simple('invoke', notifier.Callback(_thread, self.package_manager, function, packages), _finished) thread.run() else: self.package_manager.set_finished() # nothing to do, ready to take new commands except LockError: # make it thread safe: another process started a package manager # this module instance already has a running package manager raise umcm.UMC_Error(_('Another package operation is in progress'))
def authenticate(self, msg): # PAM MUST be initialized outside of a thread. Otherwise it segfaults e.g. with pam_saml.so. # See http://pam-python.sourceforge.net/doc/html/#bugs args = msg.body.copy() locale = args.pop('locale', None) args.pop('pam', None) args.setdefault('new_password', None) args.setdefault('username', '') args.setdefault('password', '') pam = PamAuth(locale) thread = threads.Simple( 'pam', notifier.Callback(self.__authenticate_thread, pam, **args), notifier.Callback(self.__authentication_result, pam, msg, locale)) thread.run()
def users_query(self, request): partitionDevice = request.options['partitionDevice'] self._check_error(request, partitionDevice) callback = notifier.Callback(self._users_query, request.id, partitionDevice, request) tools.repquota(request.options['partitionDevice'], callback)
def _response(self, request, *args, **kwargs): # other arguments than request wont be propagated # needed for @LDAP_Connection # fake a multi_request request.options = [request.options] if with_progress: progress_obj = self.new_progress() request.options[0][with_progress] = progress_obj def _thread(self, progress_obj, _multi_response, request): try: result = _multi_response(self, request) except Exception: progress_obj.exception(sys.exc_info()) else: progress_obj.finish_with_result(result[0]) thread = Thread(target=_thread, args=[self, progress_obj, _multi_response, request]) thread.start() self.finished(request.id, progress_obj.initialised()) else: result = _multi_response(self, request) if not isinstance(result[0], types.FunctionType): self.finished(request.id, result[0]) else: # return value is a function which is meant to be executed as thread # TODO: replace notfier by threading thread = notifier.threads.Simple('simple_response', notifier.Callback(result[0], self, request), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def handle_request_exit(self, msg): """Handles an EXIT request. If the request does not have an argument that contains a valid name of a running UMC module instance the request is returned as a bad request. If the request is valid it is passed on to the module process. Additionally a timer of 3000 milliseconds is started. After that amount of time the module process MUST have been exited itself. If not the UMC server will kill the module process. :param Request msg: UMCP request """ if len(msg.arguments) < 1: return self.handle_request_unknown(msg) module_name = msg.arguments[0] if module_name: if module_name in self.__processes: self.__processes[module_name].request(msg) CORE.info('Ask module %s to shutdown gracefully' % module_name) # added timer to kill away module after 3000ms cb = notifier.Callback(self._purge_child, module_name) self.__killtimer[module_name] = notifier.timer_add(3000, cb) else: CORE.info('Got EXIT request for a non-existing module %s' % module_name)
def _load_module(self): MODULE.process('Loading python module.') modname = self.__module from ..error import UMC_Error try: try: file_ = 'univention.management.console.modules.%s' % (modname,) self.__module = __import__(file_, [], [], modname) MODULE.process('Imported python module.') self.__handler = self.__module.Instance() MODULE.process('Module instance created.') except Exception as exc: error = _('Failed to load module %(module)s: %(error)s\n%(traceback)s') % {'module': modname, 'error': exc, 'traceback': traceback.format_exc()} MODULE.error(error) if isinstance(exc, ImportError) and str(exc).startswith('No module named %s' % (modname,)): error = '\n'.join(( _('The requested module %r does not exist.') % (modname,), _('The module may have been removed recently.'), _('Please relogin to the Univention Management Console to see if the error persists.'), _('Further information can be found in the logfile %s.') % ('/var/log/univention/management-console-module-%s.log' % (modname,),), )) raise UMC_Error(error, status=MODULE_ERR_INIT_FAILED) except UMC_Error: try: exc_info = sys.exc_info() self.__init_etype, self.__init_exc, self.__init_etraceback = exc_info # FIXME: do not keep a reference to traceback finally: exc_info = None else: self.__handler.signal_connect('success', notifier.Callback(self._reply, True))
def wait4state(computer, signal, value): def _sig_handler(new_value, expected_value): print 'GOT SIGNAL', signal, new_value sys.exit(0) return False computer.signal_connect(signal, notifier.Callback(_sig_handler, value))
def send(self, request): def _send_thread(sender, recipient, subject, message): MODULE.info('sending mail: thread running') msg = u'From: ' + sender + u'\r\n' msg += u'To: ' + recipient + u'\r\n' msg += u'Subject: %s\r\n' % subject msg += u'\r\n' msg += message + u'\r\n' msg += u'\r\n' msg = msg.encode('latin1') server = smtplib.SMTP('localhost') server.set_debuglevel(0) server.sendmail(sender, recipient, msg) server.quit() def _send_return(thread, result, request): import traceback if not isinstance(result, BaseException): MODULE.info('sending mail: completed successfully') self.finished(request.id, True) else: msg = '%s\n%s: %s\n' % ( ''.join(traceback.format_tb(thread.exc_info[2])), thread.exc_info[0].__name__, str(thread.exc_info[1])) MODULE.process('sending mail:An internal error occurred: %s' % msg) self.finished(request.id, False, msg, False) keys = ['sender', 'recipient', 'subject', 'message'] self.required_options(request, *keys) for key in keys: if request.options[key]: MODULE.info('send ' + key + '=' + request.options[key].replace('%', '_')) func = notifier.Callback(_send_thread, request.options['sender'], request.options['recipient'], request.options['subject'], request.options['message']) MODULE.info('sending mail: starting thread') cb = notifier.Callback(_send_return, request) thread = notifier.threads.Simple('mailing', func, cb) thread.run()
def move_container_query(self, request): scope = 'one' modules = self.modules_with_childs container = request.options.get('container') if not container: scope = 'base' thread = notifier.threads.Simple('MoveContainerQuery', notifier.Callback(self._container_query, request, container, modules, scope), notifier.Callback(self.thread_finished_callback, request)) thread.run()
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 check_finished(self, request): '''Check whether the join/setup scripts are finished. This method implements a long polling request, i.e., the request is only finished at the moment when all scripts have been executed or due to a timeout. If it returns because of the timeout, a new try can be started.''' def _thread(request, obj): def progress_info(state, **kwargs): info = { 'component': state.fractionName, 'info': state.message, 'errors': state.errors, 'critical': state.critical, 'steps': state.percentage } info.update(kwargs) MODULE.info( 'Progress state: %(steps).1f%% - %(component)s - %(info)s' % info) return info # acquire the lock in order to wait for the join/setup scripts to finish # do this for 30 sec and then return anyway SLEEP_TIME = 0.200 WAIT_TIME = 30 ntries = WAIT_TIME / SLEEP_TIME while not obj._finishedLock.acquire(False): if ntries <= 0 or self._progressParser.changed and self._progressParser.current: state = self._progressParser.current return progress_info(state, finished=False) time.sleep(SLEEP_TIME) ntries -= 1 obj._finishedLock.release() # scripts are done, return final result # return all errors that we gathered throughout the setup state = self._progressParser.current return progress_info(state, finished=obj._finishedResult) thread = notifier.threads.Simple( 'check_finished', notifier.Callback(_thread, request, self), notifier.Callback(self.thread_finished_callback, request)) thread.run()
def __init__(self, command, stdout=True, stderr=False, shell=False): Process.__init__(self, command, stdout=stdout, stderr=stderr, shell=shell) if stdout: self.__stdout = [] cb = notifier.Callback(self._output, self.__stdout) self.signal_connect('stdout', cb) else: self.__stdout = None if stderr: self.__stderr = [] cb = notifier.Callback(self._output, self.__stderr) self.signal_connect('stderr', cb) else: self.__stderr = None self.signal_connect('killed', self._finished) self.signal_new('finished')