def reconfigureEventGenerators(): eventConfigs = getEventConfigs() for eventGenerator in _EVENT_GENERATORS.values(): eventGenerator.setEventConfigs([]) for (eventConfigId, eventConfig) in eventConfigs.items(): mainEventConfigId = eventConfigId.split('{')[0] try: eventGenerator = _EVENT_GENERATORS[mainEventConfigId] except KeyError: logger.info( "Cannot reconfigure event generator for event '%s': not found", eventConfigId) continue try: eventType = eventConfig['type'] del eventConfig['type'] ec = EventConfigFactory(eventType, eventConfigId, **eventConfig) eventGenerator.addEventConfig(ec) logger.notice("Event config '%s' added to event generator '%s'", eventConfigId, mainEventConfigId) except Exception as err: # pylint: disable=broad-except logger.error("Failed to reconfigure event generator '%s': %s", mainEventConfigId, err)
def getNextEvent(self): if self._opsiclientd.is_stopping(): return None if not self._watcher: logger.info("Nothing to watch for") self._event = threading.Event() self._event.wait() return None wqlResult = None from opsiclientd.windows import importWmiAndPythoncom # pylint: disable=import-outside-toplevel (wmi, _pythoncom) = importWmiAndPythoncom() while not self._stopped: try: wqlResult = self._watcher(timeout_ms=500) break except wmi.x_wmi_timed_out: continue if wqlResult: eventInfo = {} for prop in wqlResult.properties: value = getattr(wqlResult, prop) if isinstance(value, tuple): eventInfo[prop] = [] for val in value: eventInfo[prop].append(val) else: eventInfo[prop] = value return self.createEvent(eventInfo)
def mergeObjectsFunction(snapshotObj, updateObj, masterObj, snapshotBackend, workBackend, masterBackend): # pylint: disable=unused-argument,too-many-arguments masterVersions = sorted([ f"{p.productVersion}-{p.packageVersion}" for p in masterBackend.productOnDepot_getObjects( ["productVersion", "packageVersion"], productId=snapshotObj.productId, depotId=self._depotId) ]) snapshotVersions = sorted([ f"{p.productVersion}-{p.packageVersion}" for p in snapshotBackend.productOnDepot_getObjects( ["productVersion", "packageVersion"], productId=snapshotObj.productId, depotId=self._depotId) ]) logger.info( "Syncing ProductOnClient %s (product versions local=%s, server=%s)", updateObj, snapshotVersions, masterVersions) if snapshotVersions != masterVersions: logger.notice( "Product %s changed on server since last sync, not updating actionRequest (local=%s, server=%s)", snapshotObj.productId, snapshotVersions, masterVersions) updateObj.actionRequest = None updateObj.targetConfiguration = None return updateObj
def check_restart_marker(self): logger.info("Checking if restart marker '%s' exists", self.restart_marker) if os.path.exists(self.restart_marker): if os.path.getsize(self.restart_marker) == 0: logger.notice( "Old restart marker found, gui startup and daemon startup events disabled" ) self.disabledEventTypes = ["gui startup", "daemon startup"] else: logger.notice("Reading restart marker") with open(self.restart_marker, "r", encoding="utf-8") as file: for line in file.readlines(): line = line.strip() if line.startswith("#") or not "=" in line: continue option, value = line.split("=", 1) option = option.strip().lower() if option == "disabled_event_types": self.disabledEventTypes = [ v.strip().lower() for v in value.split(",") if v.strip().lower() ] logger.notice( "Event types %s disabled by restart marker", self.disabledEventTypes) try: os.remove(self.restart_marker) except Exception as err: # pylint: disable=broad-except logger.error(err)
def initialize(self): if self._opsiclientd.is_stopping(): return if not self._wql: return from opsiclientd.windows import importWmiAndPythoncom # pylint: disable=import-outside-toplevel (wmi, pythoncom) = importWmiAndPythoncom() pythoncom.CoInitialize() max_attempts = 10 for attempt in range(1, 100): try: logger.debug("Creating wmi object") con = wmi.WMI(privileges=["Security"]) logger.info("Watching for wql: %s", self._wql) self._watcher = con.watch_for(raw_wql=self._wql, wmi_class='') break except Exception as err: # pylint: disable=broad-except if self._stopped: return logger.warning("Failed to create wmi watcher (wql=%s): %s", self._wql, err, exc_info=True) if attempt >= max_attempts: raise for i in range(3): # pylint: disable=unused-variable if self._stopped: return time.sleep(1) logger.debug("Initialized")
def setup_firewall_linux(): logger.notice("Configure iptables") port = config.get('control_server', 'port') cmds = [] if os.path.exists("/usr/bin/firewall-cmd"): # openSUSE Leap cmds.append([ "/usr/bin/firewall-cmd", f"--add-port={port}/tcp", "--zone", "public" ]) elif os.path.exists("/sbin/SuSEfirewall2"): # other SUSE cmds.append(["/sbin/SuSEfirewall2", "open", "EXT", "TCP" f"{port}"]) elif os.path.exists("/usr/sbin/ucr"): # UCS cmds.append([ "/usr/sbin/ucr", "set", f"security/packetfilter/package/opsiclientd/tcp/{port}/all=ACCEPT" ]) cmds.append(["/usr/sbin/service", "univention-firewall", "restart"]) elif os.path.exists("/sbin/iptables"): for iptables in ("iptables", "ip6tables"): cmds.append([ iptables, "-A", "INPUT", "-p", "tcp", "--dport", str(port), "-j", "ACCEPT" ]) else: logger.warning( "Could not configure firewall - no suitable executable found.") for cmd in cmds: logger.info("Running command: %s", str(cmd)) subprocess.call(cmd)
def run(self): with log_context({'instance': 'control pipe'}): try: while not self._stopEvent.is_set(): if self.clientInfo: self.checkConnection() else: # Old protocol with self.comLock: request = self.read() if request: logger.info("Received request '%s' from %s", request, self) response = self.processIncomingRpc(request) logger.info("Sending response '%s' to %s", response, self) self.write(response) if self.clientInfo: # Switch to new protocol self.executeRpc('blockLogin', [ self._controller._opsiclientd. _blockLogin ], with_lock=False) # pylint: disable=protected-access time.sleep(0.5) except Exception as err: # pylint: disable=broad-except logger.error(err, exc_info=True) finally: self.clientDisconnected()
def importWmiAndPythoncom(importWmi=True, importPythoncom=True): global wmi # pylint: disable=global-statement,invalid-name global pythoncom # pylint: disable=global-statement,invalid-name if importWmi and not pythoncom: importPythoncom = True if not ((wmi or not importWmi) and (pythoncom or not importPythoncom)): logger.info("Importing wmi / pythoncom") with importWmiAndPythoncomLock: while not ((wmi or not importWmi) and (pythoncom or not importPythoncom)): try: if not pythoncom and importPythoncom: logger.debug("Importing pythoncom") import pythoncom # pylint: disable=import-error,import-outside-toplevel,redefined-outer-name if not wmi and importWmi: logger.debug("Importing wmi") pythoncom.CoInitialize() try: import wmi # pylint: disable=import-error,import-outside-toplevel,redefined-outer-name finally: pythoncom.CoUninitialize() except Exception as import_error: # pylint: disable=broad-except logger.warning( "Failed to import: %s, retrying in 2 seconds", import_error) time.sleep(2) return (wmi, pythoncom)
def getFromService(self, configService): ''' Get settings from service ''' logger.notice("Getting config from service") if not configService: raise Exception("Config service is undefined") query = { "objectId": self.get('global', 'host_id'), "configId": [ 'clientconfig.configserver.url', 'clientconfig.depot.drive', 'clientconfig.depot.id', 'clientconfig.depot.user', 'clientconfig.suspend_bitlocker_on_reboot', 'opsiclientd.*' # everything starting with opsiclientd. ] } configService.backend_setOptions({"addConfigStateDefaults": True}) for configState in configService.configState_getObjects(**query): logger.info("Got config state from service: %r", configState) if not configState.values: logger.debug("No values - skipping %s", configState.configId) continue if configState.configId == 'clientconfig.configserver.url': self.set('config_service', 'url', configState.values) elif configState.configId == 'clientconfig.depot.drive': self.set('depot_server', 'drive', configState.values[0]) elif configState.configId == 'clientconfig.depot.id': self.set('depot_server', 'depot_id', configState.values[0]) elif configState.configId == 'clientconfig.depot.user': self.set('depot_server', 'username', configState.values[0]) elif configState.configId == 'clientconfig.suspend_bitlocker_on_reboot': self.set('global', 'suspend_bitlocker_on_reboot', configState.values[0]) elif configState.configId.startswith('opsiclientd.'): try: parts = configState.configId.lower().split('.') if len(parts) < 3: logger.debug( "Expected at least 3 parts in %s - skipping.", configState.configId) continue value = configState.values if len(value) == 1: value = value[0] self.set(section=parts[1], option=parts[2], value=value) except Exception as err: # pylint: disable=broad-except logger.error("Failed to process configState '%s': %s", configState.configId, err) logger.notice("Got config from service") logger.debug("Config is now:\n %s", objectToBeautifiedText(self.getDict()))
def hidePopup(self): if self._popupNotificationServer: try: logger.info("Stopping popup message notification server") self._popupNotificationServer.stop(stopReactor=False) except Exception as err: # pylint: disable=broad-except logger.error("Failed to stop popup notification server: %s", err)
def getNextEvent(self): from opsiclientd.windows import importWmiAndPythoncom # pylint: disable=import-outside-toplevel (_wmi, pythoncom) = importWmiAndPythoncom(importWmi=False, importPythoncom=True) pythoncom.PumpMessages() logger.info( "Event generator '%s' now deactivated after %d event occurrences", self, self._eventsOccured) self.cleanup()
def setBlockLogin(self, blockLogin, handleNotifier=True): # pylint: disable=too-many-branches blockLogin = forceBool(blockLogin) changed = self._blockLogin != blockLogin self._blockLogin = blockLogin logger.notice("Block login now set to '%s'", self._blockLogin) if self._blockLogin: if not self._blockLoginEventId: self._blockLoginEventId = timeline.addEvent( title="Blocking login", description="User login blocked", category="block_login", durationEvent=True) if not self._blockLoginNotifierPid and config.get( 'global', 'block_login_notifier'): if handleNotifier and RUNNING_ON_WINDOWS: logger.info("Starting block login notifier app") # Start block login notifier on physical console sessionId = System.getActiveConsoleSessionId() while True: try: self._blockLoginNotifierPid = System.runCommandInSession( command=config.get('global', 'block_login_notifier'), sessionId=sessionId, desktop='winlogon', waitForProcessEnding=False)[2] break except Exception as err: # pylint: disable=broad-except logger.error( "Failed to start block login notifier app: %s", err) break else: if self._blockLoginEventId: timeline.setEventEnd(eventId=self._blockLoginEventId) self._blockLoginEventId = None if handleNotifier and self._blockLoginNotifierPid: try: logger.info( "Terminating block login notifier app (pid %s)", self._blockLoginNotifierPid) System.terminateProcess( processId=self._blockLoginNotifierPid) except Exception as err: # pylint: disable=broad-except logger.warning( "Failed to terminate block login notifier app: %s", err) self._blockLoginNotifierPid = None if changed and self._controlPipe: try: self._controlPipe.executeRpc("blockLogin", self._blockLogin) except Exception as rpc_error: # pylint: disable=broad-except logger.debug(rpc_error)
def licenseOnClient_getObjects(self, attributes=[], **filter): # pylint: disable=dangerous-default-value,redefined-builtin licenseOnClients = self._workBackend.licenseOnClient_getObjects( attributes, **filter) logger.info( "licenseOnClient_getObjects called with filter %s, %s LicenseOnClients found", filter, len(licenseOnClients)) for licenseOnClient in licenseOnClients: # Recreate for later sync to server self.licenseOnClient_insertObject(licenseOnClient) return licenseOnClients
def run(self): while True: try: System.reboot(0) logger.notice("Reboot initiated") break except Exception as err: # pylint: disable=broad-except # Device not ready? logger.info("Failed to initiate reboot: %s", err) time.sleep(1)
def isShutdownRequested(self): try: shutdownRequested = System.getRegistryValue( System.HKEY_LOCAL_MACHINE, "SOFTWARE\\opsi.org\\winst", "ShutdownRequested") except Exception as err: # pylint: disable=broad-except logger.info("Failed to get shutdownRequested from registry: %s", err) shutdownRequested = 0 logger.notice("Shutdown request in Registry: %s", shutdownRequested) return forceBool(shutdownRequested)
def processEvent(self, event): logger.trace("check lock (ocd), currently %s -> locking if not True", self._opsiclientd.eventLock.locked()) # if triggered by Basic.py fire_event, lock is already acquired if not self._opsiclientd.eventLock.locked(): self._opsiclientd.eventLock.acquire() try: logger.info("GUI started") self._guiStarted.set() finally: logger.trace("release lock (WaitForGUI)") self._opsiclientd.eventLock.release()
def cleanup(self): if self._lastEventOccurence and (time.time() - self._lastEventOccurence < 10): # Waiting some seconds before exit to avoid Win32 releasing # exceptions waitTime = int(10 - (time.time() - self._lastEventOccurence)) logger.info("Event generator '%s' cleaning up in %d seconds", self, waitTime) time.sleep(waitTime) from opsiclientd.windows import importWmiAndPythoncom # pylint: disable=import-outside-toplevel (_wmi, pythoncom) = importWmiAndPythoncom(importWmi=False, importPythoncom=True) pythoncom.CoUninitialize()
def setup_firewall_windows(): logger.notice("Configure Windows firewall") port = config.get('control_server', 'port') cmds = [[ "netsh", "advfirewall", "firewall", "delete", "rule", 'name="opsiclientd-control-port"' ], [ "netsh", "advfirewall", "firewall", "add", "rule", 'name="opsiclientd-control-port"', "dir=in", "action=allow", "protocol=TCP", f"localport={port}" ]] for cmd in cmds: logger.info("Running command: %s", str(cmd)) subprocess.call(cmd)
def setup_firewall_macos(): logger.notice("Configure MacOS firewall") cmds = [] for path in ("/usr/local/bin/opsiclientd", "/usr/local/lib/opsiclientd/opsiclientd"): cmds.append( ["/usr/libexec/ApplicationFirewall/socketfilterfw", "--add", path]) cmds.append([ "/usr/libexec/ApplicationFirewall/socketfilterfw", "--unblockapp", path ]) for cmd in cmds: logger.info("Running command: %s", str(cmd)) subprocess.call(cmd)
def run(self): with opsicommon.logging.log_context( {'instance': f'event generator {self._generatorConfig.getId()}'}): try: logger.info("Initializing event generator '%s'", self) self.initialize() if self._generatorConfig.activationDelay > 0: logger.debug( "Waiting %d seconds before activation of event generator '%s'", self._generatorConfig.activationDelay, self) time.sleep(self._generatorConfig.activationDelay) logger.info("Activating event generator '%s'", self) while not self._stopped and ( (self._generatorConfig.maxRepetitions < 0) or (self._eventsOccured <= self._generatorConfig.maxRepetitions)): logger.info("Getting next event...") event = self.getNextEvent() # pylint: disable=assignment-from-none,assignment-from-no-return self._eventsOccured += 1 # Count as occured, even if event is None! if event: logger.info("Got new event: %s (%d/%d)", event, self._eventsOccured, self._generatorConfig.maxRepetitions + 1) self.fireEvent(event) for _unused in range(10): if self._stopped: break time.sleep(1) if not self._stopped: logger.notice( "Event generator '%s' now deactivated after %d event occurrences", self, self._eventsOccured) except Exception as err: # pylint: disable=broad-except if not self._stopped: logger.error("Failure in event generator '%s': %s", self, err, exc_info=True) try: self.cleanup() except Exception as err: # pylint: disable=broad-except if not self._stopped: logger.error("Failed to clean up: %s", err) logger.info("Event generator '%s' exiting ", self)
def self_update_from_file(self, filename): logger.notice("Self-update from file %s", filename) test_file = "base_library.zip" inst_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) if not os.path.exists(os.path.join(inst_dir, test_file)): raise RuntimeError( f"File not found: {os.path.join(inst_dir, test_file)}") if self._selfUpdating: raise RuntimeError("Self-update already running") self._selfUpdating = True try: with tempfile.TemporaryDirectory() as tmpdir: destination = os.path.join(tmpdir, "content") shutil.unpack_archive(filename=filename, extract_dir=destination) bin_dir = destination if not os.path.exists(os.path.join(bin_dir, test_file)): bin_dir = None for fn in os.listdir(destination): if os.path.exists( os.path.join(destination, fn, test_file)): bin_dir = os.path.join(destination, fn) break if not bin_dir: raise RuntimeError("Invalid archive") try: check_signature(bin_dir) except Exception as err: # pylint: disable=broad-except logger.error("Could not verify signature!\n%s", err, exc_info=True) logger.error("Not performing self_update.") raise RuntimeError("Invalid signature") from err binary = os.path.join(bin_dir, os.path.basename(self._argv[0])) logger.info("Testing new binary: %s", binary) out = subprocess.check_output([binary, "--version"]) logger.info(out) move_dir = inst_dir + "_old" logger.info("Moving current installation dir '%s' to '%s'", inst_dir, move_dir) if os.path.exists(move_dir): shutil.rmtree(move_dir) os.rename(inst_dir, move_dir) logger.info("Installing '%s' into '%s'", bin_dir, inst_dir) shutil.copytree(bin_dir, inst_dir) self.restart(3) finally: self._selfUpdating = False
def run(self): with opsicommon.logging.log_context({ 'instance': 'event generator ' + self._event.eventConfig.getId() }): if self._event.eventConfig.notificationDelay > 0: logger.debug( "Waiting %d seconds before notifying listener '%s' of event '%s'", self._event.eventConfig.notificationDelay, self._eventListener, self._event) time.sleep(self._event.eventConfig.notificationDelay) try: logger.info("Calling processEvent on listener %s", self._eventListener) self._eventListener.processEvent(self._event) except Exception as err: # pylint: disable=broad-except logger.error(err, exc_info=True)
def opsi_service_setup(options=None): try: config.readConfigFile() except Exception as err: # pylint: disable=broad-except logger.info(err) if os.path.exists(config.ca_cert_file): # Delete ca cert which could be invalid or expired os.remove(config.ca_cert_file) service_address = getattr(options, "service_address", None) or config.get( 'config_service', 'url')[0] service_username = getattr(options, "service_username", None) or config.get('global', 'host_id') service_password = getattr(options, "service_password", None) or config.get('global', 'opsi_host_key') if getattr(options, "client_id", None): config.set('global', 'host_id', options.client_id) if not config.get('global', 'host_id'): fqdn = get_fqdn() fqdn = config.set('global', 'host_id', fqdn) secret_filter.add_secrets(service_password) logger.notice("Connecting to '%s' as '%s'", service_address, service_username) jsonrpc_client = JSONRPCClient(address=service_address, username=service_username, password=service_password, verify_server_cert=False) try: update_ca_cert(jsonrpc_client, allow_remove=False) except Exception as err: # pylint: disable=broad-except logger.error(err, exc_info=True) try: client = jsonrpc_client.host_getObjects(id=config.get( 'global', 'host_id')) # pylint: disable=no-member if client and client[0] and client[0].opsiHostKey: config.set('global', 'opsi_host_key', client[0].opsiHostKey) config.getFromService(jsonrpc_client) config.updateConfigFile(force=True) finally: jsonrpc_client.disconnect()
def isRebootRequested(self): try: rebootRequested = System.getRegistryValue( System.HKEY_LOCAL_MACHINE, "SOFTWARE\\opsi.org\\winst", "RebootRequested") except Exception as error: # pylint: disable=broad-except logger.warning("Failed to get RebootRequested from registry: %s", error) rebootRequested = 0 logger.notice("Reboot request in Registry: %s", rebootRequested) if rebootRequested == 2: # Logout logger.info("Logout requested") self.clearRebootRequest() return False return forceBool(rebootRequested)
def cleanup(self): if self._opsiclientd.is_stopping(): return if self._lastEventOccurence and (time.time() - self._lastEventOccurence < 10): # Waiting some seconds before exit to avoid Win32 releasing exceptions waitTime = int(10 - (time.time() - self._lastEventOccurence)) logger.info("Event generator '%s' cleaning up in %d seconds", self, waitTime) time.sleep(waitTime) try: from opsiclientd.windows import importWmiAndPythoncom # pylint: disable=import-outside-toplevel (_wmi, pythoncom) = importWmiAndPythoncom() pythoncom.CoUninitialize() except ImportError: # Probably not running on Windows. pass
def executeRpc(self, method, params=None, with_lock=True): params = params or [] with log_context({'instance': 'control pipe'}): rpc_id = 1 if not self.clientInfo: return { "id": rpc_id, "error": f"Cannot execute rpc, not supported by client {self}", "result": None } request = {"id": rpc_id, "method": method, "params": params} try: if with_lock: self.comLock.acquire() # pylint: disable=consider-using-with try: request_json = toJson(request) logger.info("Sending request '%s' to client %s", request_json, self) self.write(request_json) response_json = self.read() if not response_json: logger.warning( "No response for method '%s' received from client %s", request["method"], self) return {"id": rpc_id, "error": None, "result": None} logger.info("Received response '%s' from client %s", response_json, self) response = fromJson(response_json) if method == "loginUser" and response.get("result"): # Credential provider can only handle one successful login. # Ensure, that the credential provider is not used for a # second login if it keeps the pipe connection open. self.login_capable = False return response finally: if with_lock: self.comLock.release() except Exception as client_err: # pylint: disable=broad-except logger.error(client_err, exc_info=True) return {"id": rpc_id, "error": str(client_err), "result": None}
def SvcRun(self): # pylint: disable=invalid-name """ Gets called from windows to start service """ try: logger.notice("Handling start request") startTime = time.time() self.ReportServiceStatus(win32service.SERVICE_RUNNING) logger.debug("Took %0.2f seconds to report service running status", (time.time() - startTime)) # Write to event log servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED, (self._svc_name_, '')) from .opsiclientd import opsiclientd_factory # pylint: disable=import-outside-toplevel self.opsiclientd = opsiclientd_factory() self.opsiclientd.start() # Wait for stop event win32event.WaitForSingleObject(self._stopEvent, win32event.INFINITE) # Shutdown opsiclientd self.opsiclientd.stop() self.opsiclientd.join(15) logger.notice("opsiclientd stopped") try: self.ReportServiceStatus(win32service.SERVICE_STOPPED) servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STOPPED, (self._svc_name_, '')) except Exception as err: # pylint: disable=broad-except # Errors can occur if windows is shutting down logger.info(err, exc_info=True) for thread in threading.enumerate(): logger.notice("Running thread after stop: %s", thread) except Exception as err: # pylint: disable=broad-except logger.critical("opsiclientd crash %s", err, exc_info=True)
def getDaemonLoopingContext(): with getEventGeneratorContext(): for event_generator in getEventGenerators( generatorClass=DaemonStartupEventGenerator): try: event_generator.createAndFireEvent() except ValueError as err: logger.error( "Unable to fire DaemonStartupEvent from %s: %s", event_generator, err, exc_info=True) if getEventGenerators(generatorClass=GUIStartupEventGenerator): # Wait until gui starts up logger.notice( "Waiting for gui startup (timeout: %d seconds)", config.get('global', 'wait_for_gui_timeout')) self.waitForGUI( timeout=config.get('global', 'wait_for_gui_timeout')) if not self.is_stopping(): logger.notice("Done waiting for GUI") # Wait some more seconds for events to fire time.sleep(5) try: yield finally: for event_generator in getEventGenerators( generatorClass=DaemonShutdownEventGenerator): logger.info( "Create and fire shutdown event generator %s", event_generator) try: event_generator.createAndFireEvent() except ValueError as err: logger.error( "Unable to fire DaemonStartupEvent from %s: %s", event_generator, err, exc_info=True)
def getControlPipe(): logger.notice("Starting control pipe") try: self._controlPipe = ControlPipeFactory(self) self._controlPipe.daemon = True self._controlPipe.start() logger.notice("Control pipe started") yield except Exception as err: # pylint: disable=broad-except logger.error("Failed to start control pipe: %s", err, exc_info=True) raise finally: logger.info("Stopping control pipe") try: self._controlPipe.stop() self._controlPipe.join(2) logger.info("Control pipe stopped") except (NameError, RuntimeError) as stopError: logger.debug("Stopping controlPipe failed: %s", stopError)
def callback(self, eventType, *args): logger.debug( "UserLoginEventGenerator event callback: eventType '%s', args: %s", eventType, args) if self._opsiclientd.is_stopping(): return if args[0].split("\\")[-1] == OPSI_SETUP_USER_NAME: logger.info( "Login of user %s detected, no UserLoginAction will be fired.", args[0]) return if eventType == 'Logon': logger.notice("User login detected: %s", args[0]) self._eventsOccured += 1 self.fireEvent(self.createEvent(eventInfo={'User': args[0]})) if (self._generatorConfig.maxRepetitions > 0) and (self._eventsOccured > self._generatorConfig.maxRepetitions): self.stop()